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);
+}