ARM: highbank: add coherent DMA setup
authorRob Herring <rob.herring@calxeda.com>
Tue, 21 Aug 2012 10:31:06 +0000 (12:31 +0200)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Tue, 2 Oct 2012 06:58:07 +0000 (08:58 +0200)
Some highbank DMA masters can support coherent (ACP) or non-coherent DMA.
This sets up dma_map_ops for masters which are configured for coherent DMA.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Documentation/devicetree/bindings/ata/ahci-platform.txt
Documentation/devicetree/bindings/dma/arm-pl330.txt
Documentation/devicetree/bindings/net/calxeda-xgmac.txt
arch/arm/boot/dts/highbank.dts
arch/arm/mach-highbank/highbank.c

index 8bb8a76d42e8c1b9cad1de552d8639045a204992..6c1ad01d27e8369f4716dc2f245ef49d5c8be42d 100644 (file)
@@ -8,6 +8,9 @@ Required properties:
 - interrupts        : <interrupt mapping for SATA IRQ>
 - reg               : <registers mapping>
 
+Optional properties:
+- dma-coherent      : Present if dma operations are coherent
+
 Example:
         sata@ffe08000 {
                compatible = "calxeda,hb-ahci";
index a4cd273b2a679d0d5c4952d6a576149658570cdd..36e27d54260b37ddde16669c0294474026084b7b 100644 (file)
@@ -9,6 +9,9 @@ Required properties:
     region.
   - interrupts: interrupt number to the cpu.
 
+Optional properties:
+- dma-coherent      : Present if dma operations are coherent
+
 Example:
 
        pdma0: pdma@12680000 {
index 411727a3f82d6add5a7c1ca18aa01dbd30fe0ff5..c8ae996bd8f2e4403cd8c1bd7ed7507d9379f7d7 100644 (file)
@@ -6,6 +6,9 @@ Required properties:
 - interrupts : Should contain 3 xgmac interrupts. The 1st is main interrupt.
   The 2nd is pwr mgt interrupt. The 3rd is low power state interrupt.
 
+Optional properties:
+- dma-coherent      : Present if dma operations are coherent
+
 Example:
 
 ethernet@fff50000 {
index 9fecf1ae777bac14b2770c0cf09dd601e85b73b8..7414577c177fce867038a717b29cb3c3ea3545fe 100644 (file)
                        compatible = "calxeda,hb-ahci";
                        reg = <0xffe08000 0x10000>;
                        interrupts = <0 83 4>;
+                       dma-coherent;
                };
 
                sdhci@ffe0e000 {
index d75b0a78d88ab94a85512cc3de2116ea3a710743..93617d61f4b1fbd44043257fcdf8474577a34b97 100644 (file)
@@ -15,6 +15,7 @@
  */
 #include <linux/clk.h>
 #include <linux/clkdev.h>
+#include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
@@ -23,6 +24,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
 #include <linux/smp.h>
+#include <linux/amba/bus.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp_plat.h>
@@ -149,10 +151,60 @@ static void highbank_power_off(void)
                cpu_do_idle();
 }
 
+static int highbank_platform_notifier(struct notifier_block *nb,
+                                 unsigned long event, void *__dev)
+{
+       struct resource *res;
+       int reg = -1;
+       struct device *dev = __dev;
+
+       if (event != BUS_NOTIFY_ADD_DEVICE)
+               return NOTIFY_DONE;
+
+       if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci"))
+               reg = 0xc;
+       else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci"))
+               reg = 0x18;
+       else if (of_device_is_compatible(dev->of_node, "arm,pl330"))
+               reg = 0x20;
+       else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) {
+               res = platform_get_resource(to_platform_device(dev),
+                                           IORESOURCE_MEM, 0);
+               if (res) {
+                       if (res->start == 0xfff50000)
+                               reg = 0;
+                       else if (res->start == 0xfff51000)
+                               reg = 4;
+               }
+       }
+
+       if (reg < 0)
+               return NOTIFY_DONE;
+
+       if (of_property_read_bool(dev->of_node, "dma-coherent")) {
+               writel(0xff31, sregs_base + reg);
+               set_dma_ops(dev, &arm_coherent_dma_ops);
+       } else
+               writel(0, sregs_base + reg);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block highbank_amba_nb = {
+       .notifier_call = highbank_platform_notifier,
+};
+
+static struct notifier_block highbank_platform_nb = {
+       .notifier_call = highbank_platform_notifier,
+};
+
 static void __init highbank_init(void)
 {
        pm_power_off = highbank_power_off;
 
+       bus_register_notifier(&platform_bus_type, &highbank_platform_nb);
+       bus_register_notifier(&amba_bustype, &highbank_amba_nb);
+
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }