diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/coherency-fabric.txt | 9 | ||||
-rw-r--r-- | arch/arm/boot/dts/armada-370-xp.dtsi | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/addr-map.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/coherency.c | 73 |
4 files changed, 85 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt index 2bfbf67dd77e..17d8cd107559 100644 --- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt +++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt | |||
@@ -5,12 +5,17 @@ Available on Marvell SOCs: Armada 370 and Armada XP | |||
5 | Required properties: | 5 | Required properties: |
6 | 6 | ||
7 | - compatible: "marvell,coherency-fabric" | 7 | - compatible: "marvell,coherency-fabric" |
8 | - reg: Should contain,coherency fabric registers location and length. | 8 | |
9 | - reg: Should contain coherency fabric registers location and | ||
10 | length. First pair for the coherency fabric registers, second pair | ||
11 | for the per-CPU fabric registers registers. | ||
9 | 12 | ||
10 | Example: | 13 | Example: |
11 | 14 | ||
12 | coherency-fabric@d0020200 { | 15 | coherency-fabric@d0020200 { |
13 | compatible = "marvell,coherency-fabric"; | 16 | compatible = "marvell,coherency-fabric"; |
14 | reg = <0xd0020200 0xb0>; | 17 | reg = <0xd0020200 0xb0>, |
18 | <0xd0021810 0x1c>; | ||
19 | |||
15 | }; | 20 | }; |
16 | 21 | ||
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index b0d075b50f29..98a6b26a7dc8 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi | |||
@@ -38,7 +38,8 @@ | |||
38 | 38 | ||
39 | coherency-fabric@d0020200 { | 39 | coherency-fabric@d0020200 { |
40 | compatible = "marvell,coherency-fabric"; | 40 | compatible = "marvell,coherency-fabric"; |
41 | reg = <0xd0020200 0xb0>; | 41 | reg = <0xd0020200 0xb0>, |
42 | <0xd0021810 0x1c>; | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | soc { | 45 | soc { |
diff --git a/arch/arm/mach-mvebu/addr-map.c b/arch/arm/mach-mvebu/addr-map.c index fe454a4430be..595f6b722a8f 100644 --- a/arch/arm/mach-mvebu/addr-map.c +++ b/arch/arm/mach-mvebu/addr-map.c | |||
@@ -108,6 +108,9 @@ static int __init armada_setup_cpu_mbus(void) | |||
108 | 108 | ||
109 | addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; | 109 | addr_map_cfg.bridge_virt_base = mbus_unit_addr_decoding_base; |
110 | 110 | ||
111 | if (of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric")) | ||
112 | addr_map_cfg.hw_io_coherency = 1; | ||
113 | |||
111 | /* | 114 | /* |
112 | * Disable, clear and configure windows. | 115 | * Disable, clear and configure windows. |
113 | */ | 116 | */ |
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 596ee66a9cc4..8278960066c3 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/smp.h> | 24 | #include <linux/smp.h> |
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/platform_device.h> | ||
25 | #include <asm/smp_plat.h> | 27 | #include <asm/smp_plat.h> |
26 | #include "armada-370-xp.h" | 28 | #include "armada-370-xp.h" |
27 | 29 | ||
@@ -33,10 +35,13 @@ | |||
33 | * value matching its virtual mapping | 35 | * value matching its virtual mapping |
34 | */ | 36 | */ |
35 | static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; | 37 | static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; |
38 | static void __iomem *coherency_cpu_base; | ||
36 | 39 | ||
37 | /* Coherency fabric registers */ | 40 | /* Coherency fabric registers */ |
38 | #define COHERENCY_FABRIC_CFG_OFFSET 0x4 | 41 | #define COHERENCY_FABRIC_CFG_OFFSET 0x4 |
39 | 42 | ||
43 | #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 | ||
44 | |||
40 | static struct of_device_id of_coherency_table[] = { | 45 | static struct of_device_id of_coherency_table[] = { |
41 | {.compatible = "marvell,coherency-fabric"}, | 46 | {.compatible = "marvell,coherency-fabric"}, |
42 | { /* end of list */ }, | 47 | { /* end of list */ }, |
@@ -68,6 +73,70 @@ int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id) | |||
68 | return ll_set_cpu_coherent(coherency_base, hw_cpu_id); | 73 | return ll_set_cpu_coherent(coherency_base, hw_cpu_id); |
69 | } | 74 | } |
70 | 75 | ||
76 | static inline void mvebu_hwcc_sync_io_barrier(void) | ||
77 | { | ||
78 | writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); | ||
79 | while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); | ||
80 | } | ||
81 | |||
82 | static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page, | ||
83 | unsigned long offset, size_t size, | ||
84 | enum dma_data_direction dir, | ||
85 | struct dma_attrs *attrs) | ||
86 | { | ||
87 | if (dir != DMA_TO_DEVICE) | ||
88 | mvebu_hwcc_sync_io_barrier(); | ||
89 | return pfn_to_dma(dev, page_to_pfn(page)) + offset; | ||
90 | } | ||
91 | |||
92 | |||
93 | static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, | ||
94 | size_t size, enum dma_data_direction dir, | ||
95 | struct dma_attrs *attrs) | ||
96 | { | ||
97 | if (dir != DMA_TO_DEVICE) | ||
98 | mvebu_hwcc_sync_io_barrier(); | ||
99 | } | ||
100 | |||
101 | static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle, | ||
102 | size_t size, enum dma_data_direction dir) | ||
103 | { | ||
104 | if (dir != DMA_TO_DEVICE) | ||
105 | mvebu_hwcc_sync_io_barrier(); | ||
106 | } | ||
107 | |||
108 | static struct dma_map_ops mvebu_hwcc_dma_ops = { | ||
109 | .alloc = arm_dma_alloc, | ||
110 | .free = arm_dma_free, | ||
111 | .mmap = arm_dma_mmap, | ||
112 | .map_page = mvebu_hwcc_dma_map_page, | ||
113 | .unmap_page = mvebu_hwcc_dma_unmap_page, | ||
114 | .get_sgtable = arm_dma_get_sgtable, | ||
115 | .map_sg = arm_dma_map_sg, | ||
116 | .unmap_sg = arm_dma_unmap_sg, | ||
117 | .sync_single_for_cpu = mvebu_hwcc_dma_sync, | ||
118 | .sync_single_for_device = mvebu_hwcc_dma_sync, | ||
119 | .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, | ||
120 | .sync_sg_for_device = arm_dma_sync_sg_for_device, | ||
121 | .set_dma_mask = arm_dma_set_mask, | ||
122 | }; | ||
123 | |||
124 | static int mvebu_hwcc_platform_notifier(struct notifier_block *nb, | ||
125 | unsigned long event, void *__dev) | ||
126 | { | ||
127 | struct device *dev = __dev; | ||
128 | |||
129 | if (event != BUS_NOTIFY_ADD_DEVICE) | ||
130 | return NOTIFY_DONE; | ||
131 | set_dma_ops(dev, &mvebu_hwcc_dma_ops); | ||
132 | |||
133 | return NOTIFY_OK; | ||
134 | } | ||
135 | |||
136 | static struct notifier_block mvebu_hwcc_platform_nb = { | ||
137 | .notifier_call = mvebu_hwcc_platform_notifier, | ||
138 | }; | ||
139 | |||
71 | int __init coherency_init(void) | 140 | int __init coherency_init(void) |
72 | { | 141 | { |
73 | struct device_node *np; | 142 | struct device_node *np; |
@@ -76,6 +145,10 @@ int __init coherency_init(void) | |||
76 | if (np) { | 145 | if (np) { |
77 | pr_info("Initializing Coherency fabric\n"); | 146 | pr_info("Initializing Coherency fabric\n"); |
78 | coherency_base = of_iomap(np, 0); | 147 | coherency_base = of_iomap(np, 0); |
148 | coherency_cpu_base = of_iomap(np, 1); | ||
149 | set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); | ||
150 | bus_register_notifier(&platform_bus_type, | ||
151 | &mvebu_hwcc_platform_nb); | ||
79 | } | 152 | } |
80 | 153 | ||
81 | return 0; | 154 | return 0; |