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