dmaengine: imx-sdma: Add imx6sx platform support
authorZidan Wang <zidan.wang@freescale.com>
Thu, 23 Jul 2015 03:40:49 +0000 (11:40 +0800)
committerVinod Koul <vinod.koul@intel.com>
Wed, 19 Aug 2015 15:58:55 +0000 (21:28 +0530)
The new Solo X has more requirements for SDMA events. So it creates
a event mux to remap most of event numbers in GPR (General Purpose
Register). If we want to use SDMA support for those module who do
not get the even number as default, we need to configure GPR first.

Thus this patch adds this support of GPR event remapping configuration
to the SDMA driver.

Signed-off-by: Zidan Wang <zidan.wang@freescale.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/imx-sdma.c

index 34dece3af1925a5058234f76c2f8d15687ab7729..acf1e2f0c23c538334f7d8062928f4384465ea63 100644 (file)
@@ -42,6 +42,9 @@
 #include <asm/irq.h>
 #include <linux/platform_data/dma-imx-sdma.h>
 #include <linux/platform_data/dma-imx.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 
 #include "dmaengine.h"
 
@@ -1447,6 +1450,72 @@ err_firmware:
        release_firmware(fw);
 }
 
+#define EVENT_REMAP_CELLS 3
+
+static int __init sdma_event_remap(struct sdma_engine *sdma)
+{
+       struct device_node *np = sdma->dev->of_node;
+       struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0);
+       struct property *event_remap;
+       struct regmap *gpr;
+       char propname[] = "fsl,sdma-event-remap";
+       u32 reg, val, shift, num_map, i;
+       int ret = 0;
+
+       if (IS_ERR(np) || IS_ERR(gpr_np))
+               goto out;
+
+       event_remap = of_find_property(np, propname, NULL);
+       num_map = event_remap ? (event_remap->length / sizeof(u32)) : 0;
+       if (!num_map) {
+               dev_warn(sdma->dev, "no event needs to be remapped\n");
+               goto out;
+       } else if (num_map % EVENT_REMAP_CELLS) {
+               dev_err(sdma->dev, "the property %s must modulo %d\n",
+                               propname, EVENT_REMAP_CELLS);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       gpr = syscon_node_to_regmap(gpr_np);
+       if (IS_ERR(gpr)) {
+               dev_err(sdma->dev, "failed to get gpr regmap\n");
+               ret = PTR_ERR(gpr);
+               goto out;
+       }
+
+       for (i = 0; i < num_map; i += EVENT_REMAP_CELLS) {
+               ret = of_property_read_u32_index(np, propname, i, &reg);
+               if (ret) {
+                       dev_err(sdma->dev, "failed to read property %s index %d\n",
+                                       propname, i);
+                       goto out;
+               }
+
+               ret = of_property_read_u32_index(np, propname, i + 1, &shift);
+               if (ret) {
+                       dev_err(sdma->dev, "failed to read property %s index %d\n",
+                                       propname, i + 1);
+                       goto out;
+               }
+
+               ret = of_property_read_u32_index(np, propname, i + 2, &val);
+               if (ret) {
+                       dev_err(sdma->dev, "failed to read property %s index %d\n",
+                                       propname, i + 2);
+                       goto out;
+               }
+
+               regmap_update_bits(gpr, reg, BIT(shift), val << shift);
+       }
+
+out:
+       if (!IS_ERR(gpr_np))
+               of_node_put(gpr_np);
+
+       return ret;
+}
+
 static int sdma_get_firmware(struct sdma_engine *sdma,
                const char *fw_name)
 {
@@ -1671,6 +1740,10 @@ static int sdma_probe(struct platform_device *pdev)
        if (ret)
                goto err_init;
 
+       ret = sdma_event_remap(sdma);
+       if (ret)
+               goto err_init;
+
        if (sdma->drvdata->script_addrs)
                sdma_add_scripts(sdma, sdma->drvdata->script_addrs);
        if (pdata && pdata->script_addrs)