18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson SA 2010-2013 48c2ecf20Sopenharmony_ci * Author: Rickard Andersson <rickard.andersson@stericsson.com> for 58c2ecf20Sopenharmony_ci * ST-Ericsson. 68c2ecf20Sopenharmony_ci * Author: Daniel Lezcano <daniel.lezcano@linaro.org> for Linaro. 78c2ecf20Sopenharmony_ci * Author: Ulf Hansson <ulf.hansson@linaro.org> for Linaro. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/suspend.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/arm-ux500-pm.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "db8500-regs.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* ARM WFI Standby signal register */ 228c2ecf20Sopenharmony_ci#define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130) 238c2ecf20Sopenharmony_ci#define PRCM_ARM_WFI_STANDBY_WFI0 0x08 248c2ecf20Sopenharmony_ci#define PRCM_ARM_WFI_STANDBY_WFI1 0x10 258c2ecf20Sopenharmony_ci#define PRCM_IOCR (prcmu_base + 0x310) 268c2ecf20Sopenharmony_ci#define PRCM_IOCR_IOFORCE 0x1 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Dual A9 core interrupt management unit registers */ 298c2ecf20Sopenharmony_ci#define PRCM_A9_MASK_REQ (prcmu_base + 0x328) 308c2ecf20Sopenharmony_ci#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ 0x1 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define PRCM_A9_MASK_ACK (prcmu_base + 0x32c) 338c2ecf20Sopenharmony_ci#define PRCM_ARMITMSK31TO0 (prcmu_base + 0x11c) 348c2ecf20Sopenharmony_ci#define PRCM_ARMITMSK63TO32 (prcmu_base + 0x120) 358c2ecf20Sopenharmony_ci#define PRCM_ARMITMSK95TO64 (prcmu_base + 0x124) 368c2ecf20Sopenharmony_ci#define PRCM_ARMITMSK127TO96 (prcmu_base + 0x128) 378c2ecf20Sopenharmony_ci#define PRCM_POWER_STATE_VAL (prcmu_base + 0x25C) 388c2ecf20Sopenharmony_ci#define PRCM_ARMITVAL31TO0 (prcmu_base + 0x260) 398c2ecf20Sopenharmony_ci#define PRCM_ARMITVAL63TO32 (prcmu_base + 0x264) 408c2ecf20Sopenharmony_ci#define PRCM_ARMITVAL95TO64 (prcmu_base + 0x268) 418c2ecf20Sopenharmony_ci#define PRCM_ARMITVAL127TO96 (prcmu_base + 0x26C) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void __iomem *prcmu_base; 448c2ecf20Sopenharmony_cistatic void __iomem *dist_base; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* This function decouple the gic from the prcmu */ 478c2ecf20Sopenharmony_ciint prcmu_gic_decouple(void) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci u32 val = readl(PRCM_A9_MASK_REQ); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* Set bit 0 register value to 1 */ 528c2ecf20Sopenharmony_ci writel(val | PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, 538c2ecf20Sopenharmony_ci PRCM_A9_MASK_REQ); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Make sure the register is updated */ 568c2ecf20Sopenharmony_ci readl(PRCM_A9_MASK_REQ); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* Wait a few cycles for the gic mask completion */ 598c2ecf20Sopenharmony_ci udelay(1); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* This function recouple the gic with the prcmu */ 658c2ecf20Sopenharmony_ciint prcmu_gic_recouple(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci u32 val = readl(PRCM_A9_MASK_REQ); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Set bit 0 register value to 0 */ 708c2ecf20Sopenharmony_ci writel(val & ~PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ, PRCM_A9_MASK_REQ); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define PRCMU_GIC_NUMBER_REGS 5 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * This function checks if there are pending irq on the gic. It only 798c2ecf20Sopenharmony_ci * makes sense if the gic has been decoupled before with the 808c2ecf20Sopenharmony_ci * db8500_prcmu_gic_decouple function. Disabling an interrupt only 818c2ecf20Sopenharmony_ci * disables the forwarding of the interrupt to any CPU interface. It 828c2ecf20Sopenharmony_ci * does not prevent the interrupt from changing state, for example 838c2ecf20Sopenharmony_ci * becoming pending, or active and pending if it is already 848c2ecf20Sopenharmony_ci * active. Hence, we have to check the interrupt is pending *and* is 858c2ecf20Sopenharmony_ci * active. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cibool prcmu_gic_pending_irq(void) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci u32 pr; /* Pending register */ 908c2ecf20Sopenharmony_ci u32 er; /* Enable register */ 918c2ecf20Sopenharmony_ci int i; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 5 registers. STI & PPI not skipped */ 948c2ecf20Sopenharmony_ci for (i = 0; i < PRCMU_GIC_NUMBER_REGS; i++) { 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci pr = readl_relaxed(dist_base + GIC_DIST_PENDING_SET + i * 4); 978c2ecf20Sopenharmony_ci er = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (pr & er) 1008c2ecf20Sopenharmony_ci return true; /* There is a pending interrupt */ 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return false; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * This function checks if there are pending interrupt on the 1088c2ecf20Sopenharmony_ci * prcmu which has been delegated to monitor the irqs with the 1098c2ecf20Sopenharmony_ci * db8500_prcmu_copy_gic_settings function. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_cibool prcmu_pending_irq(void) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci u32 it, im; 1148c2ecf20Sopenharmony_ci int i; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) { 1178c2ecf20Sopenharmony_ci it = readl(PRCM_ARMITVAL31TO0 + i * 4); 1188c2ecf20Sopenharmony_ci im = readl(PRCM_ARMITMSK31TO0 + i * 4); 1198c2ecf20Sopenharmony_ci if (it & im) 1208c2ecf20Sopenharmony_ci return true; /* There is a pending interrupt */ 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return false; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * This function checks if the specified cpu is in in WFI. It's usage 1288c2ecf20Sopenharmony_ci * makes sense only if the gic is decoupled with the db8500_prcmu_gic_decouple 1298c2ecf20Sopenharmony_ci * function. Of course passing smp_processor_id() to this function will 1308c2ecf20Sopenharmony_ci * always return false... 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cibool prcmu_is_cpu_in_wfi(int cpu) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return readl(PRCM_ARM_WFI_STANDBY) & 1358c2ecf20Sopenharmony_ci (cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* 1398c2ecf20Sopenharmony_ci * This function copies the gic SPI settings to the prcmu in order to 1408c2ecf20Sopenharmony_ci * monitor them and abort/finish the retention/off sequence or state. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ciint prcmu_copy_gic_settings(void) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci u32 er; /* Enable register */ 1458c2ecf20Sopenharmony_ci int i; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* We skip the STI and PPI */ 1488c2ecf20Sopenharmony_ci for (i = 0; i < PRCMU_GIC_NUMBER_REGS - 1; i++) { 1498c2ecf20Sopenharmony_ci er = readl_relaxed(dist_base + 1508c2ecf20Sopenharmony_ci GIC_DIST_ENABLE_SET + (i + 1) * 4); 1518c2ecf20Sopenharmony_ci writel(er, PRCM_ARMITMSK31TO0 + i * 4); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#ifdef CONFIG_SUSPEND 1588c2ecf20Sopenharmony_cistatic int ux500_suspend_enter(suspend_state_t state) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci cpu_do_idle(); 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int ux500_suspend_valid(suspend_state_t state) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops ux500_suspend_ops = { 1708c2ecf20Sopenharmony_ci .enter = ux500_suspend_enter, 1718c2ecf20Sopenharmony_ci .valid = ux500_suspend_valid, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci#define UX500_SUSPEND_OPS (&ux500_suspend_ops) 1748c2ecf20Sopenharmony_ci#else 1758c2ecf20Sopenharmony_ci#define UX500_SUSPEND_OPS NULL 1768c2ecf20Sopenharmony_ci#endif 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_civoid __init ux500_pm_init(u32 phy_base, u32 size) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct device_node *np; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci prcmu_base = ioremap(phy_base, size); 1838c2ecf20Sopenharmony_ci if (!prcmu_base) { 1848c2ecf20Sopenharmony_ci pr_err("could not remap PRCMU for PM functions\n"); 1858c2ecf20Sopenharmony_ci return; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); 1888c2ecf20Sopenharmony_ci dist_base = of_iomap(np, 0); 1898c2ecf20Sopenharmony_ci of_node_put(np); 1908c2ecf20Sopenharmony_ci if (!dist_base) { 1918c2ecf20Sopenharmony_ci pr_err("could not remap GIC dist base for PM functions\n"); 1928c2ecf20Sopenharmony_ci return; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * On watchdog reboot the GIC is in some cases decoupled. 1978c2ecf20Sopenharmony_ci * This will make sure that the GIC is correctly configured. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci prcmu_gic_recouple(); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* Set up ux500 suspend callbacks. */ 2028c2ecf20Sopenharmony_ci suspend_set_ops(UX500_SUSPEND_OPS); 2038c2ecf20Sopenharmony_ci} 204