summaryrefslogtreecommitdiff
path: root/plat/xilinx
diff options
context:
space:
mode:
authorTejas Patel <tejas.patel@xilinx.com>2019-02-27 18:44:56 +0530
committerJolly Shah <jolly.shah@xilinx.com>2020-01-15 11:03:30 -0800
commit6e82cd8c9b37ad6226523e88829ecba776b15bc8 (patch)
tree31e365b348dd110e05772e78abc02ac76ae8a542 /plat/xilinx
parent89224531b43f4a2396a0b5a9ab34349bd7c58b06 (diff)
xilinx: versal: Implement set wakeup source for client
Add support to set wakeup source for APU while suspending. Signed-off-by: Tejas Patel <tejas.patel@xilinx.com> Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com> Signed-off-by: Jolly Shah <jolly.shah@xilinx.com> Change-Id: I4809fd83a710def8144fdad74990c45e62b8fdf3
Diffstat (limited to 'plat/xilinx')
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.c114
-rw-r--r--plat/xilinx/versal/pm_service/pm_defs.h4
2 files changed, 118 insertions, 0 deletions
diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
index b234e1bfa..5b47838e9 100644
--- a/plat/xilinx/versal/pm_service/pm_client.c
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -9,16 +9,22 @@
* for getting information about and changing state of the APU.
*/
+#include <assert.h>
#include <plat_ipi.h>
#include <platform_def.h>
#include <versal_def.h>
#include <lib/bakery_lock.h>
#include <lib/mmio.h>
+#include <lib/utils.h>
#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
#include <plat/common/platform.h>
+#include "pm_api_sys.h"
#include "pm_client.h"
#define UNDEFINED_CPUID (~0)
+#define IRQ_MAX 142
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1)
DEFINE_BAKERY_LOCK(pm_client_secure_lock);
@@ -44,6 +50,111 @@ static const struct pm_proc pm_procs_all[] = {
const struct pm_proc *primary_proc = &pm_procs_all[0];
+/* Interrupt to PM node index map */
+static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
+ [13] = XPM_NODEIDX_DEV_GPIO,
+ [14] = XPM_NODEIDX_DEV_I2C_0,
+ [15] = XPM_NODEIDX_DEV_I2C_1,
+ [16] = XPM_NODEIDX_DEV_SPI_0,
+ [17] = XPM_NODEIDX_DEV_SPI_1,
+ [18] = XPM_NODEIDX_DEV_UART_0,
+ [19] = XPM_NODEIDX_DEV_UART_1,
+ [20] = XPM_NODEIDX_DEV_CAN_FD_0,
+ [21] = XPM_NODEIDX_DEV_CAN_FD_1,
+ [22] = XPM_NODEIDX_DEV_USB_0,
+ [23] = XPM_NODEIDX_DEV_USB_0,
+ [24] = XPM_NODEIDX_DEV_USB_0,
+ [25] = XPM_NODEIDX_DEV_USB_0,
+ [26] = XPM_NODEIDX_DEV_USB_0,
+ [37] = XPM_NODEIDX_DEV_TTC_0,
+ [38] = XPM_NODEIDX_DEV_TTC_0,
+ [39] = XPM_NODEIDX_DEV_TTC_0,
+ [40] = XPM_NODEIDX_DEV_TTC_1,
+ [41] = XPM_NODEIDX_DEV_TTC_1,
+ [42] = XPM_NODEIDX_DEV_TTC_1,
+ [43] = XPM_NODEIDX_DEV_TTC_2,
+ [44] = XPM_NODEIDX_DEV_TTC_2,
+ [45] = XPM_NODEIDX_DEV_TTC_2,
+ [46] = XPM_NODEIDX_DEV_TTC_3,
+ [47] = XPM_NODEIDX_DEV_TTC_3,
+ [48] = XPM_NODEIDX_DEV_TTC_3,
+ [56] = XPM_NODEIDX_DEV_GEM_0,
+ [57] = XPM_NODEIDX_DEV_GEM_0,
+ [58] = XPM_NODEIDX_DEV_GEM_1,
+ [59] = XPM_NODEIDX_DEV_GEM_1,
+ [60] = XPM_NODEIDX_DEV_ADMA_0,
+ [61] = XPM_NODEIDX_DEV_ADMA_1,
+ [62] = XPM_NODEIDX_DEV_ADMA_2,
+ [63] = XPM_NODEIDX_DEV_ADMA_3,
+ [64] = XPM_NODEIDX_DEV_ADMA_4,
+ [65] = XPM_NODEIDX_DEV_ADMA_5,
+ [66] = XPM_NODEIDX_DEV_ADMA_6,
+ [67] = XPM_NODEIDX_DEV_ADMA_7,
+ [74] = XPM_NODEIDX_DEV_USB_0,
+ [126] = XPM_NODEIDX_DEV_SDIO_0,
+ [127] = XPM_NODEIDX_DEV_SDIO_0,
+ [128] = XPM_NODEIDX_DEV_SDIO_1,
+ [129] = XPM_NODEIDX_DEV_SDIO_1,
+ [142] = XPM_NODEIDX_DEV_RTC,
+};
+
+/**
+ * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
+ * @irq: Interrupt number
+ *
+ * Return: PM node index corresponding to the specified interrupt
+ */
+static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq)
+{
+ assert(irq <= IRQ_MAX);
+ return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
+ * wake sources in the LibPM.
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+ uint32_t reg_num;
+ uint32_t device_id;
+ uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
+ uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
+
+ zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
+
+ for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+ uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+ uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+ if (!reg)
+ continue;
+
+ while (reg) {
+ enum pm_device_node_idx node_idx;
+ uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+ idx = __builtin_ctz(lowest_set);
+ irq = base_irq + idx;
+
+ if (irq > IRQ_MAX)
+ break;
+
+ node_idx = irq_to_pm_node_idx(irq);
+ reg &= ~lowest_set;
+
+ if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
+ (!pm_wakeup_nodes_set[node_idx])) {
+ /* Get device ID from node index */
+ device_id = PERIPH_DEVID(node_idx);
+ ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0,
+ device_id, 1);
+ pm_wakeup_nodes_set[node_idx] = !ret;
+ }
+ }
+ }
+}
+
/**
* pm_client_suspend() - Client-specific suspend actions
*
@@ -55,6 +166,9 @@ void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
{
bakery_lock_get(&pm_client_secure_lock);
+ if (state == PM_STATE_SUSPEND_TO_RAM)
+ pm_client_set_wakeup_sources();
+
/* Set powerdown request */
mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
proc->pwrdn_mask);
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index 626fa3916..281494a76 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -29,6 +29,10 @@
#define XPM_DEVID_ACPU_0 APU_DEVID(XPM_NODEIDX_DEV_ACPU_0)
#define XPM_DEVID_ACPU_1 APU_DEVID(XPM_NODEIDX_DEV_ACPU_1)
+#define PERIPH_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, \
+ XPM_NODESUBCL_DEV_PERIPH, \
+ XPM_NODETYPE_DEV_PERIPH, (IDX))
+
/* PM API ids */
#define PM_GET_API_VERSION 1U
#define PM_GET_DEVICE_STATUS 3U