msm: ocmem: Add Device Tree Support

Add support for reading ocmem hardware data from device
tree.

Change-Id: Ibb626741351414d7f9d199e7f8b9d71a782f2106
Signed-off-by: Naveen Ramaraj <nramaraj@codeaurora.org>
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 43c7fc8..a233080 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  */
 
-#include <mach/ocmem_priv.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -18,10 +17,12 @@
 #include <linux/rbtree.h>
 #include <linux/genalloc.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
 
 /* This code is to temporarily work around the default state of OCMEM
    regions in Virtio. These registers will be read from DT in a subsequent
@@ -41,14 +42,6 @@
 	unsigned int p_tail;
 };
 
-struct ocmem_plat_data {
-	void __iomem *vbase;
-	unsigned long size;
-	unsigned long base;
-	struct ocmem_partition *parts;
-	unsigned nr_parts;
-};
-
 struct ocmem_zone zones[OCMEM_CLIENT_MAX];
 
 struct ocmem_zone *get_zone(unsigned id)
@@ -183,8 +176,216 @@
 	return pdata;
 }
 
+int __devinit of_ocmem_parse_regions(struct device *dev,
+			struct ocmem_partition **part)
+{
+	const char *name;
+	struct device_node *child = NULL;
+	int nr_parts = 0;
+	int i = 0;
+	int rc = 0;
+	int id = -1;
+
+	/*Compute total partitions */
+	for_each_child_of_node(dev->of_node, child)
+		nr_parts++;
+
+	if (nr_parts == 0)
+		return 0;
+
+	*part = devm_kzalloc(dev, nr_parts * sizeof(**part),
+			GFP_KERNEL);
+
+	if (!*part)
+		return -ENOMEM;
+
+	for_each_child_of_node(dev->of_node, child)
+	{
+		const u32 *addr;
+		u32 min;
+		u64 size;
+		u64 p_start;
+
+		addr = of_get_address(child, 0, &size, NULL);
+
+		if (!addr) {
+			dev_err(dev, "Invalid addr for partition %d, ignored\n",
+						i);
+			continue;
+		}
+
+		rc = of_property_read_u32(child, "qcom,ocmem-part-min", &min);
+
+		if (rc) {
+			dev_err(dev, "No min for partition %d, ignored\n", i);
+			continue;
+		}
+
+		rc = of_property_read_string(child, "qcom,ocmem-part-name",
+							&name);
+
+		if (rc) {
+			dev_err(dev, "No name for partition %d, ignored\n", i);
+			continue;
+		}
+
+		id = get_id(name);
+
+		if (id < 0) {
+			dev_err(dev, "Ignoring invalid partition %s\n", name);
+			continue;
+		}
+
+		p_start = of_translate_address(child, addr);
+
+		if (p_start == OF_BAD_ADDR) {
+			dev_err(dev, "Invalid offset for partition %d\n", i);
+			continue;
+		}
+
+		(*part)[i].p_start = p_start;
+		(*part)[i].p_size = size;
+		(*part)[i].id = id;
+		(*part)[i].name = name;
+		(*part)[i].p_min = min;
+		(*part)[i].p_tail = of_property_read_bool(child, "tail");
+		i++;
+	}
+
+	return i;
+}
+
 static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
 {
+	struct device   *dev = &pdev->dev;
+	struct device_node *node = pdev->dev.of_node;
+	struct ocmem_plat_data *pdata = NULL;
+	struct ocmem_partition *parts = NULL;
+	struct resource *ocmem_irq;
+	struct resource *dm_irq;
+	struct resource *ocmem_mem;
+	struct resource *reg_base;
+	struct resource *br_base;
+	struct resource *dm_base;
+	struct resource *ocmem_mem_io;
+	unsigned nr_parts = 0;
+	unsigned nr_regions = 0;
+
+	pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+			GFP_KERNEL);
+
+	if (!pdata) {
+		dev_err(dev, "Unable to allocate memory for platform data\n");
+		return NULL;
+	}
+
+	ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							"ocmem_physical");
+	if (!ocmem_mem) {
+		dev_err(dev, "No OCMEM memory resource\n");
+		return NULL;
+	}
+
+	ocmem_mem_io = request_mem_region(ocmem_mem->start,
+				resource_size(ocmem_mem), pdev->name);
+
+	if (!ocmem_mem_io) {
+		dev_err(dev, "Could not claim OCMEM memory\n");
+		return NULL;
+	}
+
+	pdata->base = ocmem_mem->start;
+	pdata->size = resource_size(ocmem_mem);
+	pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
+						resource_size(ocmem_mem));
+	if (!pdata->vbase) {
+		dev_err(dev, "Could not ioremap ocmem memory\n");
+		return NULL;
+	}
+
+	reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							"ocmem_ctrl_physical");
+	if (!reg_base) {
+		dev_err(dev, "No OCMEM register resource\n");
+		return NULL;
+	}
+
+	pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
+				resource_size(reg_base));
+	if (!pdata->reg_base) {
+		dev_err(dev, "Could not ioremap register map\n");
+		return NULL;
+	}
+
+	br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"br_ctrl_physical");
+	if (!br_base) {
+		dev_err(dev, "No OCMEM BR resource\n");
+		return NULL;
+	}
+
+	pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
+				resource_size(br_base));
+	if (!pdata->br_base) {
+		dev_err(dev, "Could not ioremap BR resource\n");
+		return NULL;
+	}
+
+	dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"dm_ctrl_physical");
+	if (!dm_base) {
+		dev_err(dev, "No OCMEM DM resource\n");
+		return NULL;
+	}
+
+	pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
+				resource_size(dm_base));
+	if (!pdata->dm_base) {
+		dev_err(dev, "Could not ioremap DM resource\n");
+		return NULL;
+	}
+
+	ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+							"ocmem_irq");
+
+	if (!ocmem_irq) {
+		dev_err(dev, "No OCMEM IRQ resource\n");
+		return NULL;
+	}
+
+	dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"dm_irq");
+
+	if (!dm_irq) {
+		dev_err(dev, "No DM IRQ resource\n");
+		return NULL;
+	}
+
+	if (of_property_read_u32(node, "qcom,ocmem-num-regions",
+					&nr_regions)) {
+		dev_err(dev, "No OCMEM memory regions specified\n");
+	}
+
+	if (nr_regions == 0) {
+		dev_err(dev, "No hardware memory regions found\n");
+		return NULL;
+	}
+
+	/* Figure out the number of partititons */
+	nr_parts = of_ocmem_parse_regions(dev, &parts);
+	if (nr_parts <= 0) {
+		dev_err(dev, "No valid OCMEM partitions found\n");
+		goto pdata_error;
+	} else
+		dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
+
+	pdata->nr_parts = nr_parts;
+	pdata->parts = parts;
+	pdata->nr_regions = nr_regions;
+	pdata->ocmem_irq = ocmem_irq->start;
+	pdata->dm_irq = dm_irq->start;
+	return pdata;
+pdata_error:
 	return NULL;
 }
 
