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",
},
{}
};