marvell_gicv2.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * Copyright (C) 2018 Marvell International Ltd.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. * https://spdx.org/licenses
  6. */
  7. #include <platform_def.h>
  8. #include <bl31/interrupt_mgmt.h>
  9. #include <common/debug.h>
  10. #include <drivers/arm/gicv2.h>
  11. #include <lib/bakery_lock.h>
  12. #include <lib/mmio.h>
  13. #include <plat/common/platform.h>
  14. #include <plat_marvell.h>
  15. /*
  16. * The following functions are defined as weak to allow a platform to override
  17. * the way the GICv2 driver is initialised and used.
  18. */
  19. #pragma weak plat_marvell_gic_driver_init
  20. #pragma weak plat_marvell_gic_init
  21. #define A7K8K_PIC_CAUSE_REG 0xf03f0100
  22. #define A7K8K_PIC0_MASK_REG 0xf03f0108
  23. #define A7K8K_PIC_PMUOF_IRQ_MASK (1 << 17)
  24. #define A7K8K_PIC_MAX_IRQS 32
  25. #define A7K8K_PIC_MAX_IRQ_MASK ((1UL << A7K8K_PIC_MAX_IRQS) - 1)
  26. #define A7K8K_ODMIN_SET_REG 0xf0300040
  27. #define A7K8K_ODMI_PMU_IRQ(idx) ((2 + idx) << 12)
  28. #define A7K8K_ODMI_PMU_GIC_IRQ(idx) (130 + idx)
  29. static DEFINE_BAKERY_LOCK(a7k8k_irq_lock);
  30. /*
  31. * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
  32. * interrupts.
  33. */
  34. static const interrupt_prop_t marvell_interrupt_props[] = {
  35. PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0),
  36. PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0)
  37. };
  38. static unsigned int target_mask_array[PLATFORM_CORE_COUNT];
  39. /*
  40. * Ideally `marvell_gic_data` structure definition should be a `const` but it is
  41. * kept as modifiable for overwriting with different GICD and GICC base when
  42. * running on FVP with VE memory map.
  43. */
  44. static gicv2_driver_data_t marvell_gic_data = {
  45. .gicd_base = PLAT_MARVELL_GICD_BASE,
  46. .gicc_base = PLAT_MARVELL_GICC_BASE,
  47. .interrupt_props = marvell_interrupt_props,
  48. .interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props),
  49. .target_masks = target_mask_array,
  50. .target_masks_num = ARRAY_SIZE(target_mask_array),
  51. };
  52. /*
  53. * ARM common helper to initialize the GICv2 only driver.
  54. */
  55. void plat_marvell_gic_driver_init(void)
  56. {
  57. gicv2_driver_init(&marvell_gic_data);
  58. }
  59. static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id,
  60. uint32_t flags,
  61. void *handle,
  62. void *cookie)
  63. {
  64. unsigned int idx = plat_my_core_pos();
  65. uint32_t irq;
  66. bakery_lock_get(&a7k8k_irq_lock);
  67. /* Acknowledge IRQ */
  68. irq = plat_ic_acknowledge_interrupt();
  69. plat_ic_end_of_interrupt(irq);
  70. if (irq != MARVELL_IRQ_PIC0) {
  71. bakery_lock_release(&a7k8k_irq_lock);
  72. return 0;
  73. }
  74. /* Acknowledge PMU overflow IRQ in PIC0 */
  75. mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
  76. /* Trigger ODMI Frame IRQ */
  77. mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx));
  78. bakery_lock_release(&a7k8k_irq_lock);
  79. return 0;
  80. }
  81. void mvebu_pmu_interrupt_enable(void)
  82. {
  83. unsigned int idx;
  84. uint32_t flags;
  85. int32_t rc;
  86. /* Reset PIC */
  87. mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
  88. /* Unmask PMU overflow IRQ in PIC0 */
  89. mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
  90. /* Configure ODMI Frame IRQs as edge triggered */
  91. for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++)
  92. gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx),
  93. GIC_INTR_CFG_EDGE);
  94. /*
  95. * Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type
  96. * for GICv2 in ARM-TF.
  97. */
  98. flags = 0U;
  99. set_interrupt_rm_flag((flags), (NON_SECURE));
  100. rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
  101. a7k8k_pmu_interrupt_handler,
  102. flags);
  103. if (rc != 0)
  104. panic();
  105. }
  106. void mvebu_pmu_interrupt_disable(void)
  107. {
  108. /* Reset PIC */
  109. mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
  110. /* Mask PMU overflow IRQ in PIC0 */
  111. mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
  112. }
  113. void plat_marvell_gic_init(void)
  114. {
  115. gicv2_distif_init();
  116. gicv2_pcpu_distif_init();
  117. gicv2_set_pe_target_mask(plat_my_core_pos());
  118. gicv2_cpuif_enable();
  119. }