diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index a69002e..2c30112 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_config.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 e44116f..e18dac2 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -803,6 +803,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 	dev->dev_private = dev_priv;
 	dev_priv->dev = dev;
 
+	intel_config_init(dev);
+
 	/* Setup the write-once "constant" device info */
 	device_info = (struct intel_device_info *)&dev_priv->info;
 	memcpy(device_info, info, sizeof(dev_priv->info));
@@ -1078,6 +1080,8 @@ int i915_driver_unload(struct drm_device *dev)
 
 	intel_fbdev_fini(dev);
 
+	intel_config_shutdown(dev);
+
 	drm_vblank_cleanup(dev);
 
 	intel_modeset_cleanup(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 79da7f3..1484439 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1557,6 +1557,21 @@ struct i915_virtual_gpu {
 	bool active;
 };
 
+struct intel_config_node {
+	struct acpi_device *adev;
+	struct list_head node;
+	struct list_head list;
+};
+
+struct intel_config_info {
+	const struct firmware *fw;
+	struct intel_config_node base;
+	struct list_head crtc_list;
+	struct list_head connector_list;
+	struct list_head plane_list;
+};
+
+
 struct drm_i915_private {
 	struct drm_device *dev;
 	struct kmem_cache *objects;
@@ -1800,6 +1815,7 @@ struct drm_i915_private {
 	u32 long_hpd_port_mask;
 	u32 short_hpd_port_mask;
 	struct work_struct dig_port_work;
+	struct intel_config_info *config_info;
 
 	/*
 	 * if we get a HPD irq from DP and a HPD irq from non-DP
@@ -2477,6 +2493,7 @@ struct i915_params {
 	int enable_ips;
 	int invert_brightness;
 	int enable_cmd_parser;
+	char cfg_firmware[PATH_MAX];
 	/* leave bools at the end to not create holes */
 	bool enable_hangcheck;
 	bool fastboot;
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index bb64415..e7f7aaa 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -53,6 +53,7 @@ struct i915_params i915 __read_mostly = {
 	.mmio_debug = 0,
 	.verbose_state_checks = 1,
 	.nuclear_pageflip = 0,
+	.cfg_firmware = "",
 };
 
 module_param_named(modeset, i915.modeset, int, 0400);
@@ -184,3 +185,8 @@ MODULE_PARM_DESC(verbose_state_checks,
 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).");
+
+module_param_string(cfg_firmware, i915.cfg_firmware, sizeof(i915.cfg_firmware), 0444);
+MODULE_PARM_DESC(cfg_firmware,
+		 "Load configuration firmware from built-in data or /lib/firmware. ");
+
diff --git a/drivers/gpu/drm/i915/intel_config.c b/drivers/gpu/drm/i915/intel_config.c
new file mode 100644
index 0000000..38f8540
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_config.c
@@ -0,0 +1,558 @@
+/*
+ * i915 configuration via ACPI device properties.
+ *
+ * Copyright (C) 2014, 2015 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+#include <acpi/acpi_bus.h>
+#include "intel_drv.h"
+#include <drm/i915_drm.h>
+#include "i915_drv.h"
+#include "i915_trace.h"
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+
+#define i915_ACPI_PRP_ROOT "\\_SB.PRP.GFX0"
+
+/*
+ * Load an ACPI property table into the ACPI subsystem.
+ *
+ * First, verify that a table isn't already loaded.  The table may
+ * be part of the ACPI firmware and thus loaded by the ACPI sub-system
+ * during boot.  It is also possible for ACPI sub-system to load tables
+ * to override those supplied by the firmware.
+ *
+ * If a property table for the GFX device has not been loaded, attempt
+ * to load one from /lib/firmware here.  The name will default to
+ * drm_i915.aml but the name be overridden by the cfg_firmware module
+ * parameter.
+ *
+ * The order of precidence for table loading is:
+ *   - dyanamic table loaded by ACPI driver
+ *   - table built into firmware
+ *   - dynamic table loaded based on driver name or module parameter
+ *
+ * If the table is loaded by the driver, it will be unloaded when the
+ * driver module is unloaded.  Tables that are part of the firmware or
+ * overridden by the ACPI driver are not unloaded and cannot be replaced
+ * by tables loaded by the driver.
+ */
+static int intel_acpi_load_table(struct drm_device *dev, char *firmware,
+				 struct intel_config_info *info)
+{
+	struct acpi_table_header *table;
+	acpi_status status;
+	acpi_handle handle;
+	struct acpi_device *acpi_dev = NULL;
+	int ret = 0;
+
+	/* make sure the table isn't already loaded before loading it */
+	status = acpi_get_handle(ACPI_ROOT_OBJECT, i915_ACPI_PRP_ROOT, &handle);
+	if (ACPI_FAILURE(status)) {
+
+		/* Try to dynamically load a table.... */
+		DRM_DEBUG_DRIVER("Requesting configuration table: %s\n",
+				 firmware);
+		ret = request_firmware(&info->fw, firmware, dev->dev);
+		if (ret != 0) {
+			DRM_ERROR("Failed to find ACPI table %s: %d\n",
+				  firmware, ret);
+			info->fw = NULL;
+			goto bad_table;
+		} else {
+			table = (struct acpi_table_header *)info->fw->data;
+		}
+
+		/* Load the table into the acpi device. */
+		status = acpi_load_table(table);
+		if (ACPI_FAILURE(status))
+			goto bad_table;
+
+		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, true);
+
+		/* Get a handle and scan the bus */
+		status = acpi_get_handle(ACPI_ROOT_OBJECT, i915_ACPI_PRP_ROOT,
+					 &handle);
+		if (ACPI_FAILURE(status))
+			goto bad_table;
+
+		acpi_bus_scan(handle);
+
+		/* Not using this, why make the call? */
+		if (acpi_bus_get_device(handle, &acpi_dev))
+			goto bad_table;
+
+	} else {
+		DRM_DEBUG_DRIVER("ACPI Property table previously loaded for _SB.PRP.GFX0\n");
+	}
+
+	return 0;
+
+bad_table:
+	release_firmware(info->fw);
+	return -ENODEV;
+}
+
+/*
+ * Use ACPI methods to get the property.
+ *
+ * This isn't using the generic device_property_read because that
+ * can only access properties associated with the actual device. It
+ * doesn't understand our sub-component property tree.
+ */
+static bool node_property(struct intel_config_node *n,
+			  const char *prop,
+			  void *value)
+{
+	int ret = 0;
+	const union acpi_object *obj;
+
+	ret = acpi_dev_get_property(n->adev, prop, ACPI_TYPE_ANY, &obj);
+	if (ret == -ENODATA) {
+		/*
+		 * This isn't really a failure, it's ok if the property
+		 * doesn't exist. The message is for debug purposes only.
+		 */
+		DRM_DEBUG_DRIVER("Property \"%s\" not found in %s\n",
+				 prop, acpi_device_bid(n->adev));
+	} else if (ret == -EINVAL) {
+		DRM_ERROR("Invalid acpi device or property name.\n");
+	} else if (ret) {
+		/* This is a failure. */
+		DRM_ERROR("Property request failed for %s: %d\n", prop, ret);
+	} else {
+		switch (obj->type) {
+		case ACPI_TYPE_INTEGER:
+			*(u32 *)value = obj->integer.value;
+			break;
+		case ACPI_TYPE_STRING:
+			*(char **)value = obj->string.pointer;
+			break;
+		default:
+			DRM_ERROR("Unsupported property type, only support integer and string.\n");
+			ret = -1;
+			break;
+		}
+	}
+
+	return ret == 0;
+}
+
+
+static bool alloc_new_node(struct acpi_device *cl, struct list_head *list)
+{
+	struct intel_config_node *new_node;
+
+	new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
+	if (!new_node)
+		return false;
+
+	new_node->adev = cl;
+	INIT_LIST_HEAD(&new_node->node);
+	list_add_tail(&new_node->node, list);
+
+	return true;
+}
+
+static void list_cleanup(struct intel_config_info *info)
+{
+	struct intel_config_node *n, *tmp;
+
+	list_for_each_entry_safe(n, tmp, &info->crtc_list, node)
+		kfree(n);
+	list_for_each_entry_safe(n, tmp, &info->connector_list, node)
+		kfree(n);
+	list_for_each_entry_safe(n, tmp, &info->plane_list, node)
+		kfree(n);
+}
+
+/**
+ * intel_config_init -
+ *
+ * Initialize the configuration framework by attempting to load a
+ * property table and parse the contents into component lists.
+ *
+ * @dev: The drm driver device.
+ */
+void intel_config_init(struct drm_device *dev)
+{
+	struct intel_config_info *info;
+	acpi_handle handle;
+	struct acpi_device *cl, *component;
+	char *cname;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		DRM_ERROR("Failed to allocate memory for configuration.\n");
+		return;
+	}
+
+	/* Load an ACPI table from /lib/firmware.  */
+	if (i915.cfg_firmware[0] == '\0')
+	    snprintf(i915.cfg_firmware, PATH_MAX, "drm_%s.aml",
+		     dev->driver->name);
+
+	if (intel_acpi_load_table(dev, i915.cfg_firmware, info) != 0) {
+		DRM_ERROR("Failed to load ACPI device property table.\n");
+		return;
+	}
+
+	DRM_DEBUG_DRIVER("Loaded ACPI configuration for %s\n",
+			 dev->driver->name);
+
+	INIT_LIST_HEAD(&info->base.list);
+	INIT_LIST_HEAD(&info->crtc_list);
+	INIT_LIST_HEAD(&info->connector_list);
+	INIT_LIST_HEAD(&info->plane_list);
+
+	acpi_get_handle(ACPI_ROOT_OBJECT, i915_ACPI_PRP_ROOT, &handle);
+	if (!handle) {
+		DRM_DEBUG_DRIVER("No associated ACPI handle.\n");
+		kfree(info);
+		return;
+	} else {
+		acpi_bus_get_device(handle, &info->base.adev);
+	}
+
+	/*
+	 * Create a list of one for the top level driver config.
+	 *
+	 * We don't really need a full config_info structure for this but
+	 * it simplifies the handling of driver general config settings
+	 * as we don't have to have a special case and unique structure
+	 * just for this.
+	 */
+	INIT_LIST_HEAD(&info->base.node);
+	list_add_tail(&info->base.node, &info->base.list);
+
+/* Component sub-device ACPI names */
+#define i915_COMPONENT_CRTC "CRTC"
+#define i915_COMPONENT_CONNECTOR "CNCT"
+#define i915_COMPONENT_PLANE "PLNS"
+
+	/* Build lists */
+	list_for_each_entry(component, &info->base.adev->children, node) {
+		if (!component)
+			continue;
+
+		cname = acpi_device_bid(component);
+
+		if (strcmp(cname, i915_COMPONENT_CRTC) == 0) {
+			list_for_each_entry(cl, &component->children, node) {
+				if (!alloc_new_node(cl, &info->crtc_list))
+					goto bail;
+			}
+		} else if (strcmp(cname, i915_COMPONENT_CONNECTOR) == 0) {
+			list_for_each_entry(cl, &component->children, node) {
+				if (!alloc_new_node(cl, &info->connector_list))
+					goto bail;
+			}
+		} else if (strcmp(cname, i915_COMPONENT_PLANE) == 0) {
+			list_for_each_entry(cl, &component->children, node) {
+				if (!alloc_new_node(cl, &info->plane_list))
+					goto bail;
+			}
+		}
+	}
+
+	dev_priv->config_info = info;
+	DRM_DEBUG_DRIVER("i915 Configuration loaded.\n");
+	return;
+
+bail:
+	DRM_DEBUG_DRIVER("i915 Configuration aborted, insufficient memory.\n");
+	list_cleanup(info);
+	kfree(info);
+	dev_priv->config_info = NULL;
+}
+
+
+/**
+ * Clean up the configuration infrastructure as the driver is
+ * shuting down.  Don't leak memory!
+ *
+ * @dev: The drm driver device.
+ */
+void intel_config_shutdown(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	acpi_handle handle;
+	acpi_status status;
+	struct acpi_device *adev;
+	struct intel_config_info *info;
+
+	if (dev_priv->config_info == NULL)
+		return;
+
+	/* Free the component lists.  */
+	info = dev_priv->config_info;
+	adev = info->base.adev;
+	list_cleanup(info);
+
+	/* Unload any dynamically loaded ACPI property table */
+	status = acpi_get_handle(ACPI_ROOT_OBJECT, i915_ACPI_PRP_ROOT,
+				 &handle);
+	if (ACPI_FAILURE(status)) {
+		DRM_ERROR("Failed to locate dynamic ACPI table.");
+		return;
+	}
+
+	if (handle) {
+		DRM_DEBUG_DRIVER("Unloading dynamic i915 Configuration ACPI table.\n");
+		acpi_bus_trim(adev);
+
+		status = acpi_unload_parent_table(handle);
+		if (ACPI_FAILURE(status))
+			DRM_ERROR("Failed to unload the i915 Configuration"
+				  "ACPI table. %d\n", status);
+	}
+
+	if (info->fw)
+		release_firmware(info->fw);
+
+	kfree(info);
+}
+
+
+
+/*
+ * does_name_match
+ *
+ * The various drm components have names assocated with them. To link
+ * a component in the ACPI property tree, use a "special" property
+ * called "name".
+ *
+ * The exception is the general driver properties.  There is no "name"
+ * property associated with those.  We could force one, but that may
+ * be less intuitive than leaving the name empty.
+ *
+ * This function look for a property called "name" and compares the
+ * value of that property with the passed in name parameter.
+ */
+static bool does_name_match(struct intel_config_node *node, const char *name)
+{
+	char *p_name;
+
+	/*
+	 * General driver properties aren't in a section with a "name"
+	 * property. Thus this should just return true in that case.
+	 */
+	if (!name || strlen(name) == 0)
+		return true;
+
+
+	/* Look up a name property and see if it matches */
+	if (node_property(node, "name", &p_name)) {
+		if (strcmp(name, p_name) == 0)
+			return true;
+	}
+
+	return false;
+}
+
+
+/*
+ * Map the configuration sub component enum to the cached
+ * sub component list.
+ */
+static struct list_head *cfg_type_to_list(struct intel_config_info *info,
+					  enum cfg_type cfg_type)
+{
+	switch (cfg_type) {
+	case CFG_DRV:
+		return &info->base.list;
+	case CFG_CRTC:
+		return &info->crtc_list;
+	case CFG_CONNECTOR:
+		return &info->connector_list;
+	case CFG_PLANE:
+		return &info->plane_list;
+	}
+	return NULL;
+}
+
+/*
+ * Integer property.
+ *
+ * Look up a property and set the value pointer to the property value.
+ *
+ * returns true if the property was found, false if not.
+ */
+bool intel_config_get_integer(struct drm_i915_private *dev_priv,
+			      enum cfg_type cfg_type,
+			      const char *name,
+			      const char *property,
+			      uint32_t *value)
+{
+	struct intel_config_info *info = dev_priv->config_info;
+	struct intel_config_node *n;
+	struct list_head *list;
+
+	if (!info)
+		return false;
+
+	list = cfg_type_to_list(info, cfg_type);
+	if (!list)
+		return false;
+
+	list_for_each_entry(n, list, node) {
+		if (does_name_match(n, name)) {
+			if (node_property(n, property, value))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+/*
+ * Look up a drm property name in the configuration store and if
+ * found, return the value.
+ *
+ * A default value is included in the parameter list so that something
+ * reasonable is returned if the lookup fails to find a matching
+ * configuration key.
+ */
+static uint64_t lookup_property(struct drm_i915_private *dev_priv,
+				const char *name,
+				struct drm_property *property,
+				enum cfg_type cfg_type,
+				uint64_t dflt)
+{
+	struct intel_config_info *info = dev_priv->config_info;
+	struct drm_property_enum *prop_enum;
+	const char *value;
+	uint64_t retval = dflt;
+	struct intel_config_node *n;
+	struct list_head *list;
+
+	list = cfg_type_to_list(info, cfg_type);
+	if (!list)
+		goto out;
+
+	list_for_each_entry(n, list, node) {
+		if (!does_name_match(n, name))
+			continue;
+		/*
+		 * FIXME: This is assuming that the type is string
+		 * for enun drm properties.  This should be more
+		 * generic and map drm property types to ACPI property
+		 * types.
+		 */
+		if (!node_property(n, property->name, &value))
+			continue;
+
+		/* Look for a matching enum */
+		list_for_each_entry(prop_enum, &property->enum_list, head) {
+			if (strcmp(value, prop_enum->name) == 0) {
+				retval = prop_enum->value;
+				goto out;
+			}
+		}
+	}
+
+out:
+	return retval;
+}
+
+/*
+ * Connector properties.
+ *
+ * If a connector drm property has a corresponding configuration property,
+ * use the configuration property value to initialize the drm property.
+ */
+uint64_t intel_config_init_connector_property(struct drm_connector *connector,
+					      struct drm_property *property,
+					      uint64_t dflt)
+{
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
+	struct intel_config_info *info = dev_priv->config_info;
+	uint64_t retval = dflt;
+
+	if (!info)
+		goto out;
+
+	retval = lookup_property(dev_priv, connector->name, property,
+				 CFG_CONNECTOR, dflt);
+
+out:
+	drm_object_attach_property(&connector->base, property, retval);
+	return retval;
+}
+
+
+/*
+ * Plane properties.
+ *
+ * If a plane drm property has a corresponding configuration property,
+ * use the configuration property value to initialize the drm property.
+ */
+uint64_t intel_config_init_plane_property(struct drm_plane *plane,
+					  const char *name,
+					  struct drm_property *property,
+					  uint64_t dflt)
+{
+	struct drm_i915_private *dev_priv = plane->dev->dev_private;
+	struct intel_config_info *info = dev_priv->config_info;
+	uint64_t retval = dflt;
+
+	if (!info)
+		goto out;
+
+	retval = lookup_property(dev_priv, name, property, CFG_PLANE, dflt);
+
+out:
+	drm_object_attach_property(&plane->base, property, retval);
+	return retval;
+}
+
+
+/*
+ * CRTC properties.
+ *
+ * If a crtc drm property has a corresponding configuration property,
+ * use the configuration property value to initialize the drm property.
+ */
+uint64_t intel_config_init_crtc_property(struct drm_crtc *crtc,
+					 const char *name,
+					 struct drm_property *property,
+					 uint64_t dflt)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	struct intel_config_info *info = dev_priv->config_info;
+	uint64_t retval = dflt;
+
+	if (!info)
+		goto out;
+
+	retval = lookup_property(dev_priv, name, property, CFG_CRTC, dflt);
+
+out:
+	drm_object_attach_property(&crtc->base, property, retval);
+	return retval;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 6a2ee0c..8c40a97 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1407,4 +1407,31 @@ 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;
 
+/* intel_config.c */
+enum cfg_type {
+	CFG_DRV,
+	CFG_CRTC,
+	CFG_CONNECTOR,
+	CFG_PLANE
+};
+
+void intel_config_init(struct drm_device *dev);
+void intel_config_shutdown(struct drm_device *dev);
+bool intel_config_get_integer(struct drm_i915_private *dev_priv,
+			  enum cfg_type cfg_type,
+			  const char *name,
+			  const char *property,
+			  uint32_t *value);
+uint64_t intel_config_init_connector_property(struct drm_connector *connector,
+			  struct drm_property *property,
+			  uint64_t dflt);
+uint64_t intel_config_init_plane_property(struct drm_plane *plane,
+			  const char *name,
+			  struct drm_property *property,
+			  uint64_t dflt);
+uint64_t intel_config_init_crtc_property(struct drm_crtc *crtc,
+			  const char *name,
+			  struct drm_property *property,
+			  uint64_t dflt);
+
 #endif /* __INTEL_DRV_H__ */
