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

pm24xx.c (7947B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * OMAP2 Power Management Routines
      4 *
      5 * Copyright (C) 2005 Texas Instruments, Inc.
      6 * Copyright (C) 2006-2008 Nokia Corporation
      7 *
      8 * Written by:
      9 * Richard Woodruff <r-woodruff2@ti.com>
     10 * Tony Lindgren
     11 * Juha Yrjola
     12 * Amit Kucheria <amit.kucheria@nokia.com>
     13 * Igor Stoppa <igor.stoppa@nokia.com>
     14 *
     15 * Based on pm.c for omap1
     16 */
     17
     18#include <linux/cpu_pm.h>
     19#include <linux/suspend.h>
     20#include <linux/sched.h>
     21#include <linux/proc_fs.h>
     22#include <linux/interrupt.h>
     23#include <linux/sysfs.h>
     24#include <linux/module.h>
     25#include <linux/delay.h>
     26#include <linux/clk.h>
     27#include <linux/clk-provider.h>
     28#include <linux/irq.h>
     29#include <linux/time.h>
     30
     31#include <asm/fncpy.h>
     32
     33#include <asm/mach/time.h>
     34#include <asm/mach/irq.h>
     35#include <asm/mach-types.h>
     36#include <asm/system_misc.h>
     37
     38#include <linux/omap-dma.h>
     39
     40#include "soc.h"
     41#include "common.h"
     42#include "clock.h"
     43#include "prm2xxx.h"
     44#include "prm-regbits-24xx.h"
     45#include "cm2xxx.h"
     46#include "cm-regbits-24xx.h"
     47#include "sdrc.h"
     48#include "sram.h"
     49#include "pm.h"
     50#include "control.h"
     51#include "powerdomain.h"
     52#include "clockdomain.h"
     53
     54static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
     55				  void __iomem *sdrc_power);
     56
     57static struct powerdomain *mpu_pwrdm, *core_pwrdm;
     58static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
     59
     60static struct clk *osc_ck, *emul_ck;
     61
     62static int omap2_enter_full_retention(void)
     63{
     64	u32 l;
     65
     66	/* There is 1 reference hold for all children of the oscillator
     67	 * clock, the following will remove it. If no one else uses the
     68	 * oscillator itself it will be disabled if/when we enter retention
     69	 * mode.
     70	 */
     71	clk_disable(osc_ck);
     72
     73	/* Clear old wake-up events */
     74	/* REVISIT: These write to reserved bits? */
     75	omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
     76	omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
     77	omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
     78
     79	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
     80	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
     81
     82	/* Workaround to kill USB */
     83	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
     84	omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
     85
     86	/* One last check for pending IRQs to avoid extra latency due
     87	 * to sleeping unnecessarily. */
     88	if (omap_irq_pending())
     89		goto no_sleep;
     90
     91	/* Jump to SRAM suspend code */
     92	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
     93			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
     94			   OMAP_SDRC_REGADDR(SDRC_POWER));
     95
     96no_sleep:
     97	clk_enable(osc_ck);
     98
     99	/* clear CORE wake-up events */
    100	omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
    101	omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
    102
    103	/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
    104	omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, 0x4 | 0x1);
    105
    106	/* MPU domain wake events */
    107	omap_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET, 0x1);
    108
    109	omap_prm_clear_mod_irqs(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET, 0x20);
    110
    111	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
    112	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
    113
    114	return 0;
    115}
    116
    117static int sti_console_enabled;
    118
    119static int omap2_allow_mpu_retention(void)
    120{
    121	if (!omap2xxx_cm_mpu_retention_allowed())
    122		return 0;
    123	if (sti_console_enabled)
    124		return 0;
    125
    126	return 1;
    127}
    128
    129static void omap2_enter_mpu_retention(void)
    130{
    131	const int zero = 0;
    132
    133	/* The peripherals seem not to be able to wake up the MPU when
    134	 * it is in retention mode. */
    135	if (omap2_allow_mpu_retention()) {
    136		/* REVISIT: These write to reserved bits? */
    137		omap_prm_clear_mod_irqs(CORE_MOD, PM_WKST1, ~0);
    138		omap_prm_clear_mod_irqs(CORE_MOD, OMAP24XX_PM_WKST2, ~0);
    139		omap_prm_clear_mod_irqs(WKUP_MOD, PM_WKST, ~0);
    140
    141		/* Try to enter MPU retention */
    142		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
    143
    144	} else {
    145		/* Block MPU retention */
    146		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
    147	}
    148
    149	/* WFI */
    150	asm("mcr p15, 0, %0, c7, c0, 4" : : "r" (zero) : "memory", "cc");
    151
    152	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
    153}
    154
    155static int omap2_can_sleep(void)
    156{
    157	if (omap2xxx_cm_fclks_active())
    158		return 0;
    159	if (__clk_is_enabled(osc_ck))
    160		return 0;
    161
    162	return 1;
    163}
    164
    165static void omap2_pm_idle(void)
    166{
    167	int error;
    168
    169	if (omap_irq_pending())
    170		return;
    171
    172	error = cpu_cluster_pm_enter();
    173	if (error || !omap2_can_sleep()) {
    174		omap2_enter_mpu_retention();
    175		goto out_cpu_cluster_pm;
    176	}
    177
    178	omap2_enter_full_retention();
    179
    180out_cpu_cluster_pm:
    181	cpu_cluster_pm_exit();
    182}
    183
    184static void __init prcm_setup_regs(void)
    185{
    186	int i, num_mem_banks;
    187	struct powerdomain *pwrdm;
    188
    189	/*
    190	 * Enable autoidle
    191	 * XXX This should be handled by hwmod code or PRCM init code
    192	 */
    193	omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
    194			  OMAP2_PRCM_SYSCONFIG_OFFSET);
    195
    196	/*
    197	 * Set CORE powerdomain memory banks to retain their contents
    198	 * during RETENTION
    199	 */
    200	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
    201	for (i = 0; i < num_mem_banks; i++)
    202		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
    203
    204	pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET);
    205
    206	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
    207
    208	/* Force-power down DSP, GFX powerdomains */
    209
    210	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
    211	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
    212
    213	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
    214	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
    215
    216	/* Enable hardware-supervised idle for all clkdms */
    217	clkdm_for_each(omap_pm_clkdms_setup, NULL);
    218	clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
    219
    220	omap_common_suspend_init(omap2_enter_full_retention);
    221
    222	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
    223	 * stabilisation */
    224	omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
    225				OMAP2_PRCM_CLKSSETUP_OFFSET);
    226
    227	/* Configure automatic voltage transition */
    228	omap2_prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
    229				OMAP2_PRCM_VOLTSETUP_OFFSET);
    230	omap2_prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT_MASK |
    231				(0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
    232				OMAP24XX_MEMRETCTRL_MASK |
    233				(0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
    234				(0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
    235				OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
    236
    237	/* Enable wake-up events */
    238	omap2_prm_write_mod_reg(OMAP24XX_EN_GPIOS_MASK | OMAP24XX_EN_GPT1_MASK,
    239				WKUP_MOD, PM_WKEN);
    240
    241	/* Enable SYS_CLKEN control when all domains idle */
    242	omap2_prm_set_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, OMAP24XX_GR_MOD,
    243				   OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
    244}
    245
    246int __init omap2_pm_init(void)
    247{
    248	u32 l;
    249
    250	printk(KERN_INFO "Power Management for OMAP2 initializing\n");
    251	l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
    252	printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
    253
    254	/* Look up important powerdomains */
    255
    256	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
    257	if (!mpu_pwrdm)
    258		pr_err("PM: mpu_pwrdm not found\n");
    259
    260	core_pwrdm = pwrdm_lookup("core_pwrdm");
    261	if (!core_pwrdm)
    262		pr_err("PM: core_pwrdm not found\n");
    263
    264	/* Look up important clockdomains */
    265
    266	mpu_clkdm = clkdm_lookup("mpu_clkdm");
    267	if (!mpu_clkdm)
    268		pr_err("PM: mpu_clkdm not found\n");
    269
    270	wkup_clkdm = clkdm_lookup("wkup_clkdm");
    271	if (!wkup_clkdm)
    272		pr_err("PM: wkup_clkdm not found\n");
    273
    274	dsp_clkdm = clkdm_lookup("dsp_clkdm");
    275	if (!dsp_clkdm)
    276		pr_err("PM: dsp_clkdm not found\n");
    277
    278	gfx_clkdm = clkdm_lookup("gfx_clkdm");
    279	if (!gfx_clkdm)
    280		pr_err("PM: gfx_clkdm not found\n");
    281
    282
    283	osc_ck = clk_get(NULL, "osc_ck");
    284	if (IS_ERR(osc_ck)) {
    285		printk(KERN_ERR "could not get osc_ck\n");
    286		return -ENODEV;
    287	}
    288
    289	if (cpu_is_omap242x()) {
    290		emul_ck = clk_get(NULL, "emul_ck");
    291		if (IS_ERR(emul_ck)) {
    292			printk(KERN_ERR "could not get emul_ck\n");
    293			clk_put(osc_ck);
    294			return -ENODEV;
    295		}
    296	}
    297
    298	prcm_setup_regs();
    299
    300	/*
    301	 * We copy the assembler sleep/wakeup routines to SRAM.
    302	 * These routines need to be in SRAM as that's the only
    303	 * memory the MPU can see when it wakes up after the entire
    304	 * chip enters idle.
    305	 */
    306	omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
    307					    omap24xx_cpu_suspend_sz);
    308
    309	arm_pm_idle = omap2_pm_idle;
    310
    311	return 0;
    312}