cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm-mmp2.c (5729B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * MMP2 Power Management Routines
      4 *
      5 * (C) Copyright 2012 Marvell International Ltd.
      6 * All Rights Reserved
      7 */
      8
      9#include <linux/kernel.h>
     10#include <linux/errno.h>
     11#include <linux/err.h>
     12#include <linux/time.h>
     13#include <linux/delay.h>
     14#include <linux/suspend.h>
     15#include <linux/irq.h>
     16#include <linux/io.h>
     17#include <linux/interrupt.h>
     18#include <asm/mach-types.h>
     19
     20#include <linux/soc/mmp/cputype.h>
     21#include "addr-map.h"
     22#include "pm-mmp2.h"
     23#include "regs-icu.h"
     24#include "irqs.h"
     25
     26int mmp2_set_wake(struct irq_data *d, unsigned int on)
     27{
     28	unsigned long data = 0;
     29	int irq = d->irq;
     30
     31	/* enable wakeup sources */
     32	switch (irq) {
     33	case IRQ_MMP2_RTC:
     34	case IRQ_MMP2_RTC_ALARM:
     35		data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
     36		break;
     37	case IRQ_MMP2_PMIC:
     38		data = MPMU_WUCRM_PJ_WAKEUP(7);
     39		break;
     40	case IRQ_MMP2_MMC2:
     41		/* mmc use WAKEUP2, same as GPIO wakeup source */
     42		data = MPMU_WUCRM_PJ_WAKEUP(2);
     43		break;
     44	}
     45	if (on) {
     46		if (data) {
     47			data |= __raw_readl(MPMU_WUCRM_PJ);
     48			__raw_writel(data, MPMU_WUCRM_PJ);
     49		}
     50	} else {
     51		if (data) {
     52			data = ~data & __raw_readl(MPMU_WUCRM_PJ);
     53			__raw_writel(data, MPMU_WUCRM_PJ);
     54		}
     55	}
     56	return 0;
     57}
     58
     59static void pm_scu_clk_disable(void)
     60{
     61	unsigned int val;
     62
     63	/* close AXI fabric clock gate */
     64	__raw_writel(0x0, CIU_REG(0x64));
     65	__raw_writel(0x0, CIU_REG(0x68));
     66
     67	/* close MCB master clock gate */
     68	val = __raw_readl(CIU_REG(0x1c));
     69	val |= 0xf0;
     70	__raw_writel(val, CIU_REG(0x1c));
     71
     72	return ;
     73}
     74
     75static void pm_scu_clk_enable(void)
     76{
     77	unsigned int val;
     78
     79	/* open AXI fabric clock gate */
     80	__raw_writel(0x03003003, CIU_REG(0x64));
     81	__raw_writel(0x00303030, CIU_REG(0x68));
     82
     83	/* open MCB master clock gate */
     84	val = __raw_readl(CIU_REG(0x1c));
     85	val &= ~(0xf0);
     86	__raw_writel(val, CIU_REG(0x1c));
     87
     88	return ;
     89}
     90
     91static void pm_mpmu_clk_disable(void)
     92{
     93	/*
     94	 * disable clocks in MPMU_CGR_PJ register
     95	 * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
     96	 */
     97	__raw_writel(0x0000a010, MPMU_CGR_PJ);
     98}
     99
    100static void pm_mpmu_clk_enable(void)
    101{
    102	unsigned int val;
    103
    104	__raw_writel(0xdffefffe, MPMU_CGR_PJ);
    105	val = __raw_readl(MPMU_PLL2_CTRL1);
    106	val |= (1 << 29);
    107	__raw_writel(val, MPMU_PLL2_CTRL1);
    108
    109	return ;
    110}
    111
    112void mmp2_pm_enter_lowpower_mode(int state)
    113{
    114	uint32_t idle_cfg, apcr;
    115
    116	idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
    117	apcr = __raw_readl(MPMU_PCR_PJ);
    118	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
    119		 | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
    120	idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
    121
    122	switch (state) {
    123	case POWER_MODE_SYS_SLEEP:
    124		apcr |= MPMU_PCR_PJ_SLPEN;		/* set the SLPEN bit */
    125		apcr |= MPMU_PCR_PJ_VCTCXOSD;		/* set VCTCXOSD */
    126		fallthrough;
    127	case POWER_MODE_CHIP_SLEEP:
    128		apcr |= MPMU_PCR_PJ_SLPEN;
    129		fallthrough;
    130	case POWER_MODE_APPS_SLEEP:
    131		apcr |= MPMU_PCR_PJ_APBSD;		/* set APBSD */
    132		fallthrough;
    133	case POWER_MODE_APPS_IDLE:
    134		apcr |= MPMU_PCR_PJ_AXISD;		/* set AXISDD bit */
    135		apcr |= MPMU_PCR_PJ_DDRCORSD;		/* set DDRCORSD bit */
    136		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN;	/* PJ power down */
    137		apcr |= MPMU_PCR_PJ_SPSD;
    138		fallthrough;
    139	case POWER_MODE_CORE_EXTIDLE:
    140		idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE;	/* set the IDLE bit */
    141		idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
    142		idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
    143			| APMU_PJ_IDLE_CFG_L2_PWR_SW;
    144		break;
    145	case POWER_MODE_CORE_INTIDLE:
    146		apcr &= ~MPMU_PCR_PJ_SPSD;
    147		break;
    148	}
    149
    150	/* set reserve bits */
    151	apcr |= (1 << 30) | (1 << 25);
    152
    153	/* finally write the registers back */
    154	__raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
    155	__raw_writel(apcr, MPMU_PCR_PJ);	/* 0xfe086000 */
    156}
    157
    158static int mmp2_pm_enter(suspend_state_t state)
    159{
    160	int temp;
    161
    162	temp = __raw_readl(MMP2_ICU_INT4_MASK);
    163	if (temp & (1 << 1)) {
    164		printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
    165		return -EAGAIN;
    166	}
    167
    168	temp = __raw_readl(APMU_SRAM_PWR_DWN);
    169	temp |= ((1 << 19) | (1 << 18));
    170	__raw_writel(temp, APMU_SRAM_PWR_DWN);
    171	pm_mpmu_clk_disable();
    172	pm_scu_clk_disable();
    173
    174	printk(KERN_INFO "%s: before suspend\n", __func__);
    175	cpu_do_idle();
    176	printk(KERN_INFO "%s: after suspend\n", __func__);
    177
    178	pm_mpmu_clk_enable();		/* enable clocks in MPMU */
    179	pm_scu_clk_enable();		/* enable clocks in SCU */
    180
    181	return 0;
    182}
    183
    184/*
    185 * Called after processes are frozen, but before we shut down devices.
    186 */
    187static int mmp2_pm_prepare(void)
    188{
    189	mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
    190
    191	return 0;
    192}
    193
    194/*
    195 * Called after devices are re-setup, but before processes are thawed.
    196 */
    197static void mmp2_pm_finish(void)
    198{
    199	mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
    200}
    201
    202static int mmp2_pm_valid(suspend_state_t state)
    203{
    204	return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
    205}
    206
    207/*
    208 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
    209 */
    210static const struct platform_suspend_ops mmp2_pm_ops = {
    211	.valid		= mmp2_pm_valid,
    212	.prepare	= mmp2_pm_prepare,
    213	.enter		= mmp2_pm_enter,
    214	.finish		= mmp2_pm_finish,
    215};
    216
    217static int __init mmp2_pm_init(void)
    218{
    219	uint32_t apcr;
    220
    221	if (!cpu_is_mmp2())
    222		return -EIO;
    223
    224	suspend_set_ops(&mmp2_pm_ops);
    225
    226	/*
    227	 * Set bit 0, Slow clock Select 32K clock input instead of VCXO
    228	 * VCXO is chosen by default, which would be disabled in suspend
    229	 */
    230	__raw_writel(0x5, MPMU_SCCR);
    231
    232	/*
    233	 * Clear bit 23 of CIU_CPU_CONF
    234	 * direct PJ4 to DDR access through Memory Controller slow queue
    235	 * fast queue has issue and cause lcd will flick
    236	 */
    237	__raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
    238
    239	/* Clear default low power control bit */
    240	apcr = __raw_readl(MPMU_PCR_PJ);
    241	apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
    242			| MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
    243	__raw_writel(apcr, MPMU_PCR_PJ);
    244
    245	return 0;
    246}
    247
    248late_initcall(mmp2_pm_init);