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" 3639438567SThomas Petazzoni #include "mvebu-soc-id.h" 37009f1315SGregory CLEMENT 388bd26e3aSPaul Gortmaker unsigned long coherency_phys_base; 39ccd6a131SGregory CLEMENT void __iomem *coherency_base; 40e60304f8SGregory CLEMENT static void __iomem *coherency_cpu_base; 41009f1315SGregory CLEMENT 42009f1315SGregory CLEMENT /* Coherency fabric registers */ 43009f1315SGregory CLEMENT #define COHERENCY_FABRIC_CFG_OFFSET 0x4 44009f1315SGregory CLEMENT 45e60304f8SGregory CLEMENT #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 46e60304f8SGregory CLEMENT 47924d38f4SThomas Petazzoni enum { 48501f928eSThomas Petazzoni COHERENCY_FABRIC_TYPE_NONE, 49924d38f4SThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_370_XP, 5077fa4b9aSThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_375, 51d0de9323SThomas Petazzoni COHERENCY_FABRIC_TYPE_ARMADA_380, 52924d38f4SThomas Petazzoni }; 53924d38f4SThomas Petazzoni 54009f1315SGregory CLEMENT static struct of_device_id of_coherency_table[] = { 55924d38f4SThomas Petazzoni {.compatible = "marvell,coherency-fabric", 56924d38f4SThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_370_XP }, 5777fa4b9aSThomas Petazzoni {.compatible = "marvell,armada-375-coherency-fabric", 5877fa4b9aSThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_375 }, 59d0de9323SThomas Petazzoni {.compatible = "marvell,armada-380-coherency-fabric", 60d0de9323SThomas Petazzoni .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_380 }, 61009f1315SGregory CLEMENT { /* end of list */ }, 62009f1315SGregory CLEMENT }; 63009f1315SGregory CLEMENT 642e8a5942SGregory CLEMENT /* Functions defined in coherency_ll.S */ 652e8a5942SGregory CLEMENT int ll_enable_coherency(void); 662e8a5942SGregory CLEMENT void ll_add_cpu_to_smp_group(void); 67009f1315SGregory CLEMENT 68952f4ca7SGregory CLEMENT int set_cpu_coherent(void) 69009f1315SGregory CLEMENT { 70009f1315SGregory CLEMENT if (!coherency_base) { 71b41375f7SGregory CLEMENT pr_warn("Can't make current CPU cache coherent.\n"); 72009f1315SGregory CLEMENT pr_warn("Coherency fabric is not initialized\n"); 73009f1315SGregory CLEMENT return 1; 74009f1315SGregory CLEMENT } 75009f1315SGregory CLEMENT 762e8a5942SGregory CLEMENT ll_add_cpu_to_smp_group(); 772e8a5942SGregory CLEMENT return ll_enable_coherency(); 78009f1315SGregory CLEMENT } 79009f1315SGregory CLEMENT 805ab5afd8SThomas Petazzoni /* 815ab5afd8SThomas Petazzoni * The below code implements the I/O coherency workaround on Armada 825ab5afd8SThomas Petazzoni * 375. This workaround consists in using the two channels of the 835ab5afd8SThomas Petazzoni * first XOR engine to trigger a XOR transaction that serves as the 845ab5afd8SThomas Petazzoni * I/O coherency barrier. 855ab5afd8SThomas Petazzoni */ 865ab5afd8SThomas Petazzoni 875ab5afd8SThomas Petazzoni static void __iomem *xor_base, *xor_high_base; 885ab5afd8SThomas Petazzoni static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; 895ab5afd8SThomas Petazzoni static void *coherency_wa_buf[CONFIG_NR_CPUS]; 905ab5afd8SThomas Petazzoni static bool coherency_wa_enabled; 915ab5afd8SThomas Petazzoni 925ab5afd8SThomas Petazzoni #define XOR_CONFIG(chan) (0x10 + (chan * 4)) 935ab5afd8SThomas Petazzoni #define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) 945ab5afd8SThomas Petazzoni #define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) 955ab5afd8SThomas Petazzoni #define WINDOW_BASE(w) (0x250 + ((w) << 2)) 965ab5afd8SThomas Petazzoni #define WINDOW_SIZE(w) (0x270 + ((w) << 2)) 975ab5afd8SThomas Petazzoni #define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) 985ab5afd8SThomas Petazzoni #define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) 995ab5afd8SThomas Petazzoni #define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) 1005ab5afd8SThomas Petazzoni #define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) 1015ab5afd8SThomas Petazzoni #define XOR_INIT_VALUE_LOW 0x2E0 1025ab5afd8SThomas Petazzoni #define XOR_INIT_VALUE_HIGH 0x2E4 1035ab5afd8SThomas Petazzoni 1045ab5afd8SThomas Petazzoni static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) 1055ab5afd8SThomas Petazzoni { 1065ab5afd8SThomas Petazzoni int idx = smp_processor_id(); 1075ab5afd8SThomas Petazzoni 1085ab5afd8SThomas Petazzoni /* Write '1' to the first word of the buffer */ 1095ab5afd8SThomas Petazzoni writel(0x1, coherency_wa_buf[idx]); 1105ab5afd8SThomas Petazzoni 1115ab5afd8SThomas Petazzoni /* Wait until the engine is idle */ 1125ab5afd8SThomas Petazzoni while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) 1135ab5afd8SThomas Petazzoni ; 1145ab5afd8SThomas Petazzoni 1155ab5afd8SThomas Petazzoni dmb(); 1165ab5afd8SThomas Petazzoni 1175ab5afd8SThomas Petazzoni /* Trigger channel */ 1185ab5afd8SThomas Petazzoni writel(0x1, xor_base + XOR_ACTIVATION(idx)); 1195ab5afd8SThomas Petazzoni 1205ab5afd8SThomas Petazzoni /* Poll the data until it is cleared by the XOR transaction */ 1215ab5afd8SThomas Petazzoni while (readl(coherency_wa_buf[idx])) 1225ab5afd8SThomas Petazzoni ; 1235ab5afd8SThomas Petazzoni } 1245ab5afd8SThomas Petazzoni 1255ab5afd8SThomas Petazzoni static void __init armada_375_coherency_init_wa(void) 1265ab5afd8SThomas Petazzoni { 1275ab5afd8SThomas Petazzoni const struct mbus_dram_target_info *dram; 1285ab5afd8SThomas Petazzoni struct device_node *xor_node; 1295ab5afd8SThomas Petazzoni struct property *xor_status; 1305ab5afd8SThomas Petazzoni struct clk *xor_clk; 1315ab5afd8SThomas Petazzoni u32 win_enable = 0; 1325ab5afd8SThomas Petazzoni int i; 1335ab5afd8SThomas Petazzoni 1345ab5afd8SThomas Petazzoni pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); 1355ab5afd8SThomas Petazzoni 1365ab5afd8SThomas Petazzoni /* 1375ab5afd8SThomas Petazzoni * Since the workaround uses one XOR engine, we grab a 1385ab5afd8SThomas Petazzoni * reference to its Device Tree node first. 1395ab5afd8SThomas Petazzoni */ 1405ab5afd8SThomas Petazzoni xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); 1415ab5afd8SThomas Petazzoni BUG_ON(!xor_node); 1425ab5afd8SThomas Petazzoni 1435ab5afd8SThomas Petazzoni /* 1445ab5afd8SThomas Petazzoni * Then we mark it as disabled so that the real XOR driver 1455ab5afd8SThomas Petazzoni * will not use it. 1465ab5afd8SThomas Petazzoni */ 1475ab5afd8SThomas Petazzoni xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); 1485ab5afd8SThomas Petazzoni BUG_ON(!xor_status); 1495ab5afd8SThomas Petazzoni 1505ab5afd8SThomas Petazzoni xor_status->value = kstrdup("disabled", GFP_KERNEL); 1515ab5afd8SThomas Petazzoni BUG_ON(!xor_status->value); 1525ab5afd8SThomas Petazzoni 1535ab5afd8SThomas Petazzoni xor_status->length = 8; 1545ab5afd8SThomas Petazzoni xor_status->name = kstrdup("status", GFP_KERNEL); 1555ab5afd8SThomas Petazzoni BUG_ON(!xor_status->name); 1565ab5afd8SThomas Petazzoni 1575ab5afd8SThomas Petazzoni of_update_property(xor_node, xor_status); 1585ab5afd8SThomas Petazzoni 1595ab5afd8SThomas Petazzoni /* 1605ab5afd8SThomas Petazzoni * And we remap the registers, get the clock, and do the 1615ab5afd8SThomas Petazzoni * initial configuration of the XOR engine. 1625ab5afd8SThomas Petazzoni */ 1635ab5afd8SThomas Petazzoni xor_base = of_iomap(xor_node, 0); 1645ab5afd8SThomas Petazzoni xor_high_base = of_iomap(xor_node, 1); 1655ab5afd8SThomas Petazzoni 1665ab5afd8SThomas Petazzoni xor_clk = of_clk_get_by_name(xor_node, NULL); 1675ab5afd8SThomas Petazzoni BUG_ON(!xor_clk); 1685ab5afd8SThomas Petazzoni 1695ab5afd8SThomas Petazzoni clk_prepare_enable(xor_clk); 1705ab5afd8SThomas Petazzoni 1715ab5afd8SThomas Petazzoni dram = mv_mbus_dram_info(); 1725ab5afd8SThomas Petazzoni 1735ab5afd8SThomas Petazzoni for (i = 0; i < 8; i++) { 1745ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_BASE(i)); 1755ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_SIZE(i)); 1765ab5afd8SThomas Petazzoni if (i < 4) 1775ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_REMAP_HIGH(i)); 1785ab5afd8SThomas Petazzoni } 1795ab5afd8SThomas Petazzoni 1805ab5afd8SThomas Petazzoni for (i = 0; i < dram->num_cs; i++) { 1815ab5afd8SThomas Petazzoni const struct mbus_dram_window *cs = dram->cs + i; 1825ab5afd8SThomas Petazzoni writel((cs->base & 0xffff0000) | 1835ab5afd8SThomas Petazzoni (cs->mbus_attr << 8) | 1845ab5afd8SThomas Petazzoni dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); 1855ab5afd8SThomas Petazzoni writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); 1865ab5afd8SThomas Petazzoni 1875ab5afd8SThomas Petazzoni win_enable |= (1 << i); 1885ab5afd8SThomas Petazzoni win_enable |= 3 << (16 + (2 * i)); 1895ab5afd8SThomas Petazzoni } 1905ab5afd8SThomas Petazzoni 1915ab5afd8SThomas Petazzoni writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); 1925ab5afd8SThomas Petazzoni writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); 1935ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); 1945ab5afd8SThomas Petazzoni writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); 1955ab5afd8SThomas Petazzoni 1965ab5afd8SThomas Petazzoni for (i = 0; i < CONFIG_NR_CPUS; i++) { 1975ab5afd8SThomas Petazzoni coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); 1985ab5afd8SThomas Petazzoni BUG_ON(!coherency_wa_buf[i]); 1995ab5afd8SThomas Petazzoni 2005ab5afd8SThomas Petazzoni /* 2015ab5afd8SThomas Petazzoni * We can't use the DMA mapping API, since we don't 2025ab5afd8SThomas Petazzoni * have a valid 'struct device' pointer 2035ab5afd8SThomas Petazzoni */ 2045ab5afd8SThomas Petazzoni coherency_wa_buf_phys[i] = 2055ab5afd8SThomas Petazzoni virt_to_phys(coherency_wa_buf[i]); 2065ab5afd8SThomas Petazzoni BUG_ON(!coherency_wa_buf_phys[i]); 2075ab5afd8SThomas Petazzoni 2085ab5afd8SThomas Petazzoni /* 2095ab5afd8SThomas Petazzoni * Configure the XOR engine for memset operation, with 2105ab5afd8SThomas Petazzoni * a 128 bytes block size 2115ab5afd8SThomas Petazzoni */ 2125ab5afd8SThomas Petazzoni writel(0x444, xor_base + XOR_CONFIG(i)); 2135ab5afd8SThomas Petazzoni writel(128, xor_base + XOR_BLOCK_SIZE(i)); 2145ab5afd8SThomas Petazzoni writel(coherency_wa_buf_phys[i], 2155ab5afd8SThomas Petazzoni xor_base + XOR_DEST_POINTER(i)); 2165ab5afd8SThomas Petazzoni } 2175ab5afd8SThomas Petazzoni 2185ab5afd8SThomas Petazzoni writel(0x0, xor_base + XOR_INIT_VALUE_LOW); 2195ab5afd8SThomas Petazzoni writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); 2205ab5afd8SThomas Petazzoni 2215ab5afd8SThomas Petazzoni coherency_wa_enabled = true; 2225ab5afd8SThomas Petazzoni } 2235ab5afd8SThomas Petazzoni 224e60304f8SGregory CLEMENT static inline void mvebu_hwcc_sync_io_barrier(void) 225e60304f8SGregory CLEMENT { 2265ab5afd8SThomas Petazzoni if (coherency_wa_enabled) { 2275ab5afd8SThomas Petazzoni mvebu_hwcc_armada375_sync_io_barrier_wa(); 2285ab5afd8SThomas Petazzoni return; 2295ab5afd8SThomas Petazzoni } 2305ab5afd8SThomas Petazzoni 231e60304f8SGregory CLEMENT writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); 232e60304f8SGregory CLEMENT while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); 233e60304f8SGregory CLEMENT } 234e60304f8SGregory CLEMENT 235e60304f8SGregory CLEMENT static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page, 236e60304f8SGregory CLEMENT unsigned long offset, size_t size, 237e60304f8SGregory CLEMENT enum dma_data_direction dir, 238e60304f8SGregory CLEMENT struct dma_attrs *attrs) 239e60304f8SGregory CLEMENT { 240e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 241e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 242e60304f8SGregory CLEMENT return pfn_to_dma(dev, page_to_pfn(page)) + offset; 243e60304f8SGregory CLEMENT } 244e60304f8SGregory CLEMENT 245e60304f8SGregory CLEMENT 246e60304f8SGregory CLEMENT static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, 247e60304f8SGregory CLEMENT size_t size, enum dma_data_direction dir, 248e60304f8SGregory CLEMENT struct dma_attrs *attrs) 249e60304f8SGregory CLEMENT { 250e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 251e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 252e60304f8SGregory CLEMENT } 253e60304f8SGregory CLEMENT 254e60304f8SGregory CLEMENT static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle, 255e60304f8SGregory CLEMENT size_t size, enum dma_data_direction dir) 256e60304f8SGregory CLEMENT { 257e60304f8SGregory CLEMENT if (dir != DMA_TO_DEVICE) 258e60304f8SGregory CLEMENT mvebu_hwcc_sync_io_barrier(); 259e60304f8SGregory CLEMENT } 260e60304f8SGregory CLEMENT 261e60304f8SGregory CLEMENT static struct dma_map_ops mvebu_hwcc_dma_ops = { 262e60304f8SGregory CLEMENT .alloc = arm_dma_alloc, 263e60304f8SGregory CLEMENT .free = arm_dma_free, 264e60304f8SGregory CLEMENT .mmap = arm_dma_mmap, 265e60304f8SGregory CLEMENT .map_page = mvebu_hwcc_dma_map_page, 266e60304f8SGregory CLEMENT .unmap_page = mvebu_hwcc_dma_unmap_page, 267e60304f8SGregory CLEMENT .get_sgtable = arm_dma_get_sgtable, 268e60304f8SGregory CLEMENT .map_sg = arm_dma_map_sg, 269e60304f8SGregory CLEMENT .unmap_sg = arm_dma_unmap_sg, 270e60304f8SGregory CLEMENT .sync_single_for_cpu = mvebu_hwcc_dma_sync, 271e60304f8SGregory CLEMENT .sync_single_for_device = mvebu_hwcc_dma_sync, 272e60304f8SGregory CLEMENT .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu, 273e60304f8SGregory CLEMENT .sync_sg_for_device = arm_dma_sync_sg_for_device, 274e60304f8SGregory CLEMENT .set_dma_mask = arm_dma_set_mask, 275e60304f8SGregory CLEMENT }; 276e60304f8SGregory CLEMENT 277e60304f8SGregory CLEMENT static int mvebu_hwcc_platform_notifier(struct notifier_block *nb, 278e60304f8SGregory CLEMENT unsigned long event, void *__dev) 279e60304f8SGregory CLEMENT { 280e60304f8SGregory CLEMENT struct device *dev = __dev; 281e60304f8SGregory CLEMENT 282e60304f8SGregory CLEMENT if (event != BUS_NOTIFY_ADD_DEVICE) 283e60304f8SGregory CLEMENT return NOTIFY_DONE; 284e60304f8SGregory CLEMENT set_dma_ops(dev, &mvebu_hwcc_dma_ops); 285e60304f8SGregory CLEMENT 286e60304f8SGregory CLEMENT return NOTIFY_OK; 287e60304f8SGregory CLEMENT } 288e60304f8SGregory CLEMENT 289e60304f8SGregory CLEMENT static struct notifier_block mvebu_hwcc_platform_nb = { 290e60304f8SGregory CLEMENT .notifier_call = mvebu_hwcc_platform_notifier, 291e60304f8SGregory CLEMENT }; 292e60304f8SGregory CLEMENT 293924d38f4SThomas Petazzoni static void __init armada_370_coherency_init(struct device_node *np) 294009f1315SGregory CLEMENT { 295580ff0eeSThomas Petazzoni struct resource res; 296924d38f4SThomas Petazzoni 297580ff0eeSThomas Petazzoni of_address_to_resource(np, 0, &res); 298580ff0eeSThomas Petazzoni coherency_phys_base = res.start; 299580ff0eeSThomas Petazzoni /* 300580ff0eeSThomas Petazzoni * Ensure secondary CPUs will see the updated value, 301580ff0eeSThomas Petazzoni * which they read before they join the coherency 302580ff0eeSThomas Petazzoni * fabric, and therefore before they are coherent with 303580ff0eeSThomas Petazzoni * the boot CPU cache. 304580ff0eeSThomas Petazzoni */ 305580ff0eeSThomas Petazzoni sync_cache_w(&coherency_phys_base); 306009f1315SGregory CLEMENT coherency_base = of_iomap(np, 0); 307e60304f8SGregory CLEMENT coherency_cpu_base = of_iomap(np, 1); 308952f4ca7SGregory CLEMENT set_cpu_coherent(); 309924d38f4SThomas Petazzoni } 310924d38f4SThomas Petazzoni 311d0de9323SThomas Petazzoni static void __init armada_375_380_coherency_init(struct device_node *np) 31277fa4b9aSThomas Petazzoni { 31377fa4b9aSThomas Petazzoni coherency_cpu_base = of_iomap(np, 0); 31477fa4b9aSThomas Petazzoni } 31577fa4b9aSThomas Petazzoni 316501f928eSThomas Petazzoni static int coherency_type(void) 317924d38f4SThomas Petazzoni { 318924d38f4SThomas Petazzoni struct device_node *np; 3195fbba080SThomas Petazzoni const struct of_device_id *match; 320924d38f4SThomas Petazzoni 3215fbba080SThomas Petazzoni np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); 322924d38f4SThomas Petazzoni if (np) { 3235fbba080SThomas Petazzoni int type = (int) match->data; 324924d38f4SThomas Petazzoni 325501f928eSThomas Petazzoni /* Armada 370/XP coherency works in both UP and SMP */ 326924d38f4SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) 327501f928eSThomas Petazzoni return type; 328924d38f4SThomas Petazzoni 32977fa4b9aSThomas Petazzoni /* Armada 375 coherency works only on SMP */ 33077fa4b9aSThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) 33177fa4b9aSThomas Petazzoni return type; 33277fa4b9aSThomas Petazzoni 333d0de9323SThomas Petazzoni /* Armada 380 coherency works only on SMP */ 334d0de9323SThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) 335d0de9323SThomas Petazzoni return type; 336009f1315SGregory CLEMENT } 337009f1315SGregory CLEMENT 338501f928eSThomas Petazzoni return COHERENCY_FABRIC_TYPE_NONE; 339501f928eSThomas Petazzoni } 340501f928eSThomas Petazzoni 341501f928eSThomas Petazzoni int coherency_available(void) 342501f928eSThomas Petazzoni { 343501f928eSThomas Petazzoni return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; 344501f928eSThomas Petazzoni } 345501f928eSThomas Petazzoni 346501f928eSThomas Petazzoni int __init coherency_init(void) 347501f928eSThomas Petazzoni { 348501f928eSThomas Petazzoni int type = coherency_type(); 349501f928eSThomas Petazzoni struct device_node *np; 350501f928eSThomas Petazzoni 351501f928eSThomas Petazzoni np = of_find_matching_node(NULL, of_coherency_table); 352501f928eSThomas Petazzoni 353501f928eSThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) 354501f928eSThomas Petazzoni armada_370_coherency_init(np); 355d0de9323SThomas Petazzoni else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 || 356d0de9323SThomas Petazzoni type == COHERENCY_FABRIC_TYPE_ARMADA_380) 357d0de9323SThomas Petazzoni armada_375_380_coherency_init(np); 358501f928eSThomas Petazzoni 359009f1315SGregory CLEMENT return 0; 360009f1315SGregory CLEMENT } 361865e0527SThomas Petazzoni 362865e0527SThomas Petazzoni static int __init coherency_late_init(void) 363865e0527SThomas Petazzoni { 3645ab5afd8SThomas Petazzoni int type = coherency_type(); 3655ab5afd8SThomas Petazzoni 3665ab5afd8SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_NONE) 3675ab5afd8SThomas Petazzoni return 0; 3685ab5afd8SThomas Petazzoni 36939438567SThomas Petazzoni if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) { 37039438567SThomas Petazzoni u32 dev, rev; 37139438567SThomas Petazzoni 37239438567SThomas Petazzoni if (mvebu_get_soc_id(&dev, &rev) == 0 && 37339438567SThomas Petazzoni rev == ARMADA_375_Z1_REV) 3745ab5afd8SThomas Petazzoni armada_375_coherency_init_wa(); 37539438567SThomas Petazzoni } 3765ab5afd8SThomas Petazzoni 377865e0527SThomas Petazzoni bus_register_notifier(&platform_bus_type, 378865e0527SThomas Petazzoni &mvebu_hwcc_platform_nb); 3795ab5afd8SThomas Petazzoni 380865e0527SThomas Petazzoni return 0; 381865e0527SThomas Petazzoni } 382865e0527SThomas Petazzoni 383865e0527SThomas Petazzoni postcore_initcall(coherency_late_init); 384