diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a69002e..5238deb 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -12,7 +12,8 @@ i915-y := i915_drv.o \
           i915_suspend.o \
 	  i915_sysfs.o \
 	  intel_pm.o \
-	  intel_runtime_pm.o
+	  intel_runtime_pm.o \
+	  intel_csr.o
 
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 68e0c85..4d92429 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -783,6 +783,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 	spin_lock_init(&dev_priv->mmio_flip_lock);
 	mutex_init(&dev_priv->dpio_lock);
 	mutex_init(&dev_priv->modeset_restore_lock);
+	mutex_init(&dev_priv->csr_lock);
 
 	intel_pm_setup(dev);
 
@@ -828,10 +829,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
 	intel_uncore_init(dev);
 
-	ret = i915_gem_gtt_init(dev);
+	/* Load CSR Firmware for SKL */
+	ret = intel_csr_ucode_init(dev);
 	if (ret)
 		goto out_regs;
 
+	ret = i915_gem_gtt_init(dev);
+	if (ret)
+		goto out_freecsr;
+
 	/* WARNING: Apparently we must kick fbdev drivers before vgacon,
 	 * otherwise the vga fbdev driver falls over. */
 	ret = i915_kick_out_firmware_fb(dev_priv);
@@ -1000,6 +1006,8 @@ out_mtrrfree:
 	io_mapping_free(dev_priv->gtt.mappable);
 out_gtt:
 	i915_global_gtt_cleanup(dev);
+out_freecsr:
+	intel_csr_ucode_fini(dev);
 out_regs:
 	intel_uncore_fini(dev);
 	pci_iounmap(dev->pdev, dev_priv->regs);
@@ -1077,6 +1085,8 @@ int i915_driver_unload(struct drm_device *dev)
 	mutex_unlock(&dev->struct_mutex);
 	i915_gem_cleanup_stolen(dev);
 
+	intel_csr_ucode_fini(dev);
+
 	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 82f8be4..489caa6 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -543,6 +543,26 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
 	cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work);
 }
 