@@ -225,7 +426,7 @@
 			return -EBUSY;
 		}
 
-		start = pdata->base + part->p_start;
+		start = part->p_start;
 		ret = gen_pool_add(zone->z_pool, start,
 					part->p_size, -1);
 
@@ -273,7 +474,7 @@
 				zone->z_end, part->p_size/SZ_1K);
 	}
 
-	dev_info(dev, "Total active zones = %d\n", active_zones);
+	dev_dbg(dev, "Total active zones = %d\n", active_zones);
 	return 0;
 }
 
@@ -282,7 +483,7 @@
 	struct device   *dev = &pdev->dev;
 	void *ocmem_region_vbase = NULL;
 
-	if (!pdev->dev.of_node->child) {
+	if (!pdev->dev.of_node) {
 		dev_info(dev, "Missing Configuration in Device Tree\n");
 		ocmem_pdata = parse_static_config(pdev);
 	} else {
@@ -297,6 +498,8 @@
 	BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
 	BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
 
+	dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
+
 	platform_set_drvdata(pdev, ocmem_pdata);
 
 	if (ocmem_zone_init(pdev))
@@ -316,7 +519,7 @@
 	writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
 	writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
 	writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
-	dev_info(dev, "initialized successfully\n");
+	dev_dbg(dev, "initialized successfully\n");
 	return 0;
 }
 
@@ -326,7 +529,7 @@
 }
 
 static struct of_device_id msm_ocmem_dt_match[] = {
-	{       .compatible = "qcom,msm_ocmem",
+	{       .compatible = "qcom,msm-ocmem",
 	},
 	{}
 };