[RFC,01/10] drm/i915/config: Initial framework

Submitted by Bob Paauwe on April 13, 2015, 8:51 p.m.

Details

Message ID 1428958271-15653-2-git-send-email-bob.j.paauwe@intel.com
State New
Headers show

Not browsing as part of any series.

Commit Message

Bob Paauwe April 13, 2015, 8:51 p.m.
This adds an init-time configuration framework that parses configuration
data from an ACPI property table. The table is assumed to have well
defined sub-device property tables that correspond to the various
driver components.  Initially the following sub-device tables are
defined:

CRTC (CRTC)
   The CRTC sub-device table contains additional sub-device tables
   where each one corresponds to a CRTC.  Each CRTC sub-device must
   include a property called "id" whose value matches the driver's
   crtc id. Additional properties for the CRTC are used to configure
   the crtc.

Connector (CNCT)
   The CNCT sub-device table contains additional sub-device tables
   where each one corresponds to a connector. Each of the connector
   sub-device tables must include a property called "name" whose value
   matches a connector name assigned by the driver (see later patch
   for output name function). Additional connector properties can
   be set through these tables.

Plane (PLNS)
   The PLNS sub-device table contains additional sub-device tables
   where each one corresponds to a plane.  [this needs additional work]

In addition, the main device property table for the device may
contain configuration information that applies to general driver
configuration.

The framework includes a couple of helper functions to access the
configuration data.

   intel_config_get_integer() will look up a configuration property
   and return the integer value associated with it.

   intel_config_init_<component>_property() will look up a
   configuration property and assign the value to a drm
   property of the same name.  These functions are used to
   initialize drm property instances to specific values.

v2: Add plane/connector properties to proper lists. (Bob)
    Abstract out the list cleanup (Jani)
    Squash patch that abstracted list allocation (Jani)
    Use module parameter for firmware file if it exist (Jani)
    Use defined name to access table handle (Bob)
    Remove the acpi table bind/unbind (Bob)
    Make firmware struct part of the config (Bob)
    Release firmware on shutdown (Bob)
    Free allocated intel_config_info on shutdown (Bob)

Signed-off-by: Bob Paauwe <bob.j.paauwe@intel.com>
---
 drivers/gpu/drm/i915/Makefile       |   3 +-
 drivers/gpu/drm/i915/i915_dma.c     |   4 +
 drivers/gpu/drm/i915/i915_drv.h     |  17 ++
 drivers/gpu/drm/i915/i915_params.c  |   6 +
 drivers/gpu/drm/i915/intel_config.c | 558 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h    |  27 ++
 6 files changed, 614 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/i915/intel_config.c

Patch hide | download patch | download mbox

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__ */