+void i915_firmware_load_error_print(const char *fw_path, int err)
+{
+	DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err);
+
+	/*
+	 * If the reason is not known assume -ENOENT since that's the most
+	 * usual failure mode.
+	 */
+	if (!err)
+		err = -ENOENT;
+
+	if (!(IS_BUILTIN(CONFIG_DRM_I915) && err == -ENOENT))
+		return;
+
+	DRM_ERROR(
+	  "The driver is built-in, so to load the firmware you need to\n"
+	  "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n"
+	  "in your initrd/initramfs image.\n");
+}
+
 static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
 {
 	struct drm_device *dev = dev_priv->dev;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 4ef320c..dd572a0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -666,6 +666,12 @@ struct intel_uncore {
 #define for_each_fw_domain(domain__, dev_priv__, i__) \
 	for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
 
+struct intel_csr {
+	int csr_size;
+	u8 *csr_buf;
+	const char *fw_path;
+};
+
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
 	func(is_mobile) sep \
 	func(is_i85x) sep \
@@ -1560,6 +1566,123 @@ struct i915_virtual_gpu {
 	bool active;
 };
 
+struct intel_css_header {
+	/* 0x09 for DMC */
+	uint32_t module_type;
+
+	/* Includes the DMC specific header in dwords */
+	uint32_t header_len;
+
+	/* always value would be 0x10000 */
+	uint32_t header_ver;
+
+	/* Not used */
+	uint32_t module_id;
+
+	/* Not used */
+	uint32_t module_vendor;
+
+	/* in YYYYMMDD format */
+	uint32_t date;
+
+	/* Size in dwords (CSS_Headerlen + PackageHeaderLen + dmc FWsLen)/4 */
+	uint32_t size;
+
+	/* Not used */
+	uint32_t key_size;
+
+	/* Not used */
+	uint32_t modulus_size;
+
+	/* Not used */
+	uint32_t exponent_size;
+
+	/* Not used */
+	uint32_t reserved1[12];
+
+	/* Major Minor */
+	uint32_t version;
+
+	/* Not used */
+	uint32_t reserved2[8];
+
+	/* Not used */
+	uint32_t kernel_header_info;
+} __packed;
+
+struct intel_fw_info {
+	uint16_t reserved1;
+
+	/* Stepping (A, B, C, ..., *). * is a wildcard */
+	char stepping;
+
+	/* Sub-stepping (0, 1, ..., *). * is a wildcard */
+	char substepping;
+
+	uint32_t offset;
+	uint32_t reserved2;
+} __packed;
+
+struct intel_package_header {
+	/* DMC container header length in dwords */
+	unsigned char header_len;
+
+	/* always value would be 0x01 */
+	unsigned char header_ver;
+
+	unsigned char reserved[10];
+
+	/* Number of valid entries in the FWInfo array below */
+	uint32_t num_entries;
+
+	struct intel_fw_info fw_info[20];
+} __packed;
+
+struct intel_dmc_header {
+	/* always value would be 0x40403E3E */
+	uint32_t signature;
+
+	/* DMC binary header length */
+	unsigned char header_len;
+
+	/* 0x01 */
+	unsigned char header_ver;
+
+	/* Reserved */
+	uint16_t dmcc_ver;
+
+	/* Major, Minor */
+	uint32_t	project;
+
+	/* Firmware program size (excluding header) in dwords */
+	uint32_t	fw_size;
+
+	/* Major Minor version */
+	uint32_t fw_version;
+
+	/* Number of valid MMIO cycles present. */
+	uint32_t mmio_count;
+
+	/* MMIO address */
+	uint32_t mmioaddr[8];
+
+	/* MMIO data */
+	uint32_t mmiodata[8];
+
+	/* FW filename  */
+	unsigned char dfile[32];
+
+	uint32_t reserved1[2];
+} __packed;
+
+struct intel_dmc_info {
+	__be32 *dmc_payload;
+	uint32_t dmc_fw_size;
+	uint32_t mmio_count;
+	uint32_t mmioaddr[8];
+	uint32_t mmiodata[8];
+};
+
 struct drm_i915_private {
 	struct drm_device *dev;
 	struct kmem_cache *slab;
@@ -1574,6 +1697,11 @@ struct drm_i915_private {
 
 	struct i915_virtual_gpu vgpu;
 
+	struct intel_csr csr;
+
+	/* Display CSR-related protection */
+	struct mutex csr_lock;
+
 	struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
 
 
@@ -1832,6 +1960,7 @@ struct drm_i915_private {
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
 	 */
+	struct intel_dmc_info dmc_info;
 };
 
 static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
@@ -2418,6 +2547,8 @@ struct drm_i915_cmd_table {
 #define HAS_RC6(dev)		(INTEL_INFO(dev)->gen >= 6)
 #define HAS_RC6p(dev)		(INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
 
+#define HAS_CSR(dev)	(IS_SKYLAKE(dev))
+
 #define INTEL_PCH_DEVICE_ID_MASK		0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE		0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE		0x1c00
@@ -2508,6 +2639,7 @@ extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
 extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
+void i915_firmware_load_error_print(const char *fw_path, int err);
 
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index b522eb6..77faa2b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -6776,6 +6776,24 @@ enum skl_disp_power_wells {
 #define GET_CFG_CR1_REG(id) (DPLL1_CFGCR1 + (id - SKL_DPLL1) * 8)
 #define GET_CFG_CR2_REG(id) (DPLL1_CFGCR2 + (id - SKL_DPLL1) * 8)
 
+/*
+* SKL CSR registers for DC5 and DC6
+*/
+#define CSR_PROGRAM_BASE		0x80000
+#define CSR_HEADER_OFFSET		128
+#define CSR_SSP_BASE_ADDR_GEN9		0x00002FC0
+#define CSR_HTP_ADDR_SKL		0x00500034
+#define CSR_SSP_BASE			0x8F074
+#define CSR_HTP_SKL			0x8F004
+#define CSR_LAST_WRITE			0x8F034
+#define CSR_LAST_WRITE_VALUE		0xc003b400
+/* MMIO address range for CSR program (0x80000 - 0x82FFF) */
+#define CSR_MAX_FW_SIZE			0x2FFF
+#define CSR_DEFAULT_FW_OFFSET		0xFFFFFFFF
+#define CSR_MMIO_START_RANGE	0x80000
+#define CSR_MMIO_END_RANGE		0x8FFFF
+#define CSR_MAX_MMIO_COUNT		8
+
 /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register,
  * since on HSW we can't write to it using I915_WRITE. */
 #define D_COMP_HSW			(MCHBAR_MIRROR_BASE_SNB + 0x5F0C)
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
new file mode 100644
index 0000000..f44f1cd
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -0,0 +1,262 @@
+/*
+ * 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 <linux/firmware.h>
+#include "i915_drv.h"
+#include "i915_reg.h"
+
+#define I915_CSR_SKL "i915/skl_dmc_ver1.bin"
+
+MODULE_FIRMWARE(I915_CSR_SKL);
+
+#define num_array_elements(a) (sizeof(a)/sizeof(a[0]))
+
+struct stepping_info {
+	char stepping;
+	char substepping;
+	uint16_t reserved;
+};
+
+struct stepping_info skl_stepping_info[] = {
+		{'A', '0', 0}, {'B', '0', 0}, {'C', '0', 0},
+		{'D', '0', 0}, {'E', '0', 0}, {'F', '0', 0},
+		{'G', '0', 0}, {'H', '0', 0}, {'I', '0', 0}
+};
+
+char intel_get_stepping(struct drm_device *dev)
+{
+	if (IS_SKYLAKE(dev) && (dev->pdev->revision <
+			num_array_elements(skl_stepping_info)))
+		return skl_stepping_info[dev->pdev->revision].stepping;
+	else
+		return -ENODATA;
+}
+
+char intel_get_substepping(struct drm_device *dev)
+{
+	if (IS_SKYLAKE(dev) && (dev->pdev->revision <
+			num_array_elements(skl_stepping_info)))
+		return skl_stepping_info[dev->pdev->revision].substepping;
+	else
+		return -ENODATA;
+}
+void intel_csr_load_program(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned char *buf = (unsigned char *)dev_priv->dmc_info.dmc_payload;
+	uint32_t i, num_bytes;
+
+	if (!IS_GEN9(dev)) {
+		DRM_ERROR("No CSR support available for this platform\n");
+		return;
+	}
+
+	mutex_lock(&dev_priv->csr_lock);
+	/* fw_size is dwords, converting it to bytes and nearest 8 multiple. */
+	num_bytes = dev_priv->dmc_info.dmc_fw_size * 4;
+	for (i = 0; i < (num_bytes & ~7); i = i + 8) {
+		uint64_t tmp = *(uint64_t *)(buf + i);
+
+		I915_WRITE64((CSR_PROGRAM_BASE + i), tmp);
+	}
+
+	/* fw_size is in dwords, for odd size need to write last 4 bytes */
+	if (num_bytes & 7) {
+		uint32_t tmp = *(uint32_t *)(buf + (num_bytes & ~7));
+
+		I915_WRITE((CSR_PROGRAM_BASE + i), tmp);
+	}
+
+	for (i = 0; i < dev_priv->dmc_info.mmio_count; i++) {
+		I915_WRITE(dev_priv->dmc_info.mmioaddr[i],
+			dev_priv->dmc_info.mmiodata[i]);
+	}
+	mutex_unlock(&dev_priv->csr_lock);
+}
+
+static void finish_csr_load(const struct firmware *fw, void *context)
+{
+	struct drm_i915_private *dev_priv = context;
+	struct drm_device *dev = dev_priv->dev;
+	struct intel_css_header *css_header;
+	struct intel_package_header *package_header;
+	struct intel_dmc_header *dmc_header;
+	struct intel_csr *csr = &dev_priv->csr;
+	char stepping = intel_get_stepping(dev);
+	char substepping = intel_get_substepping(dev);
+	uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes;
+	uint32_t i, j;
+	__be32 *dmc_payload;
+
+	if (!fw) {
+		i915_firmware_load_error_print(csr->fw_path, 0);
+		goto out;
+	}
+
+	if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
+		DRM_ERROR("Unknown stepping info, firmware loading failed\n");
+		goto out;
+	}
+
+	/* save csr f/w as it will be needed during resume */
+	csr->csr_buf = kmemdup(fw->data, fw->size, GFP_KERNEL);
+
+	csr->csr_size = fw->size;
+
+	release_firmware(fw);
+
+	/* Extract CSS Header information*/
+	css_header = (struct intel_css_header *)csr->csr_buf;
+	if (sizeof(struct intel_css_header) !=
+		(css_header->header_len * 4)) {
+		DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
+			(css_header->header_len * 4));
+		goto out;
+	}
+	readcount += sizeof(struct intel_css_header);
+
+	/* Extract Package Header information*/
+	package_header = (struct intel_package_header *)
+					&csr->csr_buf[readcount];
+	if (sizeof(struct intel_package_header) !=
+		(package_header->header_len * 4)) {
+		DRM_ERROR("Firmware has wrong package header length %u bytes\n",
+			(package_header->header_len * 4));
+		goto out;
+	}
+	readcount += sizeof(struct intel_package_header);
+
+	/* Search for dmc_offset to find firware binary. */
+	for (i = 0; i < package_header->num_entries; i++) {
+		if (package_header->fw_info[i].substepping == '*' &&
+			stepping == package_header->fw_info[i].stepping) {
+			dmc_offset = package_header->fw_info[i].offset;
+			break;
+		} else if (stepping == package_header->fw_info[i].stepping &&
+			substepping == package_header->fw_info[i].substepping) {
+			dmc_offset = package_header->fw_info[i].offset;
+			break;
+		} else if (package_header->fw_info[i].stepping == '*' &&
+			package_header->fw_info[i].substepping == '*')
+			dmc_offset = package_header->fw_info[i].offset;
+	}
+	if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
+		DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
+		goto out;
+	}
+	readcount += dmc_offset;
+
+	/* Extract dmc_header information. */
+	dmc_header = (struct intel_dmc_header *)&csr->csr_buf[readcount];
+	if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
+		DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
+				(dmc_header->header_len));
+		goto out;
+	}
+	readcount += sizeof(struct intel_dmc_header);
+
+	/* Cache the dmc header info. */
+	if (dmc_header->mmio_count > CSR_MAX_MMIO_COUNT) {
+		DRM_ERROR("Firmware has wrong mmio count %u\n",
+						dmc_header->mmio_count);
+		goto out;
+	}
+	dev_priv->dmc_info.mmio_count = dmc_header->mmio_count;
+	for (i = 0; i < dmc_header->mmio_count; i++) {
+		if (dmc_header->mmioaddr[i] >= CSR_MMIO_START_RANGE &&
+			dmc_header->mmioaddr[i] <= CSR_MMIO_END_RANGE) {
+			DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
+						dmc_header->mmioaddr[i]);
+			goto out;
+		}
+		dev_priv->dmc_info.mmioaddr[i] = dmc_header->mmioaddr[i];
+		dev_priv->dmc_info.mmiodata[i] = dmc_header->mmiodata[i];
+	}
+
+	/* fw_size is in dwords, so multiplied by 4 to convert into bytes. */
+	nbytes = dmc_header->fw_size * 4;
+	if (nbytes > CSR_MAX_FW_SIZE) {
+		DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
+		goto out;
+	}
+	dev_priv->dmc_info.dmc_payload = kmalloc(nbytes, GFP_KERNEL);
+	if (!dev_priv->dmc_info.dmc_payload) {
+		DRM_ERROR("Memory allocation failed for dmc payload\n");
+		goto out;
+	}
+
+	dmc_payload = dev_priv->dmc_info.dmc_payload;
+	for (i = 0, j = 0; i < nbytes; i = i + 4, j++) {
+		uint32_t *tmp = (u32 *)&csr->csr_buf[readcount + i];
+		/*
+		 * The firmware payload is an array of 32 bit words stored in
+		 * little-endian format in the firmware image and programmed
+		 * as 32 bit big-endian format to memory.
+		 */
+		dmc_payload[j] = cpu_to_be32(*tmp);
+	}
+
+	/* load csr program during system boot, as needed for DC states */
+	intel_csr_load_program(dev);
+out:
+	kfree(csr->csr_buf);
+	csr->csr_buf = NULL;
+}
+
+int intel_csr_ucode_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_csr *csr = &dev_priv->csr;
+	int ret;
+
+	if (!HAS_CSR(dev))
+		return 0;
+
+	if (IS_SKYLAKE(dev))
+		csr->fw_path = I915_CSR_SKL;
+	else {
+		DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
+		return 0;
+	}
+
+	/* CSR supported for platform, load firmware */
+	ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
+				&dev_priv->dev->pdev->dev,
+				GFP_KERNEL, dev_priv,
+				finish_csr_load);
+	if (ret)
+		i915_firmware_load_error_print(csr->fw_path, ret);
+
+	return ret;
+}
+
+void intel_csr_ucode_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (!HAS_CSR(dev))
+		return;
+
+	kfree(dev_priv->dmc_info.dmc_payload);
+	memset(&dev_priv->dmc_info, 0, sizeof(struct intel_dmc_info));
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index fca7b9f..cd20b6a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1059,6 +1059,11 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
 unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
 				     struct drm_i915_gem_object *obj);
 
+/* intel_csr.c */
+int intel_csr_ucode_init(struct drm_device *dev);
+void intel_csr_load_program(struct drm_device *dev);
+void intel_csr_ucode_fini(struct drm_device *dev);
+
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
