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

mpc52xx_pm.c (5442B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/init.h>
      3#include <linux/suspend.h>
      4#include <linux/io.h>
      5#include <linux/of_address.h>
      6
      7#include <asm/time.h>
      8#include <asm/cacheflush.h>
      9#include <asm/mpc52xx.h>
     10
     11/* these are defined in mpc52xx_sleep.S, and only used here */
     12extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
     13		struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
     14extern void mpc52xx_ds_sram(void);
     15extern const long mpc52xx_ds_sram_size;
     16extern void mpc52xx_ds_cached(void);
     17extern const long mpc52xx_ds_cached_size;
     18
     19static void __iomem *mbar;
     20static void __iomem *sdram;
     21static struct mpc52xx_cdm __iomem *cdm;
     22static struct mpc52xx_intr __iomem *intr;
     23static struct mpc52xx_gpio_wkup __iomem *gpiow;
     24static void __iomem *sram;
     25static int sram_size;
     26
     27struct mpc52xx_suspend mpc52xx_suspend;
     28
     29static int mpc52xx_pm_valid(suspend_state_t state)
     30{
     31	switch (state) {
     32	case PM_SUSPEND_STANDBY:
     33		return 1;
     34	default:
     35		return 0;
     36	}
     37}
     38
     39int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
     40{
     41	u16 tmp;
     42
     43	/* enable gpio */
     44	out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
     45	/* set as input */
     46	out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
     47	/* enable deep sleep interrupt */
     48	out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
     49	/* low/high level creates wakeup interrupt */
     50	tmp = in_be16(&gpiow->wkup_itype);
     51	tmp &= ~(0x3 << (pin * 2));
     52	tmp |= (!level + 1) << (pin * 2);
     53	out_be16(&gpiow->wkup_itype, tmp);
     54	/* master enable */
     55	out_8(&gpiow->wkup_maste, 1);
     56
     57	return 0;
     58}
     59
     60int mpc52xx_pm_prepare(void)
     61{
     62	struct device_node *np;
     63	const struct of_device_id immr_ids[] = {
     64		{ .compatible = "fsl,mpc5200-immr", },
     65		{ .compatible = "fsl,mpc5200b-immr", },
     66		{ .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
     67		{ .type = "builtin", .compatible = "mpc5200", }, /* efika */
     68		{}
     69	};
     70	struct resource res;
     71
     72	/* map the whole register space */
     73	np = of_find_matching_node(NULL, immr_ids);
     74
     75	if (of_address_to_resource(np, 0, &res)) {
     76		pr_err("mpc52xx_pm_prepare(): could not get IMMR address\n");
     77		of_node_put(np);
     78		return -ENOSYS;
     79	}
     80
     81	mbar = ioremap(res.start, 0xc000); /* we should map whole region including SRAM */
     82
     83	of_node_put(np);
     84	if (!mbar) {
     85		pr_err("mpc52xx_pm_prepare(): could not map registers\n");
     86		return -ENOSYS;
     87	}
     88	/* these offsets are from mpc5200 users manual */
     89	sdram	= mbar + 0x100;
     90	cdm	= mbar + 0x200;
     91	intr	= mbar + 0x500;
     92	gpiow	= mbar + 0xc00;
     93	sram	= mbar + 0x8000;	/* Those will be handled by the */
     94	sram_size = 0x4000;		/* bestcomm driver soon */
     95
     96	/* call board suspend code, if applicable */
     97	if (mpc52xx_suspend.board_suspend_prepare)
     98		mpc52xx_suspend.board_suspend_prepare(mbar);
     99	else {
    100		printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
    101				__func__, __LINE__);
    102		goto out_unmap;
    103	}
    104
    105	return 0;
    106
    107 out_unmap:
    108	iounmap(mbar);
    109	return -ENOSYS;
    110}
    111
    112
    113char saved_sram[0x4000];
    114
    115int mpc52xx_pm_enter(suspend_state_t state)
    116{
    117	u32 clk_enables;
    118	u32 msr, hid0;
    119	u32 intr_main_mask;
    120	void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500;
    121	unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
    122	char saved_0x500[0x600-0x500];
    123
    124	if (WARN_ON(mpc52xx_ds_cached_size > sizeof(saved_0x500)))
    125		return -ENOMEM;
    126
    127	/* disable all interrupts in PIC */
    128	intr_main_mask = in_be32(&intr->main_mask);
    129	out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
    130
    131	/* don't let DEC expire any time soon */
    132	mtspr(SPRN_DEC, 0x7fffffff);
    133
    134	/* save SRAM */
    135	memcpy(saved_sram, sram, sram_size);
    136
    137	/* copy low level suspend code to sram */
    138	memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
    139
    140	out_8(&cdm->ccs_sleep_enable, 1);
    141	out_8(&cdm->osc_sleep_enable, 1);
    142	out_8(&cdm->ccs_qreq_test, 1);
    143
    144	/* disable all but SDRAM and bestcomm (SRAM) clocks */
    145	clk_enables = in_be32(&cdm->clk_enables);
    146	out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
    147
    148	/* disable power management */
    149	msr = mfmsr();
    150	mtmsr(msr & ~MSR_POW);
    151
    152	/* enable sleep mode, disable others */
    153	hid0 = mfspr(SPRN_HID0);
    154	mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
    155
    156	/* save original, copy our irq handler, flush from dcache and invalidate icache */
    157	memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
    158	memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
    159	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
    160
    161	/* call low-level sleep code */
    162	mpc52xx_deep_sleep(sram, sdram, cdm, intr);
    163
    164	/* restore original irq handler */
    165	memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
    166	flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
    167
    168	/* restore old power mode */
    169	mtmsr(msr & ~MSR_POW);
    170	mtspr(SPRN_HID0, hid0);
    171	mtmsr(msr);
    172
    173	out_be32(&cdm->clk_enables, clk_enables);
    174	out_8(&cdm->ccs_sleep_enable, 0);
    175	out_8(&cdm->osc_sleep_enable, 0);
    176
    177	/* restore SRAM */
    178	memcpy(sram, saved_sram, sram_size);
    179
    180	/* reenable interrupts in PIC */
    181	out_be32(&intr->main_mask, intr_main_mask);
    182
    183	return 0;
    184}
    185
    186void mpc52xx_pm_finish(void)
    187{
    188	/* call board resume code */
    189	if (mpc52xx_suspend.board_resume_finish)
    190		mpc52xx_suspend.board_resume_finish(mbar);
    191
    192	iounmap(mbar);
    193}
    194
    195static const struct platform_suspend_ops mpc52xx_pm_ops = {
    196	.valid		= mpc52xx_pm_valid,
    197	.prepare	= mpc52xx_pm_prepare,
    198	.enter		= mpc52xx_pm_enter,
    199	.finish		= mpc52xx_pm_finish,
    200};
    201
    202int __init mpc52xx_pm_init(void)
    203{
    204	suspend_set_ops(&mpc52xx_pm_ops);
    205	return 0;
    206}