cci.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <stdbool.h>
  8. #include <stdint.h>
  9. #include <arch.h>
  10. #include <arch_helpers.h>
  11. #include <common/debug.h>
  12. #include <drivers/arm/cci.h>
  13. #include <lib/mmio.h>
  14. #define MAKE_CCI_PART_NUMBER(hi, lo) (((hi) << 8) | (lo))
  15. #define CCI_PART_LO_MASK U(0xff)
  16. #define CCI_PART_HI_MASK U(0xf)
  17. /* CCI part number codes read from Peripheral ID registers 0 and 1 */
  18. #define CCI400_PART_NUM 0x420
  19. #define CCI500_PART_NUM 0x422
  20. #define CCI550_PART_NUM 0x423
  21. #define CCI400_SLAVE_PORTS 5
  22. #define CCI500_SLAVE_PORTS 7
  23. #define CCI550_SLAVE_PORTS 7
  24. static uintptr_t cci_base;
  25. static const int *cci_slave_if_map;
  26. #if ENABLE_ASSERTIONS
  27. static unsigned int max_master_id;
  28. static int cci_num_slave_ports;
  29. static bool validate_cci_map(const int *map)
  30. {
  31. unsigned int valid_cci_map = 0U;
  32. int slave_if_id;
  33. unsigned int i;
  34. /* Validate the map */
  35. for (i = 0U; i <= max_master_id; i++) {
  36. slave_if_id = map[i];
  37. if (slave_if_id < 0)
  38. continue;
  39. if (slave_if_id >= cci_num_slave_ports) {
  40. ERROR("Slave interface ID is invalid\n");
  41. return false;
  42. }
  43. if ((valid_cci_map & (1UL << slave_if_id)) != 0U) {
  44. ERROR("Multiple masters are assigned same slave interface ID\n");
  45. return false;
  46. }
  47. valid_cci_map |= 1UL << slave_if_id;
  48. }
  49. if (valid_cci_map == 0U) {
  50. ERROR("No master is assigned a valid slave interface\n");
  51. return false;
  52. }
  53. return true;
  54. }
  55. /*
  56. * Read CCI part number from Peripheral ID registers
  57. */
  58. static unsigned int read_cci_part_number(uintptr_t base)
  59. {
  60. unsigned int part_lo, part_hi;
  61. part_lo = mmio_read_32(base + PERIPHERAL_ID0) & CCI_PART_LO_MASK;
  62. part_hi = mmio_read_32(base + PERIPHERAL_ID1) & CCI_PART_HI_MASK;
  63. return MAKE_CCI_PART_NUMBER(part_hi, part_lo);
  64. }
  65. /*
  66. * Identify a CCI device, and return the number of slaves. Return -1 for an
  67. * unidentified device.
  68. */
  69. static int get_slave_ports(unsigned int part_num)
  70. {
  71. int num_slave_ports = -1;
  72. switch (part_num) {
  73. case CCI400_PART_NUM:
  74. num_slave_ports = CCI400_SLAVE_PORTS;
  75. break;
  76. case CCI500_PART_NUM:
  77. num_slave_ports = CCI500_SLAVE_PORTS;
  78. break;
  79. case CCI550_PART_NUM:
  80. num_slave_ports = CCI550_SLAVE_PORTS;
  81. break;
  82. default:
  83. /* Do nothing in default case */
  84. break;
  85. }
  86. return num_slave_ports;
  87. }
  88. #endif /* ENABLE_ASSERTIONS */
  89. void __init cci_init(uintptr_t base, const int *map,
  90. unsigned int num_cci_masters)
  91. {
  92. assert(map != NULL);
  93. assert(base != 0U);
  94. cci_base = base;
  95. cci_slave_if_map = map;
  96. #if ENABLE_ASSERTIONS
  97. /*
  98. * Master Id's are assigned from zero, So in an array of size n
  99. * the max master id is (n - 1).
  100. */
  101. max_master_id = num_cci_masters - 1U;
  102. cci_num_slave_ports = get_slave_ports(read_cci_part_number(base));
  103. #endif
  104. assert(cci_num_slave_ports >= 0);
  105. assert(validate_cci_map(map));
  106. }
  107. void cci_enable_snoop_dvm_reqs(unsigned int master_id)
  108. {
  109. int slave_if_id = cci_slave_if_map[master_id];
  110. assert(master_id <= max_master_id);
  111. assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
  112. assert(cci_base != 0U);
  113. /*
  114. * Enable Snoops and DVM messages, no need for Read/Modify/Write as
  115. * rest of bits are write ignore
  116. */
  117. mmio_write_32(cci_base +
  118. SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
  119. DVM_EN_BIT | SNOOP_EN_BIT);
  120. /*
  121. * Wait for the completion of the write to the Snoop Control Register
  122. * before testing the change_pending bit
  123. */
  124. dsbish();
  125. /* Wait for the dust to settle down */
  126. while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
  127. ;
  128. }
  129. void cci_disable_snoop_dvm_reqs(unsigned int master_id)
  130. {
  131. int slave_if_id = cci_slave_if_map[master_id];
  132. assert(master_id <= max_master_id);
  133. assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0));
  134. assert(cci_base != 0U);
  135. /*
  136. * Disable Snoops and DVM messages, no need for Read/Modify/Write as
  137. * rest of bits are write ignore.
  138. */
  139. mmio_write_32(cci_base +
  140. SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG,
  141. ~(DVM_EN_BIT | SNOOP_EN_BIT));
  142. /*
  143. * Wait for the completion of the write to the Snoop Control Register
  144. * before testing the change_pending bit
  145. */
  146. dsbish();
  147. /* Wait for the dust to settle down */
  148. while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U)
  149. ;
  150. }