]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
ArmPkg/ArmGicDxe: Expose HardwareInterrupt2 protocol
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / GicV3 / ArmGicV3Dxe.c
index 50b51ffcf57b23b110899c7c55237cf85b61d196..01154848f4439af3e87e89cf796f3d69ce4a0c4a 100644 (file)
@@ -19,6 +19,7 @@
 #define ARM_GIC_DEFAULT_PRIORITY  0x80\r
 \r
 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;\r
+extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;\r
 \r
 STATIC UINTN mGicDistributorBase;\r
 STATIC UINTN mGicRedistributorsBase;\r
@@ -192,6 +193,140 @@ EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
   GicV3EndOfInterrupt\r
 };\r
 \r
+/**\r
+  Get interrupt trigger type of an interrupt\r
+\r
+  @param This          Instance pointer for this protocol\r
+  @param Source        Hardware source of the interrupt.\r
+  @param TriggerType   Returns interrupt trigger type.\r
+\r
+  @retval EFI_SUCCESS       Source interrupt supported.\r
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+GicV3GetTriggerType (\r
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,\r
+  IN  HARDWARE_INTERRUPT_SOURCE             Source,\r
+  OUT EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  *TriggerType\r
+  )\r
+{\r
+  UINTN                   RegAddress;\r
+  UINTN                   Config1Bit;\r
+  EFI_STATUS              Status;\r
+\r
+  Status = GicGetDistributorIcfgBaseAndBit (\r
+             Source,\r
+             &RegAddress,\r
+             &Config1Bit\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((MmioRead32 (RegAddress) & (1 << Config1Bit)) == 0) {\r
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH;\r
+  } else {\r
+     *TriggerType = EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set interrupt trigger type of an interrupt\r
+\r
+  @param This          Instance pointer for this protocol\r
+  @param Source        Hardware source of the interrupt.\r
+  @param TriggerType   Interrupt trigger type.\r
+\r
+  @retval EFI_SUCCESS       Source interrupt supported.\r
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+GicV3SetTriggerType (\r
+  IN  EFI_HARDWARE_INTERRUPT2_PROTOCOL      *This,\r
+  IN  HARDWARE_INTERRUPT_SOURCE             Source,\r
+  IN  EFI_HARDWARE_INTERRUPT2_TRIGGER_TYPE  TriggerType\r
+  )\r
+{\r
+  UINTN                   RegAddress;\r
+  UINTN                   Config1Bit;\r
+  UINT32                  Value;\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 SourceEnabled;\r
+\r
+  if (   (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)\r
+      && (TriggerType != EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH)) {\r
+          DEBUG ((DEBUG_ERROR, "Invalid interrupt trigger type: %d\n", \\r
+                 TriggerType));\r
+          ASSERT (FALSE);\r
+          return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = GicGetDistributorIcfgBaseAndBit (\r
+             Source,\r
+             &RegAddress,\r
+             &Config1Bit\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = GicV3GetInterruptSourceState (\r
+             (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
+             Source,\r
+             &SourceEnabled\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Value = (TriggerType == EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING)\r
+          ?  ARM_GIC_ICDICFR_EDGE_TRIGGERED\r
+          :  ARM_GIC_ICDICFR_LEVEL_TRIGGERED;\r
+\r
+  // Before changing the value, we must disable the interrupt,\r
+  // otherwise GIC behavior is UNPREDICTABLE.\r
+  if (SourceEnabled) {\r
+    GicV3DisableInterruptSource (\r
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
+      Source\r
+      );\r
+  }\r
+\r
+  MmioAndThenOr32 (\r
+    RegAddress,\r
+    ~(0x1 << Config1Bit),\r
+    Value << Config1Bit\r
+    );\r
+  // Restore interrupt state\r
+  if (SourceEnabled) {\r
+    GicV3EnableInterruptSource (\r
+      (EFI_HARDWARE_INTERRUPT_PROTOCOL*)This,\r
+      Source\r
+      );\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol = {\r
+  (HARDWARE_INTERRUPT2_REGISTER)RegisterInterruptSource,\r
+  (HARDWARE_INTERRUPT2_ENABLE)GicV3EnableInterruptSource,\r
+  (HARDWARE_INTERRUPT2_DISABLE)GicV3DisableInterruptSource,\r
+  (HARDWARE_INTERRUPT2_INTERRUPT_STATE)GicV3GetInterruptSourceState,\r
+  (HARDWARE_INTERRUPT2_END_OF_INTERRUPT)GicV3EndOfInterrupt,\r
+  GicV3GetTriggerType,\r
+  GicV3SetTriggerType\r
+};\r
+\r
 /**\r
   Shutdown our hardware\r
 \r
@@ -353,6 +488,7 @@ GicV3DxeInitialize (
 \r
   Status = InstallAndRegisterInterruptService (\r
              &gHardwareInterruptV3Protocol,\r
+             &gHardwareInterrupt2V3Protocol,\r
              GicV3IrqInterruptHandler,\r
              GicV3ExitBootServicesEvent\r
              );\r