Path: blob/master/arch/powerpc/platforms/52xx/lite5200_pm.c
10818 views
#include <linux/init.h>1#include <linux/suspend.h>2#include <asm/io.h>3#include <asm/time.h>4#include <asm/mpc52xx.h>56/* defined in lite5200_sleep.S and only used here */7extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);89static struct mpc52xx_cdm __iomem *cdm;10static struct mpc52xx_intr __iomem *pic;11static struct mpc52xx_sdma __iomem *bes;12static struct mpc52xx_xlb __iomem *xlb;13static struct mpc52xx_gpio __iomem *gps;14static struct mpc52xx_gpio_wkup __iomem *gpw;15static void __iomem *pci;16static void __iomem *sram;17static const int sram_size = 0x4000; /* 16 kBytes */18static void __iomem *mbar;1920static suspend_state_t lite5200_pm_target_state;2122static int lite5200_pm_valid(suspend_state_t state)23{24switch (state) {25case PM_SUSPEND_STANDBY:26case PM_SUSPEND_MEM:27return 1;28default:29return 0;30}31}3233static int lite5200_pm_begin(suspend_state_t state)34{35if (lite5200_pm_valid(state)) {36lite5200_pm_target_state = state;37return 0;38}39return -EINVAL;40}4142static int lite5200_pm_prepare(void)43{44struct device_node *np;45const struct of_device_id immr_ids[] = {46{ .compatible = "fsl,mpc5200-immr", },47{ .compatible = "fsl,mpc5200b-immr", },48{ .type = "soc", .compatible = "mpc5200", }, /* lite5200 */49{ .type = "builtin", .compatible = "mpc5200", }, /* efika */50{}51};52u64 regaddr64 = 0;53const u32 *regaddr_p;5455/* deep sleep? let mpc52xx code handle that */56if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)57return mpc52xx_pm_prepare();5859if (lite5200_pm_target_state != PM_SUSPEND_MEM)60return -EINVAL;6162/* map registers */63np = of_find_matching_node(NULL, immr_ids);64regaddr_p = of_get_address(np, 0, NULL, NULL);65if (regaddr_p)66regaddr64 = of_translate_address(np, regaddr_p);67of_node_put(np);6869mbar = ioremap((u32) regaddr64, 0xC000);70if (!mbar) {71printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);72return -ENOSYS;73}7475cdm = mbar + 0x200;76pic = mbar + 0x500;77gps = mbar + 0xb00;78gpw = mbar + 0xc00;79pci = mbar + 0xd00;80bes = mbar + 0x1200;81xlb = mbar + 0x1f00;82sram = mbar + 0x8000;8384return 0;85}8687/* save and restore registers not bound to any real devices */88static struct mpc52xx_cdm scdm;89static struct mpc52xx_intr spic;90static struct mpc52xx_sdma sbes;91static struct mpc52xx_xlb sxlb;92static struct mpc52xx_gpio sgps;93static struct mpc52xx_gpio_wkup sgpw;94static char spci[0x200];9596static void lite5200_save_regs(void)97{98_memcpy_fromio(&spic, pic, sizeof(*pic));99_memcpy_fromio(&sbes, bes, sizeof(*bes));100_memcpy_fromio(&scdm, cdm, sizeof(*cdm));101_memcpy_fromio(&sxlb, xlb, sizeof(*xlb));102_memcpy_fromio(&sgps, gps, sizeof(*gps));103_memcpy_fromio(&sgpw, gpw, sizeof(*gpw));104_memcpy_fromio(spci, pci, 0x200);105106_memcpy_fromio(saved_sram, sram, sram_size);107}108109static void lite5200_restore_regs(void)110{111int i;112_memcpy_toio(sram, saved_sram, sram_size);113114/* PCI Configuration */115_memcpy_toio(pci, spci, 0x200);116117/*118* GPIOs. Interrupt Master Enable has higher address then other119* registers, so just memcpy is ok.120*/121_memcpy_toio(gpw, &sgpw, sizeof(*gpw));122_memcpy_toio(gps, &sgps, sizeof(*gps));123124125/* XLB Arbitrer */126out_be32(&xlb->snoop_window, sxlb.snoop_window);127out_be32(&xlb->master_priority, sxlb.master_priority);128out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable);129130/* enable */131out_be32(&xlb->int_enable, sxlb.int_enable);132out_be32(&xlb->config, sxlb.config);133134135/* CDM - Clock Distribution Module */136out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel);137out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel);138139out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en);140out_8(&cdm->fd_enable, scdm.fd_enable);141out_be16(&cdm->fd_counters, scdm.fd_counters);142143out_be32(&cdm->clk_enables, scdm.clk_enables);144145out_8(&cdm->osc_disable, scdm.osc_disable);146147out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1);148out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2);149out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3);150out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6);151152153/* BESTCOMM */154out_be32(&bes->taskBar, sbes.taskBar);155out_be32(&bes->currentPointer, sbes.currentPointer);156out_be32(&bes->endPointer, sbes.endPointer);157out_be32(&bes->variablePointer, sbes.variablePointer);158159out_8(&bes->IntVect1, sbes.IntVect1);160out_8(&bes->IntVect2, sbes.IntVect2);161out_be16(&bes->PtdCntrl, sbes.PtdCntrl);162163for (i=0; i<32; i++)164out_8(&bes->ipr[i], sbes.ipr[i]);165166out_be32(&bes->cReqSelect, sbes.cReqSelect);167out_be32(&bes->task_size0, sbes.task_size0);168out_be32(&bes->task_size1, sbes.task_size1);169out_be32(&bes->MDEDebug, sbes.MDEDebug);170out_be32(&bes->ADSDebug, sbes.ADSDebug);171out_be32(&bes->Value1, sbes.Value1);172out_be32(&bes->Value2, sbes.Value2);173out_be32(&bes->Control, sbes.Control);174out_be32(&bes->Status, sbes.Status);175out_be32(&bes->PTDDebug, sbes.PTDDebug);176177/* restore tasks */178for (i=0; i<16; i++)179out_be16(&bes->tcr[i], sbes.tcr[i]);180181/* enable interrupts */182out_be32(&bes->IntPend, sbes.IntPend);183out_be32(&bes->IntMask, sbes.IntMask);184185186/* PIC */187out_be32(&pic->per_pri1, spic.per_pri1);188out_be32(&pic->per_pri2, spic.per_pri2);189out_be32(&pic->per_pri3, spic.per_pri3);190191out_be32(&pic->main_pri1, spic.main_pri1);192out_be32(&pic->main_pri2, spic.main_pri2);193194out_be32(&pic->enc_status, spic.enc_status);195196/* unmask and enable interrupts */197out_be32(&pic->per_mask, spic.per_mask);198out_be32(&pic->main_mask, spic.main_mask);199out_be32(&pic->ctrl, spic.ctrl);200}201202static int lite5200_pm_enter(suspend_state_t state)203{204/* deep sleep? let mpc52xx code handle that */205if (state == PM_SUSPEND_STANDBY) {206return mpc52xx_pm_enter(state);207}208209lite5200_save_regs();210211/* effectively save FP regs */212enable_kernel_fp();213214lite5200_low_power(sram, mbar);215216lite5200_restore_regs();217218iounmap(mbar);219return 0;220}221222static void lite5200_pm_finish(void)223{224/* deep sleep? let mpc52xx code handle that */225if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)226mpc52xx_pm_finish();227}228229static void lite5200_pm_end(void)230{231lite5200_pm_target_state = PM_SUSPEND_ON;232}233234static const struct platform_suspend_ops lite5200_pm_ops = {235.valid = lite5200_pm_valid,236.begin = lite5200_pm_begin,237.prepare = lite5200_pm_prepare,238.enter = lite5200_pm_enter,239.finish = lite5200_pm_finish,240.end = lite5200_pm_end,241};242243int __init lite5200_pm_init(void)244{245suspend_set_ops(&lite5200_pm_ops);246return 0;247}248249250