platform: msm_shared: Add qgic api to change from interrupt detection types
By default all interrupts are configured as edge based. Add an api to configure
either as edge or level based
Change-Id: I6a50fc49761269374943fa3b41156213cd6160da
diff --git a/platform/msm_shared/include/qgic.h b/platform/msm_shared/include/qgic.h
index 45607ff..30abec5 100644
--- a/platform/msm_shared/include/qgic.h
+++ b/platform/msm_shared/include/qgic.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011, 2014, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -56,11 +56,17 @@
#define GIC_DIST_CONFIG GIC_DIST_REG(0xc00)
#define GIC_DIST_SOFTINT GIC_DIST_REG(0xf00)
+#define INTERRUPT_LVL_N_TO_N 0x0
+#define INTERRUPT_LVL_1_TO_N 0x1
+#define INTERRUPT_EDGE_N_TO_N 0x2
+#define INTERRUPT_EDGE_1_TO_N 0x3
+
struct ihandler {
int_handler func;
void *arg;
};
void qgic_init(void);
+void qgic_change_interrupt_cfg(uint32_t spi_number, uint8_t type);
#endif
diff --git a/platform/msm_shared/qgic.c b/platform/msm_shared/qgic.c
index 48e846d..49299e7 100644
--- a/platform/msm_shared/qgic.c
+++ b/platform/msm_shared/qgic.c
@@ -32,6 +32,7 @@
*/
#include <reg.h>
+#include <bits.h>
#include <debug.h>
#include <arch/arm.h>
#include <kernel/thread.h>
@@ -179,3 +180,24 @@
handler[vector].arg = arg;
exit_critical_section();
}
+
+void qgic_change_interrupt_cfg(uint32_t spi_number, uint8_t type)
+{
+ uint32_t register_number, register_address, bit_number, value;
+ register_number = spi_number >> 4; // r = n DIV 16
+ bit_number = (spi_number % 16) << 1; // b = (n MOD 16) * 2
+ value = readl(GIC_DIST_CONFIG + (register_number << 2));
+ // there are two bits per register to indicate the level
+ if (type == INTERRUPT_LVL_N_TO_N)
+ value &= ~(BIT(bit_number)|BIT(bit_number+1)); // 0x0 0x0
+ else if (type == INTERRUPT_LVL_1_TO_N)
+ value = (value & ~BIT(bit_number+1)) | BIT(bit_number); // 0x0 0x1
+ else if (type == INTERRUPT_EDGE_N_TO_N)
+ value = BIT(bit_number+1) | (value & ~BIT(bit_number));// 0x1 0x0
+ else if (type == INTERRUPT_EDGE_1_TO_N)
+ value |= (BIT(bit_number)|BIT(bit_number+1)); // 0x1 0x1
+ else
+ dprintf(CRITICAL, "Invalid interrupt type change requested\n");
+ register_address = GIC_DIST_CONFIG + (register_number << 2);
+ writel(value, register_address);
+}