1c73a90e5STejas Patel /* 20b151872STanmay Shah * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved. 3c73a90e5STejas Patel * 4c73a90e5STejas Patel * SPDX-License-Identifier: BSD-3-Clause 5c73a90e5STejas Patel */ 6c73a90e5STejas Patel 7c73a90e5STejas Patel /* 8c73a90e5STejas Patel * APU specific definition of processors in the subsystem as well as functions 9c73a90e5STejas Patel * for getting information about and changing state of the APU. 10c73a90e5STejas Patel */ 11c73a90e5STejas Patel 126e82cd8cSTejas Patel #include <assert.h> 13c73a90e5STejas Patel #include <plat_ipi.h> 14c73a90e5STejas Patel #include <platform_def.h> 15c73a90e5STejas Patel #include <versal_def.h> 16c73a90e5STejas Patel #include <lib/bakery_lock.h> 17fbb32695STejas Patel #include <lib/mmio.h> 186e82cd8cSTejas Patel #include <lib/utils.h> 19fbb32695STejas Patel #include <drivers/arm/gicv3.h> 206e82cd8cSTejas Patel #include <drivers/arm/gic_common.h> 21fbb32695STejas Patel #include <plat/common/platform.h> 226e82cd8cSTejas Patel #include "pm_api_sys.h" 23c73a90e5STejas Patel #include "pm_client.h" 240b151872STanmay Shah #include "pm_defs.h" 25c73a90e5STejas Patel 2625b1a910STejas Patel #define UNDEFINED_CPUID (~0) 275d1c211eSAbhyuday Godhasara #define IRQ_MAX 142U 285d1c211eSAbhyuday Godhasara #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U) 2925b1a910STejas Patel 30c73a90e5STejas Patel DEFINE_BAKERY_LOCK(pm_client_secure_lock); 31c73a90e5STejas Patel 32c73a90e5STejas Patel static const struct pm_ipi apu_ipi = { 33c73a90e5STejas Patel .local_ipi_id = IPI_ID_APU, 34c73a90e5STejas Patel .remote_ipi_id = IPI_ID_PMC, 35c73a90e5STejas Patel .buffer_base = IPI_BUFFER_APU_BASE, 36c73a90e5STejas Patel }; 37c73a90e5STejas Patel 38c73a90e5STejas Patel /* Order in pm_procs_all array must match cpu ids */ 39c73a90e5STejas Patel static const struct pm_proc pm_procs_all[] = { 40c73a90e5STejas Patel { 41c73a90e5STejas Patel .node_id = XPM_DEVID_ACPU_0, 42c73a90e5STejas Patel .ipi = &apu_ipi, 43fbb32695STejas Patel .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, 44c73a90e5STejas Patel }, 45c73a90e5STejas Patel { 46c73a90e5STejas Patel .node_id = XPM_DEVID_ACPU_1, 47c73a90e5STejas Patel .ipi = &apu_ipi, 48fbb32695STejas Patel .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, 49c73a90e5STejas Patel } 50c73a90e5STejas Patel }; 51c73a90e5STejas Patel 52c73a90e5STejas Patel const struct pm_proc *primary_proc = &pm_procs_all[0]; 53fbb32695STejas Patel 546e82cd8cSTejas Patel /* Interrupt to PM node index map */ 556e82cd8cSTejas Patel static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = { 566e82cd8cSTejas Patel [13] = XPM_NODEIDX_DEV_GPIO, 576e82cd8cSTejas Patel [14] = XPM_NODEIDX_DEV_I2C_0, 586e82cd8cSTejas Patel [15] = XPM_NODEIDX_DEV_I2C_1, 596e82cd8cSTejas Patel [16] = XPM_NODEIDX_DEV_SPI_0, 606e82cd8cSTejas Patel [17] = XPM_NODEIDX_DEV_SPI_1, 616e82cd8cSTejas Patel [18] = XPM_NODEIDX_DEV_UART_0, 626e82cd8cSTejas Patel [19] = XPM_NODEIDX_DEV_UART_1, 636e82cd8cSTejas Patel [20] = XPM_NODEIDX_DEV_CAN_FD_0, 646e82cd8cSTejas Patel [21] = XPM_NODEIDX_DEV_CAN_FD_1, 656e82cd8cSTejas Patel [22] = XPM_NODEIDX_DEV_USB_0, 666e82cd8cSTejas Patel [23] = XPM_NODEIDX_DEV_USB_0, 676e82cd8cSTejas Patel [24] = XPM_NODEIDX_DEV_USB_0, 686e82cd8cSTejas Patel [25] = XPM_NODEIDX_DEV_USB_0, 696e82cd8cSTejas Patel [26] = XPM_NODEIDX_DEV_USB_0, 706e82cd8cSTejas Patel [37] = XPM_NODEIDX_DEV_TTC_0, 716e82cd8cSTejas Patel [38] = XPM_NODEIDX_DEV_TTC_0, 726e82cd8cSTejas Patel [39] = XPM_NODEIDX_DEV_TTC_0, 736e82cd8cSTejas Patel [40] = XPM_NODEIDX_DEV_TTC_1, 746e82cd8cSTejas Patel [41] = XPM_NODEIDX_DEV_TTC_1, 756e82cd8cSTejas Patel [42] = XPM_NODEIDX_DEV_TTC_1, 766e82cd8cSTejas Patel [43] = XPM_NODEIDX_DEV_TTC_2, 776e82cd8cSTejas Patel [44] = XPM_NODEIDX_DEV_TTC_2, 786e82cd8cSTejas Patel [45] = XPM_NODEIDX_DEV_TTC_2, 796e82cd8cSTejas Patel [46] = XPM_NODEIDX_DEV_TTC_3, 806e82cd8cSTejas Patel [47] = XPM_NODEIDX_DEV_TTC_3, 816e82cd8cSTejas Patel [48] = XPM_NODEIDX_DEV_TTC_3, 826e82cd8cSTejas Patel [56] = XPM_NODEIDX_DEV_GEM_0, 836e82cd8cSTejas Patel [57] = XPM_NODEIDX_DEV_GEM_0, 846e82cd8cSTejas Patel [58] = XPM_NODEIDX_DEV_GEM_1, 856e82cd8cSTejas Patel [59] = XPM_NODEIDX_DEV_GEM_1, 866e82cd8cSTejas Patel [60] = XPM_NODEIDX_DEV_ADMA_0, 876e82cd8cSTejas Patel [61] = XPM_NODEIDX_DEV_ADMA_1, 886e82cd8cSTejas Patel [62] = XPM_NODEIDX_DEV_ADMA_2, 896e82cd8cSTejas Patel [63] = XPM_NODEIDX_DEV_ADMA_3, 906e82cd8cSTejas Patel [64] = XPM_NODEIDX_DEV_ADMA_4, 916e82cd8cSTejas Patel [65] = XPM_NODEIDX_DEV_ADMA_5, 926e82cd8cSTejas Patel [66] = XPM_NODEIDX_DEV_ADMA_6, 936e82cd8cSTejas Patel [67] = XPM_NODEIDX_DEV_ADMA_7, 946e82cd8cSTejas Patel [74] = XPM_NODEIDX_DEV_USB_0, 956e82cd8cSTejas Patel [126] = XPM_NODEIDX_DEV_SDIO_0, 966e82cd8cSTejas Patel [127] = XPM_NODEIDX_DEV_SDIO_0, 976e82cd8cSTejas Patel [128] = XPM_NODEIDX_DEV_SDIO_1, 986e82cd8cSTejas Patel [129] = XPM_NODEIDX_DEV_SDIO_1, 996e82cd8cSTejas Patel [142] = XPM_NODEIDX_DEV_RTC, 1006e82cd8cSTejas Patel }; 1016e82cd8cSTejas Patel 1026e82cd8cSTejas Patel /** 1036e82cd8cSTejas Patel * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number 1046e82cd8cSTejas Patel * @irq: Interrupt number 1056e82cd8cSTejas Patel * 1066e82cd8cSTejas Patel * Return: PM node index corresponding to the specified interrupt 1076e82cd8cSTejas Patel */ 108*912b7a6fSVenkatesh Yadav Abbarapu static enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq) 1096e82cd8cSTejas Patel { 1106e82cd8cSTejas Patel assert(irq <= IRQ_MAX); 1116e82cd8cSTejas Patel return irq_node_map[irq]; 1126e82cd8cSTejas Patel } 1136e82cd8cSTejas Patel 1146e82cd8cSTejas Patel /** 1156e82cd8cSTejas Patel * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as 1166e82cd8cSTejas Patel * wake sources in the LibPM. 117b05d2792SRavi Patel * @node_id: Node id of processor 1186e82cd8cSTejas Patel */ 119b05d2792SRavi Patel static void pm_client_set_wakeup_sources(uint32_t node_id) 1206e82cd8cSTejas Patel { 1216e82cd8cSTejas Patel uint32_t reg_num; 1226e82cd8cSTejas Patel uint32_t device_id; 1236e82cd8cSTejas Patel uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX]; 1246e82cd8cSTejas Patel uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4; 1256e82cd8cSTejas Patel 126fa98d7f2SAbhyuday Godhasara zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set)); 1276e82cd8cSTejas Patel 1285d1c211eSAbhyuday Godhasara for (reg_num = 0U; reg_num < NUM_GICD_ISENABLER; reg_num++) { 1296e82cd8cSTejas Patel uint32_t base_irq = reg_num << ISENABLER_SHIFT; 1306e82cd8cSTejas Patel uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2)); 1316e82cd8cSTejas Patel 132775bf1bbSAbhyuday Godhasara if (reg == 0U) { 1336e82cd8cSTejas Patel continue; 13441567195SAbhyuday Godhasara } 1356e82cd8cSTejas Patel 136775bf1bbSAbhyuday Godhasara while (reg != 0U) { 1376e82cd8cSTejas Patel enum pm_device_node_idx node_idx; 138fa98d7f2SAbhyuday Godhasara uint32_t idx, irq, lowest_set = reg & (-reg); 139fa98d7f2SAbhyuday Godhasara enum pm_ret_status ret; 140bb1768c6SMichal Simek 1416e82cd8cSTejas Patel idx = __builtin_ctz(lowest_set); 1426e82cd8cSTejas Patel irq = base_irq + idx; 1436e82cd8cSTejas Patel 14441567195SAbhyuday Godhasara if (irq > IRQ_MAX) { 1456e82cd8cSTejas Patel break; 14641567195SAbhyuday Godhasara } 1476e82cd8cSTejas Patel 1486e82cd8cSTejas Patel node_idx = irq_to_pm_node_idx(irq); 1496e82cd8cSTejas Patel reg &= ~lowest_set; 1506e82cd8cSTejas Patel 1510b151872STanmay Shah if (node_idx > XPM_NODEIDX_DEV_MIN && node_idx < XPM_NODEIDX_DEV_MAX) { 1520b151872STanmay Shah if (pm_wakeup_nodes_set[node_idx] == 0U) { 1536e82cd8cSTejas Patel /* Get device ID from node index */ 1546e82cd8cSTejas Patel device_id = PERIPH_DEVID(node_idx); 155b05d2792SRavi Patel ret = pm_set_wakeup_source(node_id, 1564697164aSTejas Patel device_id, 1, 1574697164aSTejas Patel SECURE_FLAG); 1580b151872STanmay Shah pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ? 1590b151872STanmay Shah 1 : 0; 1600b151872STanmay Shah } 1616e82cd8cSTejas Patel } 1626e82cd8cSTejas Patel } 1636e82cd8cSTejas Patel } 1646e82cd8cSTejas Patel } 1656e82cd8cSTejas Patel 166fbb32695STejas Patel /** 167fbb32695STejas Patel * pm_client_suspend() - Client-specific suspend actions 168fbb32695STejas Patel * 169fbb32695STejas Patel * This function should contain any PU-specific actions 170fbb32695STejas Patel * required prior to sending suspend request to PMU 171fbb32695STejas Patel * Actions taken depend on the state system is suspending to. 172fbb32695STejas Patel */ 173*912b7a6fSVenkatesh Yadav Abbarapu void pm_client_suspend(const struct pm_proc *proc, uint32_t state) 174fbb32695STejas Patel { 175fbb32695STejas Patel bakery_lock_get(&pm_client_secure_lock); 176fbb32695STejas Patel 17741567195SAbhyuday Godhasara if (state == PM_STATE_SUSPEND_TO_RAM) { 1785d1c211eSAbhyuday Godhasara pm_client_set_wakeup_sources((uint32_t)proc->node_id); 17941567195SAbhyuday Godhasara } 1806e82cd8cSTejas Patel 181fbb32695STejas Patel /* Set powerdown request */ 182fbb32695STejas Patel mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) | 183775bf1bbSAbhyuday Godhasara (uint32_t)proc->pwrdn_mask); 184fbb32695STejas Patel 185fbb32695STejas Patel bakery_lock_release(&pm_client_secure_lock); 186fbb32695STejas Patel } 187fbb32695STejas Patel 188fbb32695STejas Patel /** 189fbb32695STejas Patel * pm_client_abort_suspend() - Client-specific abort-suspend actions 190fbb32695STejas Patel * 191fbb32695STejas Patel * This function should contain any PU-specific actions 192fbb32695STejas Patel * required for aborting a prior suspend request 193fbb32695STejas Patel */ 194fbb32695STejas Patel void pm_client_abort_suspend(void) 195fbb32695STejas Patel { 196fbb32695STejas Patel /* Enable interrupts at processor level (for current cpu) */ 197fbb32695STejas Patel gicv3_cpuif_enable(plat_my_core_pos()); 198fbb32695STejas Patel 199fbb32695STejas Patel bakery_lock_get(&pm_client_secure_lock); 200fbb32695STejas Patel 201fbb32695STejas Patel /* Clear powerdown request */ 202fbb32695STejas Patel mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) & 203775bf1bbSAbhyuday Godhasara ~((uint32_t)primary_proc->pwrdn_mask)); 204fbb32695STejas Patel 205fbb32695STejas Patel bakery_lock_release(&pm_client_secure_lock); 206fbb32695STejas Patel } 207fbb32695STejas Patel 208fbb32695STejas Patel /** 20925b1a910STejas Patel * pm_get_cpuid() - get the local cpu ID for a global node ID 21025b1a910STejas Patel * @nid: node id of the processor 21125b1a910STejas Patel * 21225b1a910STejas Patel * Return: the cpu ID (starting from 0) for the subsystem 21325b1a910STejas Patel */ 214*912b7a6fSVenkatesh Yadav Abbarapu static uint32_t pm_get_cpuid(uint32_t nid) 21525b1a910STejas Patel { 2165d1c211eSAbhyuday Godhasara for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) { 21741567195SAbhyuday Godhasara if (pm_procs_all[i].node_id == nid) { 21825b1a910STejas Patel return i; 21925b1a910STejas Patel } 22041567195SAbhyuday Godhasara } 22125b1a910STejas Patel return UNDEFINED_CPUID; 22225b1a910STejas Patel } 22325b1a910STejas Patel 22425b1a910STejas Patel /** 22525b1a910STejas Patel * pm_client_wakeup() - Client-specific wakeup actions 22625b1a910STejas Patel * 22725b1a910STejas Patel * This function should contain any PU-specific actions 22825b1a910STejas Patel * required for waking up another APU core 22925b1a910STejas Patel */ 23025b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc) 23125b1a910STejas Patel { 232*912b7a6fSVenkatesh Yadav Abbarapu uint32_t cpuid = pm_get_cpuid(proc->node_id); 23325b1a910STejas Patel 23441567195SAbhyuday Godhasara if (cpuid == UNDEFINED_CPUID) { 23525b1a910STejas Patel return; 23641567195SAbhyuday Godhasara } 23725b1a910STejas Patel 23825b1a910STejas Patel bakery_lock_get(&pm_client_secure_lock); 23925b1a910STejas Patel 24025b1a910STejas Patel /* clear powerdown bit for affected cpu */ 24125b1a910STejas Patel uint32_t val = mmio_read_32(FPD_APU_PWRCTL); 24225b1a910STejas Patel val &= ~(proc->pwrdn_mask); 24325b1a910STejas Patel mmio_write_32(FPD_APU_PWRCTL, val); 24425b1a910STejas Patel 24525b1a910STejas Patel bakery_lock_release(&pm_client_secure_lock); 24625b1a910STejas Patel } 24725b1a910STejas Patel 24825b1a910STejas Patel /** 249fbb32695STejas Patel * pm_get_proc() - returns pointer to the proc structure 250fbb32695STejas Patel * @cpuid: id of the cpu whose proc struct pointer should be returned 251fbb32695STejas Patel * 252fbb32695STejas Patel * Return: pointer to a proc structure if proc is found, otherwise NULL 253fbb32695STejas Patel */ 254*912b7a6fSVenkatesh Yadav Abbarapu const struct pm_proc *pm_get_proc(uint32_t cpuid) 255fbb32695STejas Patel { 25641567195SAbhyuday Godhasara if (cpuid < ARRAY_SIZE(pm_procs_all)) { 257fbb32695STejas Patel return &pm_procs_all[cpuid]; 25841567195SAbhyuday Godhasara } 259fbb32695STejas Patel 260fbb32695STejas Patel return NULL; 261fbb32695STejas Patel } 262