tegra_fiq_glue.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /*
  2. * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
  3. * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: BSD-3-Clause
  6. */
  7. #include <assert.h>
  8. #include <arch_helpers.h>
  9. #include <bl31/interrupt_mgmt.h>
  10. #include <bl31/ehf.h>
  11. #include <common/bl_common.h>
  12. #include <common/debug.h>
  13. #include <context.h>
  14. #include <denver.h>
  15. #include <lib/el3_runtime/context_mgmt.h>
  16. #include <plat/common/platform.h>
  17. #if ENABLE_WDT_LEGACY_FIQ_HANDLING
  18. #include <flowctrl.h>
  19. #endif
  20. #include <tegra_def.h>
  21. #include <tegra_private.h>
  22. /* Legacy FIQ used by earlier Tegra platforms */
  23. #define LEGACY_FIQ_PPI_WDT 28U
  24. /*******************************************************************************
  25. * Static variables
  26. ******************************************************************************/
  27. static uint64_t ns_fiq_handler_addr;
  28. static uint32_t fiq_handler_active;
  29. static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT];
  30. /*******************************************************************************
  31. * Handler for FIQ interrupts
  32. ******************************************************************************/
  33. static int tegra_fiq_interrupt_handler(unsigned int id, unsigned int flags,
  34. void *handle, void *cookie)
  35. {
  36. cpu_context_t *ctx = cm_get_context(NON_SECURE);
  37. el3_state_t *el3state_ctx = get_el3state_ctx(ctx);
  38. uint32_t cpu = plat_my_core_pos();
  39. (void)flags;
  40. (void)handle;
  41. (void)cookie;
  42. /*
  43. * Jump to NS world only if the NS world's FIQ handler has
  44. * been registered
  45. */
  46. if (ns_fiq_handler_addr != 0U) {
  47. /*
  48. * The FIQ was generated when the execution was in the non-secure
  49. * world. Save the context registers to start with.
  50. */
  51. cm_el1_sysregs_context_save(NON_SECURE);
  52. /*
  53. * Save elr_el3 and spsr_el3 from the saved context, and overwrite
  54. * the context with the NS fiq_handler_addr and SPSR value.
  55. */
  56. fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3));
  57. fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3));
  58. /*
  59. * Set the new ELR to continue execution in the NS world using the
  60. * FIQ handler registered earlier.
  61. */
  62. cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr);
  63. }
  64. #if ENABLE_WDT_LEGACY_FIQ_HANDLING
  65. /*
  66. * Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ
  67. * need to issue an IPI to other CPUs, to allow them to handle
  68. * the "system hung" scenario. This interrupt is passed to the GICD
  69. * via the Flow Controller. So, once we receive this interrupt,
  70. * disable the routing so that we can mark it as "complete" in the
  71. * GIC later.
  72. */
  73. if (id == LEGACY_FIQ_PPI_WDT) {
  74. tegra_fc_disable_fiq_to_ccplex_routing();
  75. }
  76. #endif
  77. /*
  78. * Mark this interrupt as complete to avoid a FIQ storm.
  79. */
  80. plat_ic_end_of_interrupt(id);
  81. return 0;
  82. }
  83. /*******************************************************************************
  84. * Setup handler for FIQ interrupts
  85. ******************************************************************************/
  86. void tegra_fiq_handler_setup(void)
  87. {
  88. /* return if already registered */
  89. if (fiq_handler_active == 0U) {
  90. /*
  91. * Register an interrupt handler for FIQ interrupts generated for
  92. * NS interrupt sources
  93. */
  94. ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler);
  95. /* handler is now active */
  96. fiq_handler_active = 1;
  97. }
  98. }
  99. /*******************************************************************************
  100. * Validate and store NS world's entrypoint for FIQ interrupts
  101. ******************************************************************************/
  102. void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint)
  103. {
  104. ns_fiq_handler_addr = entrypoint;
  105. }
  106. /*******************************************************************************
  107. * Handler to return the NS EL1/EL0 CPU context
  108. ******************************************************************************/
  109. int32_t tegra_fiq_get_intr_context(void)
  110. {
  111. cpu_context_t *ctx = cm_get_context(NON_SECURE);
  112. gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx);
  113. const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx);
  114. uint32_t cpu = plat_my_core_pos();
  115. uint64_t val;
  116. /*
  117. * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so
  118. * that el3_exit() sends these values back to the NS world.
  119. */
  120. write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3));
  121. write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3));
  122. val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0));
  123. write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val));
  124. val = read_el1_ctx_common(el1state_ctx, sp_el1);
  125. write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val));
  126. return 0;
  127. }