aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2012-10-12 13:20:36 -0400
committerGregory CLEMENT <gregory.clement@free-electrons.com>2012-11-21 11:07:49 -0500
commite60304f8cb7bb545e79fe62d9b9762460c254ec2 (patch)
tree9f28a557c71cf6128c7cf480b8a4a59f0c0bb6b8 /arch/arm/mach-mvebu
parent722202e10b488c14e93c428743a0e476093949e3 (diff)
arm: mvebu: Add hardware I/O Coherency support
Armada 370 and XP come with an unit called coherency fabric. This unit allows to use the Armada 370/XP as a nearly coherent architecture. The coherency mechanism uses snoop filters to ensure the coherency between caches, DRAM and devices. This mechanism needs a synchronization barrier which guarantees that all the memory writes initiated by the devices have reached their target and do not reside in intermediate write buffers. That's why the architecture is not totally coherent and we need to provide our own functions for some DMA operations. Beside the use of the coherency fabric, the device units will have to set the attribute flag of the decoding address window to select the accurate coherency process for the memory transaction. This is done each device driver programs the DRAM address windows. The value of the attribute set by the driver is retrieved through the orion_addr_map_cfg struct filled during the early initialization of the platform. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Reviewed-by: Yehuda Yitschak <yehuday@marvell.com> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/addr-map.c3
-rw-r--r--arch/arm/mach-mvebu/coherency.c73
2 files changed, 76 insertions, 0 deletions
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 */
35static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200; 37static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
38static 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
40static struct of_device_id of_coherency_table[] = { 45static 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
76static 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
82static 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
93static 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
101static 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
108static 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
124static 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
136static struct notifier_block mvebu_hwcc_platform_nb = {
137 .notifier_call = mvebu_hwcc_platform_notifier,
138};
139
71int __init coherency_init(void) 140int __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;