linux/arch/powerpc/platforms/52xx/lite5200_pm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/init.h>
   3#include <linux/suspend.h>
   4#include <asm/io.h>
   5#include <asm/time.h>
   6#include <asm/mpc52xx.h>
   7#include <asm/switch_to.h>
   8
   9/* defined in lite5200_sleep.S and only used here */
  10extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);
  11
  12static struct mpc52xx_cdm __iomem *cdm;
  13static struct mpc52xx_intr __iomem *pic;
  14static struct mpc52xx_sdma __iomem *bes;
  15static struct mpc52xx_xlb __iomem *xlb;
  16static struct mpc52xx_gpio __iomem *gps;
  17static struct mpc52xx_gpio_wkup __iomem *gpw;
  18static void __iomem *pci;
  19static void __iomem *sram;
  20static const int sram_size = 0x4000;    /* 16 kBytes */
  21static void __iomem *mbar;
  22
  23static suspend_state_t lite5200_pm_target_state;
  24
  25static int lite5200_pm_valid(suspend_state_t state)
  26{
  27        switch (state) {
  28        case PM_SUSPEND_STANDBY:
  29        case PM_SUSPEND_MEM:
  30                return 1;
  31        default:
  32                return 0;
  33        }
  34}
  35
  36static int lite5200_pm_begin(suspend_state_t state)
  37{
  38        if (lite5200_pm_valid(state)) {
  39                lite5200_pm_target_state = state;
  40                return 0;
  41        }
  42        return -EINVAL;
  43}
  44
  45static int lite5200_pm_prepare(void)
  46{
  47        struct device_node *np;
  48        const struct of_device_id immr_ids[] = {
  49                { .compatible = "fsl,mpc5200-immr", },
  50                { .compatible = "fsl,mpc5200b-immr", },
  51                { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
  52                { .type = "builtin", .compatible = "mpc5200", }, /* efika */
  53                {}
  54        };
  55        u64 regaddr64 = 0;
  56        const u32 *regaddr_p;
  57
  58        /* deep sleep? let mpc52xx code handle that */
  59        if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)
  60                return mpc52xx_pm_prepare();
  61
  62        if (lite5200_pm_target_state != PM_SUSPEND_MEM)
  63                return -EINVAL;
  64
  65        /* map registers */
  66        np = of_find_matching_node(NULL, immr_ids);
  67        regaddr_p = of_get_address(np, 0, NULL, NULL);
  68        if (regaddr_p)
  69                regaddr64 = of_translate_address(np, regaddr_p);
  70        of_node_put(np);
  71
  72        mbar = ioremap((u32) regaddr64, 0xC000);
  73        if (!mbar) {
  74                printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
  75                return -ENOSYS;
  76        }
  77
  78        cdm = mbar + 0x200;
  79        pic = mbar + 0x500;
  80        gps = mbar + 0xb00;
  81        gpw = mbar + 0xc00;
  82        pci = mbar + 0xd00;
  83        bes = mbar + 0x1200;
  84        xlb = mbar + 0x1f00;
  85        sram = mbar + 0x8000;
  86
  87        return 0;
  88}
  89
  90/* save and restore registers not bound to any real devices */
  91static struct mpc52xx_cdm scdm;
  92static struct mpc52xx_intr spic;
  93static struct mpc52xx_sdma sbes;
  94static struct mpc52xx_xlb sxlb;
  95static struct mpc52xx_gpio sgps;
  96static struct mpc52xx_gpio_wkup sgpw;
  97static char spci[0x200];
  98
  99static void lite5200_save_regs(void)
 100{
 101        _memcpy_fromio(&spic, pic, sizeof(*pic));
 102        _memcpy_fromio(&sbes, bes, sizeof(*bes));
 103        _memcpy_fromio(&scdm, cdm, sizeof(*cdm));
 104        _memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
 105        _memcpy_fromio(&sgps, gps, sizeof(*gps));
 106        _memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
 107        _memcpy_fromio(spci, pci, 0x200);
 108
 109        _memcpy_fromio(saved_sram, sram, sram_size);
 110}
 111
 112static void lite5200_restore_regs(void)
 113{
 114        int i;
 115        _memcpy_toio(sram, saved_sram, sram_size);
 116
 117        /* PCI Configuration */
 118        _memcpy_toio(pci, spci, 0x200);
 119
 120        /*
 121         * GPIOs. Interrupt Master Enable has higher address then other
 122         * registers, so just memcpy is ok.
 123         */
 124        _memcpy_toio(gpw, &sgpw, sizeof(*gpw));
 125        _memcpy_toio(gps, &sgps, sizeof(*gps));
 126
 127
 128        /* XLB Arbitrer */
 129        out_be32(&xlb->snoop_window, sxlb.snoop_window);
 130        out_be32(&xlb->master_priority, sxlb.master_priority);
 131        out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable);
 132
 133        /* enable */
 134        out_be32(&xlb->int_enable, sxlb.int_enable);
 135        out_be32(&xlb->config, sxlb.config);
 136
 137
 138        /* CDM - Clock Distribution Module */
 139        out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel);
 140        out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel);
 141
 142        out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en);
 143        out_8(&cdm->fd_enable, scdm.fd_enable);
 144        out_be16(&cdm->fd_counters, scdm.fd_counters);
 145
 146        out_be32(&cdm->clk_enables, scdm.clk_enables);
 147
 148        out_8(&cdm->osc_disable, scdm.osc_disable);
 149
 150        out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1);
 151        out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2);
 152        out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3);
 153        out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6);
 154
 155
 156        /* BESTCOMM */
 157        out_be32(&bes->taskBar, sbes.taskBar);
 158        out_be32(&bes->currentPointer, sbes.currentPointer);
 159        out_be32(&bes->endPointer, sbes.endPointer);
 160        out_be32(&bes->variablePointer, sbes.variablePointer);
 161
 162        out_8(&bes->IntVect1, sbes.IntVect1);
 163        out_8(&bes->IntVect2, sbes.IntVect2);
 164        out_be16(&bes->PtdCntrl, sbes.PtdCntrl);
 165
 166        for (i=0; i<32; i++)
 167                out_8(&bes->ipr[i], sbes.ipr[i]);
 168
 169        out_be32(&bes->cReqSelect, sbes.cReqSelect);
 170        out_be32(&bes->task_size0, sbes.task_size0);
 171        out_be32(&bes->task_size1, sbes.task_size1);
 172        out_be32(&bes->MDEDebug, sbes.MDEDebug);
 173        out_be32(&bes->ADSDebug, sbes.ADSDebug);
 174        out_be32(&bes->Value1, sbes.Value1);
 175        out_be32(&bes->Value2, sbes.Value2);
 176        out_be32(&bes->Control, sbes.Control);
 177        out_be32(&bes->Status, sbes.Status);
 178        out_be32(&bes->PTDDebug, sbes.PTDDebug);
 179
 180        /* restore tasks */
 181        for (i=0; i<16; i++)
 182                out_be16(&bes->tcr[i], sbes.tcr[i]);
 183
 184        /* enable interrupts */
 185        out_be32(&bes->IntPend, sbes.IntPend);
 186        out_be32(&bes->IntMask, sbes.IntMask);
 187
 188
 189        /* PIC */
 190        out_be32(&pic->per_pri1, spic.per_pri1);
 191        out_be32(&pic->per_pri2, spic.per_pri2);
 192        out_be32(&pic->per_pri3, spic.per_pri3);
 193
 194        out_be32(&pic->main_pri1, spic.main_pri1);
 195        out_be32(&pic->main_pri2, spic.main_pri2);
 196
 197        out_be32(&pic->enc_status, spic.enc_status);
 198
 199        /* unmask and enable interrupts */
 200        out_be32(&pic->per_mask, spic.per_mask);
 201        out_be32(&pic->main_mask, spic.main_mask);
 202        out_be32(&pic->ctrl, spic.ctrl);
 203}
 204
 205static int lite5200_pm_enter(suspend_state_t state)
 206{
 207        /* deep sleep? let mpc52xx code handle that */
 208        if (state == PM_SUSPEND_STANDBY) {
 209                return mpc52xx_pm_enter(state);
 210        }
 211
 212        lite5200_save_regs();
 213
 214        /* effectively save FP regs */
 215        enable_kernel_fp();
 216
 217        lite5200_low_power(sram, mbar);
 218
 219        lite5200_restore_regs();
 220
 221        iounmap(mbar);
 222        return 0;
 223}
 224
 225static void lite5200_pm_finish(void)
 226{
 227        /* deep sleep? let mpc52xx code handle that */
 228        if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)
 229                mpc52xx_pm_finish();
 230}
 231
 232static void lite5200_pm_end(void)
 233{
 234        lite5200_pm_target_state = PM_SUSPEND_ON;
 235}
 236
 237static const struct platform_suspend_ops lite5200_pm_ops = {
 238        .valid          = lite5200_pm_valid,
 239        .begin          = lite5200_pm_begin,
 240        .prepare        = lite5200_pm_prepare,
 241        .enter          = lite5200_pm_enter,
 242        .finish         = lite5200_pm_finish,
 243        .end            = lite5200_pm_end,
 244};
 245
 246int __init lite5200_pm_init(void)
 247{
 248        suspend_set_ops(&lite5200_pm_ops);
 249        return 0;
 250}
 251