[PATCH v4 03/14] ARM: edma: add AM33XX support to the private EDMA API

2013-01-10 Thread Matt Porter
Adds support for parsing the TI EDMA DT data into the required
EDMA private API platform data. Enables runtime PM support to
initialize the EDMA hwmod. Adds AM33XX EMDA crossbar event mux
support.

Signed-off-by: Matt Porter 
---
 arch/arm/common/edma.c |  314 ++--
 include/linux/platform_data/edma.h |1 +
 2 files changed, 306 insertions(+), 9 deletions(-)

diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index a3d189d..1951d63 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -24,6 +24,13 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include 
 
@@ -723,6 +730,9 @@ EXPORT_SYMBOL(edma_free_channel);
  */
 int edma_alloc_slot(unsigned ctlr, int slot)
 {
+   if (!edma_cc[ctlr])
+   return -EINVAL;
+
if (slot >= 0)
slot = EDMA_CHAN_SLOT(slot);
 
@@ -1366,31 +1376,291 @@ void edma_clear_event(unsigned channel)
 EXPORT_SYMBOL(edma_clear_event);
 
 /*---*/
+static int edma_of_read_u32_to_s8_array(const struct device_node *np,
+const char *propname, s8 *out_values,
+size_t sz)
+{
+   struct property *prop = of_find_property(np, propname, NULL);
+   const __be32 *val;
+
+   if (!prop)
+   return -EINVAL;
+   if (!prop->value)
+   return -ENODATA;
+   if ((sz * sizeof(u32)) > prop->length)
+   return -EOVERFLOW;
+
+   val = prop->value;
+
+   while (sz--)
+   *out_values++ = (s8)(be32_to_cpup(val++) & 0xff);
+
+   /* Terminate it */
+   *out_values++ = -1;
+   *out_values++ = -1;
+
+   return 0;
+}
+
+static int edma_of_read_u32_to_s16_array(const struct device_node *np,
+const char *propname, s16 *out_values,
+size_t sz)
+{
+   struct property *prop = of_find_property(np, propname, NULL);
+   const __be32 *val;
+
+   if (!prop)
+   return -EINVAL;
+   if (!prop->value)
+   return -ENODATA;
+   if ((sz * sizeof(u32)) > prop->length)
+   return -EOVERFLOW;
+
+   val = prop->value;
+
+   while (sz--)
+   *out_values++ = (s16)(be32_to_cpup(val++) & 0x);
+
+   /* Terminate it */
+   *out_values++ = -1;
+   *out_values++ = -1;
+
+   return 0;
+}
+
+static int edma_xbar_event_map(struct device *dev,
+  struct device_node *node,
+  struct edma_soc_info *pdata, int len)
+{
+   int ret = 0;
+   int i;
+   struct resource res;
+   void *xbar;
+   const s16 (*xbar_chans)[2];
+   u32 shift, offset, mux;
+
+   xbar_chans = devm_kzalloc(dev,
+ len/sizeof(s16) + 2*sizeof(s16),
+ GFP_KERNEL);
+   if (!xbar_chans)
+   return -ENOMEM;
+
+   ret = of_address_to_resource(node, 1, );
+   if (IS_ERR_VALUE(ret))
+   return -EIO;
+
+   xbar = devm_ioremap(dev, res.start, resource_size());
+   if (!xbar)
+   return -ENOMEM;
+
+   ret = edma_of_read_u32_to_s16_array(node,
+   "ti,edma-xbar-event-map",
+   (s16 *)xbar_chans,
+   len/sizeof(u32));
+   if (IS_ERR_VALUE(ret))
+   return -EIO;
+
+   for (i = 0; xbar_chans[i][0] != -1; i++) {
+   shift = (xbar_chans[i][1] % 4) * 8;
+   offset = xbar_chans[i][1] >> 2;
+   offset <<= 2;
+   mux = readl((void *)((u32)xbar + offset));
+   mux &= ~(0xff << shift);
+   mux |= xbar_chans[i][0] << shift;
+   writel(mux, (void *)((u32)xbar + offset));
+   }
+
+   pdata->xbar_chans = xbar_chans;
+
+   return 0;
+}
+
+static int edma_of_parse_dt(struct device *dev,
+   struct device_node *node,
+   struct edma_soc_info *pdata)
+{
+   int ret = 0;
+   u32 value;
+   struct property *prop;
+   size_t sz;
+   struct edma_rsv_info *rsv_info;
+   const s16 (*rsv_chans)[2], (*rsv_slots)[2];
+   const s8 (*queue_tc_map)[2], (*queue_priority_map)[2];
+
+   memset(pdata, 0, sizeof(struct edma_soc_info));
+
+   ret = of_property_read_u32(node, "dma-channels", );
+   if (ret < 0)
+   return ret;
+   pdata->n_channel = value;
+
+   ret = of_property_read_u32(node, "ti,edma-regions", );
+   if (ret < 0)
+   return ret;
+   pdata->n_region = value;
+
+   ret = of_property_read_u32(node, "ti,edma-slots", );
+   if (ret < 0)
+   return ret;
+   

[PATCH v4 03/14] ARM: edma: add AM33XX support to the private EDMA API

2013-01-10 Thread Matt Porter
Adds support for parsing the TI EDMA DT data into the required
EDMA private API platform data. Enables runtime PM support to
initialize the EDMA hwmod. Adds AM33XX EMDA crossbar event mux
support.

Signed-off-by: Matt Porter mpor...@ti.com
---
 arch/arm/common/edma.c |  314 ++--
 include/linux/platform_data/edma.h |1 +
 2 files changed, 306 insertions(+), 9 deletions(-)

diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index a3d189d..1951d63 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -24,6 +24,13 @@
 #include linux/platform_device.h
 #include linux/io.h
 #include linux/slab.h
+#include linux/edma.h
+#include linux/err.h
+#include linux/of_address.h
+#include linux/of_device.h
+#include linux/of_dma.h
+#include linux/of_irq.h
+#include linux/pm_runtime.h
 
 #include linux/platform_data/edma.h
 
@@ -723,6 +730,9 @@ EXPORT_SYMBOL(edma_free_channel);
  */
 int edma_alloc_slot(unsigned ctlr, int slot)
 {
+   if (!edma_cc[ctlr])
+   return -EINVAL;
+
if (slot = 0)
slot = EDMA_CHAN_SLOT(slot);
 
@@ -1366,31 +1376,291 @@ void edma_clear_event(unsigned channel)
 EXPORT_SYMBOL(edma_clear_event);
 
 /*---*/
+static int edma_of_read_u32_to_s8_array(const struct device_node *np,
+const char *propname, s8 *out_values,
+size_t sz)
+{
+   struct property *prop = of_find_property(np, propname, NULL);
+   const __be32 *val;
+
+   if (!prop)
+   return -EINVAL;
+   if (!prop-value)
+   return -ENODATA;
+   if ((sz * sizeof(u32))  prop-length)
+   return -EOVERFLOW;
+
+   val = prop-value;
+
+   while (sz--)
+   *out_values++ = (s8)(be32_to_cpup(val++)  0xff);
+
+   /* Terminate it */
+   *out_values++ = -1;
+   *out_values++ = -1;
+
+   return 0;
+}
+
+static int edma_of_read_u32_to_s16_array(const struct device_node *np,
+const char *propname, s16 *out_values,
+size_t sz)
+{
+   struct property *prop = of_find_property(np, propname, NULL);
+   const __be32 *val;
+
+   if (!prop)
+   return -EINVAL;
+   if (!prop-value)
+   return -ENODATA;
+   if ((sz * sizeof(u32))  prop-length)
+   return -EOVERFLOW;
+
+   val = prop-value;
+
+   while (sz--)
+   *out_values++ = (s16)(be32_to_cpup(val++)  0x);
+
+   /* Terminate it */
+   *out_values++ = -1;
+   *out_values++ = -1;
+
+   return 0;
+}
+
+static int edma_xbar_event_map(struct device *dev,
+  struct device_node *node,
+  struct edma_soc_info *pdata, int len)
+{
+   int ret = 0;
+   int i;
+   struct resource res;
+   void *xbar;
+   const s16 (*xbar_chans)[2];
+   u32 shift, offset, mux;
+
+   xbar_chans = devm_kzalloc(dev,
+ len/sizeof(s16) + 2*sizeof(s16),
+ GFP_KERNEL);
+   if (!xbar_chans)
+   return -ENOMEM;
+
+   ret = of_address_to_resource(node, 1, res);
+   if (IS_ERR_VALUE(ret))
+   return -EIO;
+
+   xbar = devm_ioremap(dev, res.start, resource_size(res));
+   if (!xbar)
+   return -ENOMEM;
+
+   ret = edma_of_read_u32_to_s16_array(node,
+   ti,edma-xbar-event-map,
+   (s16 *)xbar_chans,
+   len/sizeof(u32));
+   if (IS_ERR_VALUE(ret))
+   return -EIO;
+
+   for (i = 0; xbar_chans[i][0] != -1; i++) {
+   shift = (xbar_chans[i][1] % 4) * 8;
+   offset = xbar_chans[i][1]  2;
+   offset = 2;
+   mux = readl((void *)((u32)xbar + offset));
+   mux = ~(0xff  shift);
+   mux |= xbar_chans[i][0]  shift;
+   writel(mux, (void *)((u32)xbar + offset));
+   }
+
+   pdata-xbar_chans = xbar_chans;
+
+   return 0;
+}
+
+static int edma_of_parse_dt(struct device *dev,
+   struct device_node *node,
+   struct edma_soc_info *pdata)
+{
+   int ret = 0;
+   u32 value;
+   struct property *prop;
+   size_t sz;
+   struct edma_rsv_info *rsv_info;
+   const s16 (*rsv_chans)[2], (*rsv_slots)[2];
+   const s8 (*queue_tc_map)[2], (*queue_priority_map)[2];
+
+   memset(pdata, 0, sizeof(struct edma_soc_info));
+
+   ret = of_property_read_u32(node, dma-channels, value);
+   if (ret  0)
+   return ret;
+   pdata-n_channel = value;
+
+   ret = of_property_read_u32(node, ti,edma-regions, value);
+   if (ret  0)
+