summary refs log tree commit diff
path: root/arch/arm/mach-omap2/omap_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap_device.c')
-rw-r--r--arch/arm/mach-omap2/omap_device.c294
1 files changed, 109 insertions, 185 deletions
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index acbede082b5b..d45cbfdb4be6 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -35,6 +35,8 @@
 #include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/notifier.h>
 
 #include "common.h"
@@ -309,88 +311,6 @@ int omap_device_get_context_loss_count(struct platform_device *pdev)
 }
 
 /**
- * omap_device_count_resources - count number of struct resource entries needed
- * @od: struct omap_device *
- * @flags: Type of resources to include when counting (IRQ/DMA/MEM)
- *
- * Count the number of struct resource entries needed for this
- * omap_device @od.  Used by omap_device_build_ss() to determine how
- * much memory to allocate before calling
- * omap_device_fill_resources().  Returns the count.
- */
-static int omap_device_count_resources(struct omap_device *od,
-				       unsigned long flags)
-{
-	int c = 0;
-	int i;
-
-	for (i = 0; i < od->hwmods_cnt; i++)
-		c += omap_hwmod_count_resources(od->hwmods[i], flags);
-
-	pr_debug("omap_device: %s: counted %d total resources across %d hwmods\n",
-		 od->pdev->name, c, od->hwmods_cnt);
-
-	return c;
-}
-
-/**
- * omap_device_fill_resources - fill in array of struct resource
- * @od: struct omap_device *
- * @res: pointer to an array of struct resource to be filled in
- *
- * Populate one or more empty struct resource pointed to by @res with
- * the resource data for this omap_device @od.  Used by
- * omap_device_build_ss() after calling omap_device_count_resources().
- * Ideally this function would not be needed at all.  If omap_device
- * replaces platform_device, then we can specify our own
- * get_resource()/ get_irq()/etc functions that use the underlying
- * omap_hwmod information.  Or if platform_device is extended to use
- * subarchitecture-specific function pointers, the various
- * platform_device functions can simply call omap_device internal
- * functions to get device resources.  Hacking around the existing
- * platform_device code wastes memory.  Returns 0.
- */
-static int omap_device_fill_resources(struct omap_device *od,
-				      struct resource *res)
-{
-	int i, r;
-
-	for (i = 0; i < od->hwmods_cnt; i++) {
-		r = omap_hwmod_fill_resources(od->hwmods[i], res);
-		res += r;
-	}
-
-	return 0;
-}
-
-/**
- * _od_fill_dma_resources - fill in array of struct resource with dma resources
- * @od: struct omap_device *
- * @res: pointer to an array of struct resource to be filled in
- *
- * Populate one or more empty struct resource pointed to by @res with
- * the dma resource data for this omap_device @od.  Used by
- * omap_device_alloc() after calling omap_device_count_resources().
- *
- * Ideally this function would not be needed at all.  If we have
- * mechanism to get dma resources from DT.
- *
- * Returns 0.
- */
-static int _od_fill_dma_resources(struct omap_device *od,
-				      struct resource *res)
-{
-	int i, r;
-
-	for (i = 0; i < od->hwmods_cnt; i++) {
-		r = omap_hwmod_fill_dma_resources(od->hwmods[i], res);
-		res += r;
-	}
-
-	return 0;
-}
-
-/**
  * omap_device_alloc - allocate an omap_device
  * @pdev: platform_device that will be included in this omap_device
  * @oh: ptr to the single omap_hwmod that backs this omap_device
@@ -407,8 +327,7 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
 {
 	int ret = -ENOMEM;
 	struct omap_device *od;
-	struct resource *res = NULL;
-	int i, res_count;
+	int i;
 	struct omap_hwmod **hwmods;
 
 	od = kzalloc(sizeof(struct omap_device), GFP_KERNEL);
@@ -424,74 +343,6 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
 
 	od->hwmods = hwmods;
 	od->pdev = pdev;
-
-	/*
-	 * Non-DT Boot:
-	 *   Here, pdev->num_resources = 0, and we should get all the
-	 *   resources from hwmod.
-	 *
-	 * DT Boot:
-	 *   OF framework will construct the resource structure (currently
-	 *   does for MEM & IRQ resource) and we should respect/use these
-	 *   resources, killing hwmod dependency.
-	 *   If pdev->num_resources > 0, we assume that MEM & IRQ resources
-	 *   have been allocated by OF layer already (through DTB).
-	 *   As preparation for the future we examine the OF provided resources
-	 *   to see if we have DMA resources provided already. In this case
-	 *   there is no need to update the resources for the device, we use the
-	 *   OF provided ones.
-	 *
-	 * TODO: Once DMA resource is available from OF layer, we should
-	 *   kill filling any resources from hwmod.
-	 */
-	if (!pdev->num_resources) {
-		/* Count all resources for the device */
-		res_count = omap_device_count_resources(od, IORESOURCE_IRQ |
-							    IORESOURCE_DMA |
-							    IORESOURCE_MEM);
-	} else {
-		/* Take a look if we already have DMA resource via DT */
-		for (i = 0; i < pdev->num_resources; i++) {
-			struct resource *r = &pdev->resource[i];
-
-			/* We have it, no need to touch the resources */
-			if (r->flags == IORESOURCE_DMA)
-				goto have_everything;
-		}
-		/* Count only DMA resources for the device */
-		res_count = omap_device_count_resources(od, IORESOURCE_DMA);
-		/* The device has no DMA resource, no need for update */
-		if (!res_count)
-			goto have_everything;
-
-		res_count += pdev->num_resources;
-	}
-
-	/* Allocate resources memory to account for new resources */
-	res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
-	if (!res)
-		goto oda_exit3;
-
-	if (!pdev->num_resources) {
-		dev_dbg(&pdev->dev, "%s: using %d resources from hwmod\n",
-			__func__, res_count);
-		omap_device_fill_resources(od, res);
-	} else {
-		dev_dbg(&pdev->dev,
-			"%s: appending %d DMA resources from hwmod\n",
-			__func__, res_count - pdev->num_resources);
-		memcpy(res, pdev->resource,
-		       sizeof(struct resource) * pdev->num_resources);
-		_od_fill_dma_resources(od, &res[pdev->num_resources]);
-	}
-
-	ret = platform_device_add_resources(pdev, res, res_count);
-	kfree(res);
-
-	if (ret)
-		goto oda_exit3;
-
-have_everything:
 	pdev->archdata.od = od;
 
 	for (i = 0; i < oh_cnt; i++) {
@@ -501,8 +352,6 @@ have_everything:
 
 	return od;
 
-oda_exit3:
-	kfree(hwmods);
 oda_exit2:
 	kfree(od);
 oda_exit1:
@@ -522,6 +371,93 @@ void omap_device_delete(struct omap_device *od)
 }
 
 /**
+ * omap_device_copy_resources - Add legacy IO and IRQ resources
+ * @oh: interconnect target module
+ * @pdev: platform device to copy resources to
+ *
+ * We still have legacy DMA and smartreflex needing resources.
+ * Let's populate what they need until we can eventually just
+ * remove this function. Note that there should be no need to
+ * call this from omap_device_build_from_dt(), nor should there
+ * be any need to call it for other devices.
+ */
+static int
+omap_device_copy_resources(struct omap_hwmod *oh,
+			   struct platform_device *pdev)
+{
+	struct device_node *np, *child;
+	struct property *prop;
+	struct resource *res;
+	const char *name;
+	int error, irq = 0;
+
+	if (!oh || !oh->od || !oh->od->pdev) {
+		error = -EINVAL;
+		goto error;
+	}
+
+	np = oh->od->pdev->dev.of_node;
+	if (!np) {
+		error = -ENODEV;
+		goto error;
+	}
+
+	res = kzalloc(sizeof(*res) * 2, GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+
+	/* Do we have a dts range for the interconnect target module? */
+	error = omap_hwmod_parse_module_range(oh, np, res);
+
+	/* No ranges, rely on device reg entry */
+	if (error)
+		error = of_address_to_resource(np, 0, res);
+	if (error)
+		goto free;
+
+	/* SmartReflex needs first IO resource name to be "mpu" */
+	res[0].name = "mpu";
+
+	/*
+	 * We may have a configured "ti,sysc" interconnect target with a
+	 * dts child with the interrupt. If so use the first child's
+	 * first interrupt for "ti-hwmods" legacy support.
+	 */
+	of_property_for_each_string(np, "compatible", prop, name)
+		if (!strncmp("ti,sysc-", name, 8))
+			break;
+
+	child = of_get_next_available_child(np, NULL);
+
+	if (name)
+		irq = irq_of_parse_and_map(child, 0);
+	if (!irq)
+		irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		error = -EINVAL;
+		goto free;
+	}
+
+	/* Legacy DMA code needs interrupt name to be "0" */
+	res[1].start = irq;
+	res[1].end = irq;
+	res[1].flags = IORESOURCE_IRQ;
+	res[1].name = "0";
+
+	error = platform_device_add_resources(pdev, res, 2);
+
+free:
+	kfree(res);
+
+error:
+	WARN(error, "%s: %s device %s failed: %i\n",
+	     __func__, oh->name, dev_name(&pdev->dev),
+	     error);
+
+	return error;
+}
+
+/**
  * omap_device_build - build and register an omap_device with one omap_hwmod
  * @pdev_name: name of the platform_device driver to use
  * @pdev_id: this platform_device's connection ID
@@ -540,45 +476,24 @@ struct platform_device __init *omap_device_build(const char *pdev_name,
 						 struct omap_hwmod *oh,
 						 void *pdata, int pdata_len)
 {
-	struct omap_hwmod *ohs[] = { oh };
-
-	if (!oh)
-		return ERR_PTR(-EINVAL);
-
-	return omap_device_build_ss(pdev_name, pdev_id, ohs, 1, pdata,
-				    pdata_len);
-}
-
-/**
- * omap_device_build_ss - build and register an omap_device with multiple hwmods
- * @pdev_name: name of the platform_device driver to use
- * @pdev_id: this platform_device's connection ID
- * @oh: ptr to the single omap_hwmod that backs this omap_device
- * @pdata: platform_data ptr to associate with the platform_device
- * @pdata_len: amount of memory pointed to by @pdata
- *
- * Convenience function for building and registering an omap_device
- * subsystem record.  Subsystem records consist of multiple
- * omap_hwmods.  This function in turn builds and registers a
- * platform_device record.  Returns an ERR_PTR() on error, or passes
- * along the return value of omap_device_register().
- */
-struct platform_device __init *omap_device_build_ss(const char *pdev_name,
-						    int pdev_id,
-						    struct omap_hwmod **ohs,
-						    int oh_cnt, void *pdata,
-						    int pdata_len)
-{
 	int ret = -ENOMEM;
 	struct platform_device *pdev;
 	struct omap_device *od;
 
-	if (!ohs || oh_cnt == 0 || !pdev_name)
+	if (!oh || !pdev_name)
 		return ERR_PTR(-EINVAL);
 
 	if (!pdata && pdata_len > 0)
 		return ERR_PTR(-EINVAL);
 
+	if (strncmp(oh->name, "smartreflex", 11) &&
+	    strncmp(oh->name, "dma", 3)) {
+		pr_warn("%s need to update %s to probe with dt\na",
+			__func__, pdev_name);
+		ret = -ENODEV;
+		goto odbs_exit;
+	}
+
 	pdev = platform_device_alloc(pdev_name, pdev_id);
 	if (!pdev) {
 		ret = -ENOMEM;
@@ -591,7 +506,16 @@ struct platform_device __init *omap_device_build_ss(const char *pdev_name,
 	else
 		dev_set_name(&pdev->dev, "%s", pdev->name);
 
-	od = omap_device_alloc(pdev, ohs, oh_cnt);
+	/*
+	 * Must be called before omap_device_alloc() as oh->od
+	 * only contains the currently registered omap_device
+	 * and will get overwritten by omap_device_alloc().
+	 */
+	ret = omap_device_copy_resources(oh, pdev);
+	if (ret)
+		goto odbs_exit1;
+
+	od = omap_device_alloc(pdev, &oh, 1);
 	if (IS_ERR(od))
 		goto odbs_exit1;