1c73a90e5STejas Patel /* 2c73a90e5STejas Patel * Copyright (c) 2019, 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 12*6e82cd8cSTejas 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> 18*6e82cd8cSTejas Patel #include <lib/utils.h> 19fbb32695STejas Patel #include <drivers/arm/gicv3.h> 20*6e82cd8cSTejas Patel #include <drivers/arm/gic_common.h> 21fbb32695STejas Patel #include <plat/common/platform.h> 22*6e82cd8cSTejas Patel #include "pm_api_sys.h" 23c73a90e5STejas Patel #include "pm_client.h" 24c73a90e5STejas Patel 2525b1a910STejas Patel #define UNDEFINED_CPUID (~0) 26*6e82cd8cSTejas Patel #define IRQ_MAX 142 27*6e82cd8cSTejas Patel #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1) 2825b1a910STejas Patel 29c73a90e5STejas Patel DEFINE_BAKERY_LOCK(pm_client_secure_lock); 30c73a90e5STejas Patel 31c73a90e5STejas Patel static const struct pm_ipi apu_ipi = { 32c73a90e5STejas Patel .local_ipi_id = IPI_ID_APU, 33c73a90e5STejas Patel .remote_ipi_id = IPI_ID_PMC, 34c73a90e5STejas Patel .buffer_base = IPI_BUFFER_APU_BASE, 35c73a90e5STejas Patel }; 36c73a90e5STejas Patel 37c73a90e5STejas Patel /* Order in pm_procs_all array must match cpu ids */ 38c73a90e5STejas Patel static const struct pm_proc pm_procs_all[] = { 39c73a90e5STejas Patel { 40c73a90e5STejas Patel .node_id = XPM_DEVID_ACPU_0, 41c73a90e5STejas Patel .ipi = &apu_ipi, 42fbb32695STejas Patel .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, 43c73a90e5STejas Patel }, 44c73a90e5STejas Patel { 45c73a90e5STejas Patel .node_id = XPM_DEVID_ACPU_1, 46c73a90e5STejas Patel .ipi = &apu_ipi, 47fbb32695STejas Patel .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, 48c73a90e5STejas Patel } 49c73a90e5STejas Patel }; 50c73a90e5STejas Patel 51c73a90e5STejas Patel const struct pm_proc *primary_proc = &pm_procs_all[0]; 52fbb32695STejas Patel 53*6e82cd8cSTejas Patel /* Interrupt to PM node index map */ 54*6e82cd8cSTejas Patel static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = { 55*6e82cd8cSTejas Patel [13] = XPM_NODEIDX_DEV_GPIO, 56*6e82cd8cSTejas Patel [14] = XPM_NODEIDX_DEV_I2C_0, 57*6e82cd8cSTejas Patel [15] = XPM_NODEIDX_DEV_I2C_1, 58*6e82cd8cSTejas Patel [16] = XPM_NODEIDX_DEV_SPI_0, 59*6e82cd8cSTejas Patel [17] = XPM_NODEIDX_DEV_SPI_1, 60*6e82cd8cSTejas Patel [18] = XPM_NODEIDX_DEV_UART_0, 61*6e82cd8cSTejas Patel [19] = XPM_NODEIDX_DEV_UART_1, 62*6e82cd8cSTejas Patel [20] = XPM_NODEIDX_DEV_CAN_FD_0, 63*6e82cd8cSTejas Patel [21] = XPM_NODEIDX_DEV_CAN_FD_1, 64*6e82cd8cSTejas Patel [22] = XPM_NODEIDX_DEV_USB_0, 65*6e82cd8cSTejas Patel [23] = XPM_NODEIDX_DEV_USB_0, 66*6e82cd8cSTejas Patel [24] = XPM_NODEIDX_DEV_USB_0, 67*6e82cd8cSTejas Patel [25] = XPM_NODEIDX_DEV_USB_0, 68*6e82cd8cSTejas Patel [26] = XPM_NODEIDX_DEV_USB_0, 69*6e82cd8cSTejas Patel [37] = XPM_NODEIDX_DEV_TTC_0, 70*6e82cd8cSTejas Patel [38] = XPM_NODEIDX_DEV_TTC_0, 71*6e82cd8cSTejas Patel [39] = XPM_NODEIDX_DEV_TTC_0, 72*6e82cd8cSTejas Patel [40] = XPM_NODEIDX_DEV_TTC_1, 73*6e82cd8cSTejas Patel [41] = XPM_NODEIDX_DEV_TTC_1, 74*6e82cd8cSTejas Patel [42] = XPM_NODEIDX_DEV_TTC_1, 75*6e82cd8cSTejas Patel [43] = XPM_NODEIDX_DEV_TTC_2, 76*6e82cd8cSTejas Patel [44] = XPM_NODEIDX_DEV_TTC_2, 77*6e82cd8cSTejas Patel [45] = XPM_NODEIDX_DEV_TTC_2, 78*6e82cd8cSTejas Patel [46] = XPM_NODEIDX_DEV_TTC_3, 79*6e82cd8cSTejas Patel [47] = XPM_NODEIDX_DEV_TTC_3, 80*6e82cd8cSTejas Patel [48] = XPM_NODEIDX_DEV_TTC_3, 81*6e82cd8cSTejas Patel [56] = XPM_NODEIDX_DEV_GEM_0, 82*6e82cd8cSTejas Patel [57] = XPM_NODEIDX_DEV_GEM_0, 83*6e82cd8cSTejas Patel [58] = XPM_NODEIDX_DEV_GEM_1, 84*6e82cd8cSTejas Patel [59] = XPM_NODEIDX_DEV_GEM_1, 85*6e82cd8cSTejas Patel [60] = XPM_NODEIDX_DEV_ADMA_0, 86*6e82cd8cSTejas Patel [61] = XPM_NODEIDX_DEV_ADMA_1, 87*6e82cd8cSTejas Patel [62] = XPM_NODEIDX_DEV_ADMA_2, 88*6e82cd8cSTejas Patel [63] = XPM_NODEIDX_DEV_ADMA_3, 89*6e82cd8cSTejas Patel [64] = XPM_NODEIDX_DEV_ADMA_4, 90*6e82cd8cSTejas Patel [65] = XPM_NODEIDX_DEV_ADMA_5, 91*6e82cd8cSTejas Patel [66] = XPM_NODEIDX_DEV_ADMA_6, 92*6e82cd8cSTejas Patel [67] = XPM_NODEIDX_DEV_ADMA_7, 93*6e82cd8cSTejas Patel [74] = XPM_NODEIDX_DEV_USB_0, 94*6e82cd8cSTejas Patel [126] = XPM_NODEIDX_DEV_SDIO_0, 95*6e82cd8cSTejas Patel [127] = XPM_NODEIDX_DEV_SDIO_0, 96*6e82cd8cSTejas Patel [128] = XPM_NODEIDX_DEV_SDIO_1, 97*6e82cd8cSTejas Patel [129] = XPM_NODEIDX_DEV_SDIO_1, 98*6e82cd8cSTejas Patel [142] = XPM_NODEIDX_DEV_RTC, 99*6e82cd8cSTejas Patel }; 100*6e82cd8cSTejas Patel 101*6e82cd8cSTejas Patel /** 102*6e82cd8cSTejas Patel * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number 103*6e82cd8cSTejas Patel * @irq: Interrupt number 104*6e82cd8cSTejas Patel * 105*6e82cd8cSTejas Patel * Return: PM node index corresponding to the specified interrupt 106*6e82cd8cSTejas Patel */ 107*6e82cd8cSTejas Patel static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq) 108*6e82cd8cSTejas Patel { 109*6e82cd8cSTejas Patel assert(irq <= IRQ_MAX); 110*6e82cd8cSTejas Patel return irq_node_map[irq]; 111*6e82cd8cSTejas Patel } 112*6e82cd8cSTejas Patel 113*6e82cd8cSTejas Patel /** 114*6e82cd8cSTejas Patel * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as 115*6e82cd8cSTejas Patel * wake sources in the LibPM. 116*6e82cd8cSTejas Patel */ 117*6e82cd8cSTejas Patel static void pm_client_set_wakeup_sources(void) 118*6e82cd8cSTejas Patel { 119*6e82cd8cSTejas Patel uint32_t reg_num; 120*6e82cd8cSTejas Patel uint32_t device_id; 121*6e82cd8cSTejas Patel uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX]; 122*6e82cd8cSTejas Patel uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4; 123*6e82cd8cSTejas Patel 124*6e82cd8cSTejas Patel zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set)); 125*6e82cd8cSTejas Patel 126*6e82cd8cSTejas Patel for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) { 127*6e82cd8cSTejas Patel uint32_t base_irq = reg_num << ISENABLER_SHIFT; 128*6e82cd8cSTejas Patel uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2)); 129*6e82cd8cSTejas Patel 130*6e82cd8cSTejas Patel if (!reg) 131*6e82cd8cSTejas Patel continue; 132*6e82cd8cSTejas Patel 133*6e82cd8cSTejas Patel while (reg) { 134*6e82cd8cSTejas Patel enum pm_device_node_idx node_idx; 135*6e82cd8cSTejas Patel uint32_t idx, ret, irq, lowest_set = reg & (-reg); 136*6e82cd8cSTejas Patel 137*6e82cd8cSTejas Patel idx = __builtin_ctz(lowest_set); 138*6e82cd8cSTejas Patel irq = base_irq + idx; 139*6e82cd8cSTejas Patel 140*6e82cd8cSTejas Patel if (irq > IRQ_MAX) 141*6e82cd8cSTejas Patel break; 142*6e82cd8cSTejas Patel 143*6e82cd8cSTejas Patel node_idx = irq_to_pm_node_idx(irq); 144*6e82cd8cSTejas Patel reg &= ~lowest_set; 145*6e82cd8cSTejas Patel 146*6e82cd8cSTejas Patel if ((node_idx != XPM_NODEIDX_DEV_MIN) && 147*6e82cd8cSTejas Patel (!pm_wakeup_nodes_set[node_idx])) { 148*6e82cd8cSTejas Patel /* Get device ID from node index */ 149*6e82cd8cSTejas Patel device_id = PERIPH_DEVID(node_idx); 150*6e82cd8cSTejas Patel ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0, 151*6e82cd8cSTejas Patel device_id, 1); 152*6e82cd8cSTejas Patel pm_wakeup_nodes_set[node_idx] = !ret; 153*6e82cd8cSTejas Patel } 154*6e82cd8cSTejas Patel } 155*6e82cd8cSTejas Patel } 156*6e82cd8cSTejas Patel } 157*6e82cd8cSTejas Patel 158fbb32695STejas Patel /** 159fbb32695STejas Patel * pm_client_suspend() - Client-specific suspend actions 160fbb32695STejas Patel * 161fbb32695STejas Patel * This function should contain any PU-specific actions 162fbb32695STejas Patel * required prior to sending suspend request to PMU 163fbb32695STejas Patel * Actions taken depend on the state system is suspending to. 164fbb32695STejas Patel */ 165fbb32695STejas Patel void pm_client_suspend(const struct pm_proc *proc, unsigned int state) 166fbb32695STejas Patel { 167fbb32695STejas Patel bakery_lock_get(&pm_client_secure_lock); 168fbb32695STejas Patel 169*6e82cd8cSTejas Patel if (state == PM_STATE_SUSPEND_TO_RAM) 170*6e82cd8cSTejas Patel pm_client_set_wakeup_sources(); 171*6e82cd8cSTejas Patel 172fbb32695STejas Patel /* Set powerdown request */ 173fbb32695STejas Patel mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) | 174fbb32695STejas Patel proc->pwrdn_mask); 175fbb32695STejas Patel 176fbb32695STejas Patel bakery_lock_release(&pm_client_secure_lock); 177fbb32695STejas Patel } 178fbb32695STejas Patel 179fbb32695STejas Patel /** 180fbb32695STejas Patel * pm_client_abort_suspend() - Client-specific abort-suspend actions 181fbb32695STejas Patel * 182fbb32695STejas Patel * This function should contain any PU-specific actions 183fbb32695STejas Patel * required for aborting a prior suspend request 184fbb32695STejas Patel */ 185fbb32695STejas Patel void pm_client_abort_suspend(void) 186fbb32695STejas Patel { 187fbb32695STejas Patel /* Enable interrupts at processor level (for current cpu) */ 188fbb32695STejas Patel gicv3_cpuif_enable(plat_my_core_pos()); 189fbb32695STejas Patel 190fbb32695STejas Patel bakery_lock_get(&pm_client_secure_lock); 191fbb32695STejas Patel 192fbb32695STejas Patel /* Clear powerdown request */ 193fbb32695STejas Patel mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) & 194fbb32695STejas Patel ~primary_proc->pwrdn_mask); 195fbb32695STejas Patel 196fbb32695STejas Patel bakery_lock_release(&pm_client_secure_lock); 197fbb32695STejas Patel } 198fbb32695STejas Patel 199fbb32695STejas Patel /** 20025b1a910STejas Patel * pm_get_cpuid() - get the local cpu ID for a global node ID 20125b1a910STejas Patel * @nid: node id of the processor 20225b1a910STejas Patel * 20325b1a910STejas Patel * Return: the cpu ID (starting from 0) for the subsystem 20425b1a910STejas Patel */ 20525b1a910STejas Patel static unsigned int pm_get_cpuid(uint32_t nid) 20625b1a910STejas Patel { 20725b1a910STejas Patel for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { 20825b1a910STejas Patel if (pm_procs_all[i].node_id == nid) 20925b1a910STejas Patel return i; 21025b1a910STejas Patel } 21125b1a910STejas Patel return UNDEFINED_CPUID; 21225b1a910STejas Patel } 21325b1a910STejas Patel 21425b1a910STejas Patel /** 21525b1a910STejas Patel * pm_client_wakeup() - Client-specific wakeup actions 21625b1a910STejas Patel * 21725b1a910STejas Patel * This function should contain any PU-specific actions 21825b1a910STejas Patel * required for waking up another APU core 21925b1a910STejas Patel */ 22025b1a910STejas Patel void pm_client_wakeup(const struct pm_proc *proc) 22125b1a910STejas Patel { 22225b1a910STejas Patel unsigned int cpuid = pm_get_cpuid(proc->node_id); 22325b1a910STejas Patel 22425b1a910STejas Patel if (cpuid == UNDEFINED_CPUID) 22525b1a910STejas Patel return; 22625b1a910STejas Patel 22725b1a910STejas Patel bakery_lock_get(&pm_client_secure_lock); 22825b1a910STejas Patel 22925b1a910STejas Patel /* clear powerdown bit for affected cpu */ 23025b1a910STejas Patel uint32_t val = mmio_read_32(FPD_APU_PWRCTL); 23125b1a910STejas Patel val &= ~(proc->pwrdn_mask); 23225b1a910STejas Patel mmio_write_32(FPD_APU_PWRCTL, val); 23325b1a910STejas Patel 23425b1a910STejas Patel bakery_lock_release(&pm_client_secure_lock); 23525b1a910STejas Patel } 23625b1a910STejas Patel 23725b1a910STejas Patel /** 238fbb32695STejas Patel * pm_get_proc() - returns pointer to the proc structure 239fbb32695STejas Patel * @cpuid: id of the cpu whose proc struct pointer should be returned 240fbb32695STejas Patel * 241fbb32695STejas Patel * Return: pointer to a proc structure if proc is found, otherwise NULL 242fbb32695STejas Patel */ 243fbb32695STejas Patel const struct pm_proc *pm_get_proc(unsigned int cpuid) 244fbb32695STejas Patel { 245fbb32695STejas Patel if (cpuid < ARRAY_SIZE(pm_procs_all)) 246fbb32695STejas Patel return &pm_procs_all[cpuid]; 247fbb32695STejas Patel 248fbb32695STejas Patel return NULL; 249fbb32695STejas Patel } 250