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