1009f1315SGregory CLEMENT /* 2009f1315SGregory CLEMENT * Coherency fabric (Aurora) support for Armada 370 and XP platforms. 3009f1315SGregory CLEMENT * 4009f1315SGregory CLEMENT * Copyright (C) 2012 Marvell 5009f1315SGregory CLEMENT * 6009f1315SGregory CLEMENT * Yehuda Yitschak <yehuday@marvell.com> 7009f1315SGregory CLEMENT * Gregory Clement <gregory.clement@free-electrons.com> 8009f1315SGregory CLEMENT * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 9009f1315SGregory CLEMENT * 10009f1315SGregory CLEMENT * This file is licensed under the terms of the GNU General Public 11009f1315SGregory CLEMENT * License version 2. This program is licensed "as is" without any 12009f1315SGregory CLEMENT * warranty of any kind, whether express or implied. 13009f1315SGregory CLEMENT * 14009f1315SGregory CLEMENT * The Armada 370 and Armada XP SOCs have a coherency fabric which is 15009f1315SGregory CLEMENT * responsible for ensuring hardware coherency between all CPUs and between 16009f1315SGregory CLEMENT * CPUs and I/O masters. This file initializes the coherency fabric and 17009f1315SGregory CLEMENT * supplies basic routines for configuring and controlling hardware coherency 18009f1315SGregory CLEMENT */ 19009f1315SGregory CLEMENT 205ab5afd8SThomas Petazzoni #define pr_fmt(fmt) "mvebu-coherency: " fmt 215ab5afd8SThomas Petazzoni 22009f1315SGregory CLEMENT #include <linux/kernel.h> 23009f1315SGregory CLEMENT #include <linux/init.h> 24009f1315SGregory CLEMENT #include <linux/of_address.h> 25009f1315SGregory CLEMENT #include <linux/io.h> 26009f1315SGregory CLEMENT #include <linux/smp.h> 27e60304f8SGregory CLEMENT #include <linux/dma-mapping.h> 28e60304f8SGregory CLEMENT #include <linux/platform_device.h> 295ab5afd8SThomas Petazzoni #include <linux/slab.h> 305ab5afd8SThomas Petazzoni #include <linux/mbus.h> 315ab5afd8SThomas Petazzoni #include <linux/clk.h> 32009f1315SGregory CLEMENT #include <asm/smp_plat.h> 33580ff0eeSThomas Petazzoni #include <asm/cacheflush.h> 34009f1315SGregory CLEMENT #include "armada-370-xp.h" 35b12634e3SJisheng Zhang #include "coherency.h" 36009f1315SGregory CLEMENT 378bd26e3aSPaul Gortmaker unsigned long coherency_phys_base; 38865e0527SThomas Petazzoni static void __iomem *coherency_base; 39e60304f8SGregory CLEMENT static void __iomem *coherency_cpu_base; 40009f1315SGregory CLEMENT 41009f1315SGregory CLEMENT /* Coherency fabric registers */ 42009f1315SGregory CLEMENT #define COHERENCY_FABRIC_CFG_OFFSET 0x4 43009f1315SGregory CLEMENT 44e60304f8SGregory CLEMENT #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 45e60304f8SGregory CLEMENT 46924d38f4SThomas Petazzoni enum { 47501f928eSThomas Petazzoni COHERENCY_FABRIC_TYPE_NONE, 48924d38f4SThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_370_XP, 4977fa4b9aSThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_375, 50d0de9323SThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_380, 51924d38f4SThomas Petazzoni }; 52924d38f4SThomas Petazzoni 53009f1315SGregory CLEMENT static struct of_device_id of_coherency_table[] = { 54924d38f4SThomas Petazzoni {.compatible = "marvell,coherency-fabric", 55924d38f4SThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_370_XP }, 5677fa4b9aSThomas Petazzoni {.compatible = "marvell,armada-375-coherency-fabric", 5777fa4b9aSThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_375 }, 58d0de9323SThomas Petazzoni {.compatible = "marvell,armada-380-coherency-fabric", 59d0de9323SThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_380 }, 60009f1315SGregory CLEMENT { /* end of list */ }, 61009f1315SGregory CLEMENT }; 62009f1315SGregory CLEMENT 63009f1315SGregory CLEMENT /* Function defined in coherency_ll.S */ 64009f1315SGregory CLEMENT int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id); 65009f1315SGregory CLEMENT 66009f1315SGregory CLEMENT int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id) 67009f1315SGregory CLEMENT { 68009f1315SGregory CLEMENT if (!coherency_base) { 69009f1315SGregory CLEMENT pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id); 70009f1315SGregory CLEMENT pr_warn("Coherency fabric is not initialized\n"); 71009f1315SGregory CLEMENT return 1; 72009f1315SGregory CLEMENT } 73009f1315SGregory CLEMENT 74009f1315SGregory CLEMENT return ll_set_cpu_coherent(coherency_base, hw_cpu_id); 75009f1315SGregory CLEMENT } 76009f1315SGregory CLEMENT 775ab5afd8SThomas Petazzoni /* 785ab5afd8SThomas Petazzoni * The below code implements the I/O coherency workaround on Armada 795ab5afd8SThomas Petazzoni * 375. This workaround consists in using the two channels of the 805ab5afd8SThomas Petazzoni * first XOR engine to trigger a XOR transaction that serves as the 815ab5afd8SThomas Petazzoni * I/O coherency barrier. 825ab5afd8SThomas Petazzoni */ 835ab5afd8SThomas Petazzoni 845ab5afd8SThomas Petazzoni static void __iomem *xor_base, *xor_high_base; 855ab5afd8SThomas Petazzoni static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; 865ab5afd8SThomas Petazzoni static void *coherency_wa_buf[CONFIG_NR_CPUS]; 875ab5afd8SThomas Petazzoni static bool coherency_wa_enabled; 885ab5afd8SThomas Petazzoni 895ab5afd8SThomas Petazzoni #define XOR_CONFIG(chan) (0x10 + (chan * 4)) 905ab5afd8SThomas Petazzoni #define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) 915ab5afd8SThomas Petazzoni #define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) 925ab5afd8SThomas Petazzoni #define WINDOW_BASE(w) (0x250 + ((w) << 2)) 935ab5afd8SThomas Petazzoni #define WINDOW_SIZE(w) (0x270 + ((w) << 2)) 945ab5afd8SThomas Petazzoni #define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) 955ab5afd8SThomas Petazzoni #define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) 965ab5afd8SThomas Petazzoni #define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) 975ab5afd8SThomas Petazzoni #define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) 985ab5afd8SThomas Petazzoni #define XOR_INIT_VALUE_LOW 0x2E0 995ab5afd8SThomas Petazzoni #define XOR_INIT_VALUE_HIGH 0x2E4 1005ab5afd8SThomas Petazzoni 1015ab5afd8SThomas Petazzoni static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) 1025ab5afd8SThomas Petazzoni { 1035ab5afd8SThomas Petazzoni int idx = smp_processor_id(); 1045ab5afd8SThomas Petazzoni 1055ab5afd8SThomas Petazzoni /* Write '1' to the first word of the buffer */ 1065ab5afd8SThomas Petazzoni writel(0x1, coherency_wa_buf[idx]); 1075ab5afd8SThomas Petazzoni 1085ab5afd8SThomas Petazzoni /* Wait until the engine is idle */ 1095ab5afd8SThomas Petazzoni while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) 1105ab5afd8SThomas Petazzoni ; 1115ab5afd8SThomas Petazzoni 1125ab5afd8SThomas Petazzoni dmb(); 1135ab5afd8SThomas Petazzoni 1145ab5afd8SThomas Petazzoni /* Trigger channel */ 1155ab5afd8SThomas Petazzoni writel(0x1, xor_base + XOR_ACTIVATION(idx)); 1165ab5afd8SThomas Petazzoni 1175ab5afd8SThomas Petazzoni /* Poll the data until it is cleared by the XOR transaction */ 1185ab5afd8SThomas Petazzoni while (readl(coherency_wa_buf[idx])) 1195ab5afd8SThomas Petazzoni ; 1205ab5afd8SThomas Petazzoni } 1215ab5afd8SThomas Petazzoni 1225ab5afd8SThomas Petazzoni static void __init armada_375_coherency_init_wa(void) 1235ab5afd8SThomas Petazzoni { 1245ab5afd8SThomas Petazzoni const struct mbus_dram_target_info *dram; 1255ab5afd8SThomas Petazzoni struct device_node *xor_node; 1265ab5afd8SThomas Petazzoni struct property *xor_status; 1275ab5afd8SThomas Petazzoni struct clk *xor_clk; 1285ab5afd8SThomas Petazzoni u32 win_enable = 0; 1295ab5afd8SThomas Petazzoni int i; 1305ab5afd8SThomas Petazzoni 1315ab5afd8SThomas Petazzoni pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); 1325ab5afd8SThomas Petazzoni 1335ab5afd8SThomas Petazzoni /* 1345ab5afd8SThomas Petazzoni * Since the workaround uses one XOR engine, we grab a 1355ab5afd8SThomas Petazzoni * reference to its Device Tree node first. 1365ab5afd8SThomas Petazzoni */ 1375ab5afd8SThomas Petazzoni xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); 1385ab5afd8SThomas Petazzoni BUG_ON(!xor_node); 1395ab5afd8SThomas Petazzoni 1405ab5afd8SThomas Petazzoni /* 1415ab5afd8SThomas Petazzoni * Then we mark it as disabled so that the real XOR driver 1425ab5afd8SThomas Petazzoni * will not use it. 1435ab5afd8SThomas Petazzoni */ 1445ab5afd8SThomas Petazzoni xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); 1455ab5afd8SThomas Petazzoni BUG_ON(!xor_status); 1465ab5afd8SThomas Petazzoni 1475ab5afd8SThomas Petazzoni xor_status->value = kstrdup("disabled", GFP_KERNEL); 1485ab5afd8SThomas Petazzoni BUG_ON(!xor_status->value); 1495ab5afd8SThomas Petazzoni 1505ab5afd8SThomas Petazzoni xor_status->length = 8; 1515ab5afd8SThomas Petazzoni xor_status->name = kstrdup("status", GFP_KERNEL); 1525ab5afd8SThomas Petazzoni BUG_ON(!xor_status->name); 1535ab5afd8SThomas Petazzoni 1545ab5afd8SThomas Petazzoni of_update_property(xor_node, xor_status); 1555ab5afd8SThomas Petazzoni 1565ab5afd8SThomas Petazzoni /* 1575ab5afd8SThomas Petazzoni * And we remap the registers, get the clock, and do the 1585ab5afd8SThomas Petazzoni * initial configuration of the XOR engine. 1595ab5afd8SThomas Petazzoni */ 1605ab5afd8SThomas Petazzoni xor_base = of_iomap(xor_node, 0); 1615ab5afd8SThomas Petazzoni xor_high_base = of_iomap(xor_node, 1); 1625ab5afd8SThomas Petazzoni 1635ab5afd8SThomas Petazzoni xor_clk = of_clk_get_by_name(xor_node, NULL); 1645ab5afd8SThomas Petazzoni BUG_ON(!xor_clk); 1655ab5afd8SThomas Petazzoni 1665ab5afd8SThomas Petazzoni clk_prepare_enable(xor_clk); 1675ab5afd8SThomas Petazzoni 1685ab5afd8SThomas Petazzoni dram = mv_mbus_dram_info(); 1695ab5afd8SThomas Petazzoni 1705ab5afd8SThomas Petazzoni for (i = 0; i < 8; i++) { 1715ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_BASE(i)); 1725ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_SIZE(i)); 1735ab5afd8SThomas Petazzoni if (i < 4) 1745ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_REMAP_HIGH(i)); 1755ab5afd8SThomas Petazzoni } 1765ab5afd8SThomas Petazzoni 1775ab5afd8SThomas Petazzoni for (i = 0; i < dram->num_cs; i++) { 1785ab5afd8SThomas Petazzoni const struct mbus_dram_window *cs = dram->cs + i; 1795ab5afd8SThomas Petazzoni writel((cs->base & 0xffff0000) | 1805ab5afd8SThomas Petazzoni (cs->mbus_attr << 8) | 1815ab5afd8SThomas Petazzoni dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); 1825ab5afd8SThomas Petazzoni writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); 1835ab5afd8SThomas Petazzoni 1845ab5afd8SThomas Petazzoni win_enable |= (1 << i); 1855ab5afd8SThomas Petazzoni win_enable |= 3 << (16 + (2 * i)); 1865ab5afd8SThomas Petazzoni } 1875ab5afd8SThomas Petazzoni 1885ab5afd8SThomas Petazzoni writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); 1895ab5afd8SThomas Petazzoni writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); 1905ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); 1915ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); 1925ab5afd8SThomas Petazzoni 1935ab5afd8SThomas Petazzoni for (i = 0; i < CONFIG_NR_CPUS; i++) { 1945ab5afd8SThomas Petazzoni coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); 1955ab5afd8SThomas Petazzoni BUG_ON(!coherency_wa_buf[i]); 1965ab5afd8SThomas Petazzoni 1975ab5afd8SThomas Petazzoni /* 1985ab5afd8SThomas Petazzoni * We can't use the DMA mapping API, since we don't 1995ab5afd8SThomas Petazzoni * have a valid 'struct device' pointer 2005ab5afd8SThomas Petazzoni */ 2015ab5afd8SThomas Petazzoni coherency_wa_buf_phys[i] = 2025ab5afd8SThomas Petazzoni virt_to_phys(coherency_wa_buf[i]); 2035ab5afd8SThomas Petazzoni BUG_ON(!coherency_wa_buf_phys[i]); 2045ab5afd8SThomas Petazzoni 2055ab5afd8SThomas Petazzoni /* 2065ab5afd8SThomas Petazzoni * Configure the XOR engine for memset operation, with 2075ab5afd8SThomas Petazzoni * a 128 bytes block size 2085ab5afd8SThomas Petazzoni */ 2095ab5afd8SThomas Petazzoni writel(0x444, xor_base + XOR_CONFIG(i)); 2105ab5afd8SThomas Petazzoni writel(128, xor_base + XOR_BLOCK_SIZE(i)); 2115ab5afd8SThomas Petazzoni writel(coherency_wa_buf_phys[i], 2125ab5afd8SThomas Petazzoni xor_base + XOR_DEST_POINTER(i)); 2135ab5afd8SThomas Petazzoni } 2145ab5afd8SThomas Petazzoni 2155ab5afd8SThomas Petazzoni writel(0x0, xor_base + XOR_INIT_VALUE_LOW); 2165ab5afd8SThomas Petazzoni writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); 2175ab5afd8SThomas Petazzoni 2185ab5afd8SThomas Petazzoni coherency_wa_enabled = true; 2195ab5afd8SThomas Petazzoni } 2205ab5afd8SThomas Petazzoni 221e60304f8SGregory CLEMENT static inline void mvebu_hwcc_sync_io_barrier(void) 222e60304f8SGregory CLEMENT { 2235ab5afd8SThomas Petazzoni if (coherency_wa_enabled) { 2245ab5afd8SThomas Petazzoni mvebu_hwcc_armada375_sync_io_barrier_wa(); 2255ab5afd8SThomas Petazzoni return; 2265ab5afd8SThomas Petazzoni } 2275ab5afd8SThomas Petazzoni 228e60304f8SGregory CLEMENT writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); 229e60304f8SGregory CLEMENT while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); 230e60304f8SGregory CLEMENT } 231e60304f8SGregory CLEMENT 232e60304f8SGregory CLEMENT static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page, 233e60304f8SGregory CLEMENT unsigned long offset, size_t size, 234e60304f8SGregory CLEMENT enum dma_data_direction dir, 235e60304f8SGregory CLEMENT struct dma_attrs *attrs) 236e60304f8SGregory CLEMENT { 237e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 238e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 239e60304f8SGregory CLEMENT return pfn_to_dma(dev, page_to_pfn(page)) + offset; 240e60304f8SGregory CLEMENT } 241e60304f8SGregory CLEMENT 242e60304f8SGregory CLEMENT 243e60304f8SGregory CLEMENT static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, 244e60304f8SGregory CLEMENT size_t size, enum dma_data_direction dir, 245e60304f8SGregory CLEMENT struct dma_attrs *attrs) 246e60304f8SGregory CLEMENT { 247e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 248e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 249e60304f8SGregory CLEMENT } 250e60304f8SGregory CLEMENT 251e60304f8SGregory CLEMENT static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle, 252e60304f8SGregory CLEMENT size_t size, enum dma_data_direction dir) 253e60304f8SGregory CLEMENT { 254e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 255e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 256e60304f8SGregory CLEMENT } 257e60304f8SGregory CLEMENT 258e60304f8SGregory CLEMENT static struct dma_map_ops mvebu_hwcc_dma_ops = { 259e60304f8SGregory CLEMENT .alloc = arm_dma_alloc, 260e60304f8SGregory CLEMENT .free = arm_dma_free, 261e60304f8SGregory CLEMENT .mmap = arm_dma_mmap, 262e60304f8SGregory CLEMENT .map_page = mvebu_hwcc_dma_map_page, 263e60304f8SGregory CLEMENT .unmap_page = mvebu_hwcc_dma_unmap_page, 264e60304f8SGregory CLEMENT .get_sgtable = arm_dma_get_sgtable, 265e60304f8SGregory CLEMENT .map_sg = arm_dma_map_sg, 266e60304f8SGregory CLEMENT .unmap_sg = arm_dma_unmap_sg, 267e60304f8SGregory CLEMENT .sync_single_for_cpu = mvebu_hwcc_dma_sync, 268e60304f8SGregory CLEMENT .sync_single_for_device = mvebu_hwcc_dma_sync, 269e60304f8SGregory CLEMENT .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, 270e60304f8SGregory CLEMENT .sync_sg_for_device = arm_dma_sync_sg_for_device, 271e60304f8SGregory CLEMENT .set_dma_mask = arm_dma_set_mask, 272e60304f8SGregory CLEMENT }; 273e60304f8SGregory CLEMENT 274e60304f8SGregory CLEMENT static int mvebu_hwcc_platform_notifier(struct notifier_block *nb, 275e60304f8SGregory CLEMENT unsigned long event, void *__dev) 276e60304f8SGregory CLEMENT { 277e60304f8SGregory CLEMENT struct device *dev = __dev; 278e60304f8SGregory CLEMENT 279e60304f8SGregory CLEMENT if (event != BUS_NOTIFY_ADD_DEVICE) 280e60304f8SGregory CLEMENT return NOTIFY_DONE; 281e60304f8SGregory CLEMENT set_dma_ops(dev, &mvebu_hwcc_dma_ops); 282e60304f8SGregory CLEMENT 283e60304f8SGregory CLEMENT return NOTIFY_OK; 284e60304f8SGregory CLEMENT } 285e60304f8SGregory CLEMENT 286e60304f8SGregory CLEMENT static struct notifier_block mvebu_hwcc_platform_nb = { 287e60304f8SGregory CLEMENT .notifier_call = mvebu_hwcc_platform_notifier, 288e60304f8SGregory CLEMENT }; 289e60304f8SGregory CLEMENT 290924d38f4SThomas Petazzoni static void __init armada_370_coherency_init(struct device_node *np) 291009f1315SGregory CLEMENT { 292580ff0eeSThomas Petazzoni struct resource res; 293924d38f4SThomas Petazzoni 294580ff0eeSThomas Petazzoni of_address_to_resource(np, 0, &res); 295580ff0eeSThomas Petazzoni coherency_phys_base = res.start; 296580ff0eeSThomas Petazzoni /* 297580ff0eeSThomas Petazzoni * Ensure secondary CPUs will see the updated value, 298580ff0eeSThomas Petazzoni * which they read before they join the coherency 299580ff0eeSThomas Petazzoni * fabric, and therefore before they are coherent with 300580ff0eeSThomas Petazzoni * the boot CPU cache. 301580ff0eeSThomas Petazzoni */ 302580ff0eeSThomas Petazzoni sync_cache_w(&coherency_phys_base); 303009f1315SGregory CLEMENT coherency_base = of_iomap(np, 0); 304e60304f8SGregory CLEMENT coherency_cpu_base = of_iomap(np, 1); 305e60304f8SGregory CLEMENT set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); 306924d38f4SThomas Petazzoni } 307924d38f4SThomas Petazzoni 308d0de9323SThomas Petazzoni static void __init armada_375_380_coherency_init(struct device_node *np) 30977fa4b9aSThomas Petazzoni { 31077fa4b9aSThomas Petazzoni coherency_cpu_base = of_iomap(np, 0); 31177fa4b9aSThomas Petazzoni } 31277fa4b9aSThomas Petazzoni 313501f928eSThomas Petazzoni static int coherency_type(void) 314924d38f4SThomas Petazzoni { 315924d38f4SThomas Petazzoni struct device_node *np; 3165fbba080SThomas Petazzoni const struct of_device_id *match; 317924d38f4SThomas Petazzoni 3185fbba080SThomas Petazzoni np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); 319924d38f4SThomas Petazzoni if (np) { 3205fbba080SThomas Petazzoni int type = (int) match->data; 321924d38f4SThomas Petazzoni 322501f928eSThomas Petazzoni /* Armada 370/XP coherency works in both UP and SMP */ 323924d38f4SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) 324501f928eSThomas Petazzoni return type; 325924d38f4SThomas Petazzoni 32677fa4b9aSThomas Petazzoni /* Armada 375 coherency works only on SMP */ 32777fa4b9aSThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) 32877fa4b9aSThomas Petazzoni return type; 32977fa4b9aSThomas Petazzoni 330d0de9323SThomas Petazzoni /* Armada 380 coherency works only on SMP */ 331d0de9323SThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) 332d0de9323SThomas Petazzoni return type; 333d0de9323SThomas Petazzoni 334abe511acSJisheng Zhang of_node_put(np); 335009f1315SGregory CLEMENT } 336009f1315SGregory CLEMENT 337501f928eSThomas Petazzoni return COHERENCY_FABRIC_TYPE_NONE; 338501f928eSThomas Petazzoni } 339501f928eSThomas Petazzoni 340501f928eSThomas Petazzoni int coherency_available(void) 341501f928eSThomas Petazzoni { 342501f928eSThomas Petazzoni return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; 343501f928eSThomas Petazzoni } 344501f928eSThomas Petazzoni 345501f928eSThomas Petazzoni int __init coherency_init(void) 346501f928eSThomas Petazzoni { 347501f928eSThomas Petazzoni int type = coherency_type(); 348501f928eSThomas Petazzoni struct device_node *np; 349501f928eSThomas Petazzoni 350501f928eSThomas Petazzoni np = of_find_matching_node(NULL, of_coherency_table); 351501f928eSThomas Petazzoni 352501f928eSThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) 353501f928eSThomas Petazzoni armada_370_coherency_init(np); 354d0de9323SThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 || 355d0de9323SThomas Petazzoni type == COHERENCY_FABRIC_TYPE_ARMADA_380) 356d0de9323SThomas Petazzoni armada_375_380_coherency_init(np); 357501f928eSThomas Petazzoni 358009f1315SGregory CLEMENT return 0; 359009f1315SGregory CLEMENT } 360865e0527SThomas Petazzoni 361865e0527SThomas Petazzoni static int __init coherency_late_init(void) 362865e0527SThomas Petazzoni { 3635ab5afd8SThomas Petazzoni int type = coherency_type(); 3645ab5afd8SThomas Petazzoni 3655ab5afd8SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_NONE) 3665ab5afd8SThomas Petazzoni return 0; 3675ab5afd8SThomas Petazzoni 3685ab5afd8SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) 3695ab5afd8SThomas Petazzoni armada_375_coherency_init_wa(); 3705ab5afd8SThomas Petazzoni 371865e0527SThomas Petazzoni bus_register_notifier(&platform_bus_type, 372865e0527SThomas Petazzoni &mvebu_hwcc_platform_nb); 3735ab5afd8SThomas Petazzoni 374865e0527SThomas Petazzoni return 0; 375865e0527SThomas Petazzoni } 376865e0527SThomas Petazzoni 377865e0527SThomas Petazzoni postcore_initcall(coherency_late_init); 378