coherency.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * Coherency fabric (Aurora) support for Armada 370 and XP platforms.
  3. *
  4. * Copyright (C) 2012 Marvell
  5. *
  6. * Yehuda Yitschak <yehuday@marvell.com>
  7. * Gregory Clement <gregory.clement@free-electrons.com>
  8. * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  9. *
  10. * This file is licensed under the terms of the GNU General Public
  11. * License version 2. This program is licensed "as is" without any
  12. * warranty of any kind, whether express or implied.
  13. *
  14. * The Armada 370 and Armada XP SOCs have a coherency fabric which is
  15. * responsible for ensuring hardware coherency between all CPUs and between
  16. * CPUs and I/O masters. This file initializes the coherency fabric and
  17. * supplies basic routines for configuring and controlling hardware coherency
  18. */
  19. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/of_address.h>
  22. #include <linux/io.h>
  23. #include <linux/smp.h>
  24. #include <linux/dma-mapping.h>
  25. #include <linux/platform_device.h>
  26. #include <asm/smp_plat.h>
  27. #include "armada-370-xp.h"
  28. /*
  29. * Some functions in this file are called very early during SMP
  30. * initialization. At that time the device tree framework is not yet
  31. * ready, and it is not possible to get the register address to
  32. * ioremap it. That's why the pointer below is given with an initial
  33. * value matching its virtual mapping
  34. */
  35. static void __iomem *coherency_base = ARMADA_370_XP_REGS_VIRT_BASE + 0x20200;
  36. static void __iomem *coherency_cpu_base;
  37. /* Coherency fabric registers */
  38. #define COHERENCY_FABRIC_CFG_OFFSET 0x4
  39. #define IO_SYNC_BARRIER_CTL_OFFSET 0x0
  40. static struct of_device_id of_coherency_table[] = {
  41. {.compatible = "marvell,coherency-fabric"},
  42. { /* end of list */ },
  43. };
  44. #ifdef CONFIG_SMP
  45. int coherency_get_cpu_count(void)
  46. {
  47. int reg, cnt;
  48. reg = readl(coherency_base + COHERENCY_FABRIC_CFG_OFFSET);
  49. cnt = (reg & 0xF) + 1;
  50. return cnt;
  51. }
  52. #endif
  53. /* Function defined in coherency_ll.S */
  54. int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id);
  55. int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id)
  56. {
  57. if (!coherency_base) {
  58. pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id);
  59. pr_warn("Coherency fabric is not initialized\n");
  60. return 1;
  61. }
  62. return ll_set_cpu_coherent(coherency_base, hw_cpu_id);
  63. }
  64. static inline void mvebu_hwcc_sync_io_barrier(void)
  65. {
  66. writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
  67. while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
  68. }
  69. static dma_addr_t mvebu_hwcc_dma_map_page(struct device *dev, struct page *page,
  70. unsigned long offset, size_t size,
  71. enum dma_data_direction dir,
  72. struct dma_attrs *attrs)
  73. {
  74. if (dir != DMA_TO_DEVICE)
  75. mvebu_hwcc_sync_io_barrier();
  76. return pfn_to_dma(dev, page_to_pfn(page)) + offset;
  77. }
  78. static void mvebu_hwcc_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
  79. size_t size, enum dma_data_direction dir,
  80. struct dma_attrs *attrs)
  81. {
  82. if (dir != DMA_TO_DEVICE)
  83. mvebu_hwcc_sync_io_barrier();
  84. }
  85. static void mvebu_hwcc_dma_sync(struct device *dev, dma_addr_t dma_handle,
  86. size_t size, enum dma_data_direction dir)
  87. {
  88. if (dir != DMA_TO_DEVICE)
  89. mvebu_hwcc_sync_io_barrier();
  90. }
  91. static struct dma_map_ops mvebu_hwcc_dma_ops = {
  92. .alloc = arm_dma_alloc,
  93. .free = arm_dma_free,
  94. .mmap = arm_dma_mmap,
  95. .map_page = mvebu_hwcc_dma_map_page,
  96. .unmap_page = mvebu_hwcc_dma_unmap_page,
  97. .get_sgtable = arm_dma_get_sgtable,
  98. .map_sg = arm_dma_map_sg,
  99. .unmap_sg = arm_dma_unmap_sg,
  100. .sync_single_for_cpu = mvebu_hwcc_dma_sync,
  101. .sync_single_for_device = mvebu_hwcc_dma_sync,
  102. .sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,
  103. .sync_sg_for_device = arm_dma_sync_sg_for_device,
  104. .set_dma_mask = arm_dma_set_mask,
  105. };
  106. static int mvebu_hwcc_platform_notifier(struct notifier_block *nb,
  107. unsigned long event, void *__dev)
  108. {
  109. struct device *dev = __dev;
  110. if (event != BUS_NOTIFY_ADD_DEVICE)
  111. return NOTIFY_DONE;
  112. set_dma_ops(dev, &mvebu_hwcc_dma_ops);
  113. return NOTIFY_OK;
  114. }
  115. static struct notifier_block mvebu_hwcc_platform_nb = {
  116. .notifier_call = mvebu_hwcc_platform_notifier,
  117. };
  118. int __init coherency_init(void)
  119. {
  120. struct device_node *np;
  121. np = of_find_matching_node(NULL, of_coherency_table);
  122. if (np) {
  123. pr_info("Initializing Coherency fabric\n");
  124. coherency_base = of_iomap(np, 0);
  125. coherency_cpu_base = of_iomap(np, 1);
  126. set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
  127. bus_register_notifier(&platform_bus_type,
  128. &mvebu_hwcc_platform_nb);
  129. }
  130. return 0;
  131. }