162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/init.h> 362306a36Sopenharmony_ci#include <linux/suspend.h> 462306a36Sopenharmony_ci#include <linux/of_address.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <asm/io.h> 762306a36Sopenharmony_ci#include <asm/time.h> 862306a36Sopenharmony_ci#include <asm/mpc52xx.h> 962306a36Sopenharmony_ci#include <asm/switch_to.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* defined in lite5200_sleep.S and only used here */ 1262306a36Sopenharmony_ciextern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic struct mpc52xx_cdm __iomem *cdm; 1562306a36Sopenharmony_cistatic struct mpc52xx_intr __iomem *pic; 1662306a36Sopenharmony_cistatic struct mpc52xx_sdma __iomem *bes; 1762306a36Sopenharmony_cistatic struct mpc52xx_xlb __iomem *xlb; 1862306a36Sopenharmony_cistatic struct mpc52xx_gpio __iomem *gps; 1962306a36Sopenharmony_cistatic struct mpc52xx_gpio_wkup __iomem *gpw; 2062306a36Sopenharmony_cistatic void __iomem *pci; 2162306a36Sopenharmony_cistatic void __iomem *sram; 2262306a36Sopenharmony_cistatic const int sram_size = 0x4000; /* 16 kBytes */ 2362306a36Sopenharmony_cistatic void __iomem *mbar; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic suspend_state_t lite5200_pm_target_state; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int lite5200_pm_valid(suspend_state_t state) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci switch (state) { 3062306a36Sopenharmony_ci case PM_SUSPEND_STANDBY: 3162306a36Sopenharmony_ci case PM_SUSPEND_MEM: 3262306a36Sopenharmony_ci return 1; 3362306a36Sopenharmony_ci default: 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int lite5200_pm_begin(suspend_state_t state) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci if (lite5200_pm_valid(state)) { 4162306a36Sopenharmony_ci lite5200_pm_target_state = state; 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci return -EINVAL; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int lite5200_pm_prepare(void) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct device_node *np; 5062306a36Sopenharmony_ci static const struct of_device_id immr_ids[] = { 5162306a36Sopenharmony_ci { .compatible = "fsl,mpc5200-immr", }, 5262306a36Sopenharmony_ci { .compatible = "fsl,mpc5200b-immr", }, 5362306a36Sopenharmony_ci { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ 5462306a36Sopenharmony_ci { .type = "builtin", .compatible = "mpc5200", }, /* efika */ 5562306a36Sopenharmony_ci {} 5662306a36Sopenharmony_ci }; 5762306a36Sopenharmony_ci struct resource res; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 6062306a36Sopenharmony_ci if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) 6162306a36Sopenharmony_ci return mpc52xx_pm_prepare(); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (lite5200_pm_target_state != PM_SUSPEND_MEM) 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* map registers */ 6762306a36Sopenharmony_ci np = of_find_matching_node(NULL, immr_ids); 6862306a36Sopenharmony_ci of_address_to_resource(np, 0, &res); 6962306a36Sopenharmony_ci of_node_put(np); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mbar = ioremap(res.start, 0xC000); 7262306a36Sopenharmony_ci if (!mbar) { 7362306a36Sopenharmony_ci printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); 7462306a36Sopenharmony_ci return -ENOSYS; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci cdm = mbar + 0x200; 7862306a36Sopenharmony_ci pic = mbar + 0x500; 7962306a36Sopenharmony_ci gps = mbar + 0xb00; 8062306a36Sopenharmony_ci gpw = mbar + 0xc00; 8162306a36Sopenharmony_ci pci = mbar + 0xd00; 8262306a36Sopenharmony_ci bes = mbar + 0x1200; 8362306a36Sopenharmony_ci xlb = mbar + 0x1f00; 8462306a36Sopenharmony_ci sram = mbar + 0x8000; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* save and restore registers not bound to any real devices */ 9062306a36Sopenharmony_cistatic struct mpc52xx_cdm scdm; 9162306a36Sopenharmony_cistatic struct mpc52xx_intr spic; 9262306a36Sopenharmony_cistatic struct mpc52xx_sdma sbes; 9362306a36Sopenharmony_cistatic struct mpc52xx_xlb sxlb; 9462306a36Sopenharmony_cistatic struct mpc52xx_gpio sgps; 9562306a36Sopenharmony_cistatic struct mpc52xx_gpio_wkup sgpw; 9662306a36Sopenharmony_cistatic char spci[0x200]; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void lite5200_save_regs(void) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci _memcpy_fromio(&spic, pic, sizeof(*pic)); 10162306a36Sopenharmony_ci _memcpy_fromio(&sbes, bes, sizeof(*bes)); 10262306a36Sopenharmony_ci _memcpy_fromio(&scdm, cdm, sizeof(*cdm)); 10362306a36Sopenharmony_ci _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); 10462306a36Sopenharmony_ci _memcpy_fromio(&sgps, gps, sizeof(*gps)); 10562306a36Sopenharmony_ci _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); 10662306a36Sopenharmony_ci _memcpy_fromio(spci, pci, 0x200); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci _memcpy_fromio(saved_sram, sram, sram_size); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void lite5200_restore_regs(void) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci int i; 11462306a36Sopenharmony_ci _memcpy_toio(sram, saved_sram, sram_size); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* PCI Configuration */ 11762306a36Sopenharmony_ci _memcpy_toio(pci, spci, 0x200); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * GPIOs. Interrupt Master Enable has higher address then other 12162306a36Sopenharmony_ci * registers, so just memcpy is ok. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci _memcpy_toio(gpw, &sgpw, sizeof(*gpw)); 12462306a36Sopenharmony_ci _memcpy_toio(gps, &sgps, sizeof(*gps)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* XLB Arbitrer */ 12862306a36Sopenharmony_ci out_be32(&xlb->snoop_window, sxlb.snoop_window); 12962306a36Sopenharmony_ci out_be32(&xlb->master_priority, sxlb.master_priority); 13062306a36Sopenharmony_ci out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* enable */ 13362306a36Sopenharmony_ci out_be32(&xlb->int_enable, sxlb.int_enable); 13462306a36Sopenharmony_ci out_be32(&xlb->config, sxlb.config); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* CDM - Clock Distribution Module */ 13862306a36Sopenharmony_ci out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel); 13962306a36Sopenharmony_ci out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en); 14262306a36Sopenharmony_ci out_8(&cdm->fd_enable, scdm.fd_enable); 14362306a36Sopenharmony_ci out_be16(&cdm->fd_counters, scdm.fd_counters); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci out_be32(&cdm->clk_enables, scdm.clk_enables); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci out_8(&cdm->osc_disable, scdm.osc_disable); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1); 15062306a36Sopenharmony_ci out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2); 15162306a36Sopenharmony_ci out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3); 15262306a36Sopenharmony_ci out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* BESTCOMM */ 15662306a36Sopenharmony_ci out_be32(&bes->taskBar, sbes.taskBar); 15762306a36Sopenharmony_ci out_be32(&bes->currentPointer, sbes.currentPointer); 15862306a36Sopenharmony_ci out_be32(&bes->endPointer, sbes.endPointer); 15962306a36Sopenharmony_ci out_be32(&bes->variablePointer, sbes.variablePointer); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci out_8(&bes->IntVect1, sbes.IntVect1); 16262306a36Sopenharmony_ci out_8(&bes->IntVect2, sbes.IntVect2); 16362306a36Sopenharmony_ci out_be16(&bes->PtdCntrl, sbes.PtdCntrl); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (i=0; i<32; i++) 16662306a36Sopenharmony_ci out_8(&bes->ipr[i], sbes.ipr[i]); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci out_be32(&bes->cReqSelect, sbes.cReqSelect); 16962306a36Sopenharmony_ci out_be32(&bes->task_size0, sbes.task_size0); 17062306a36Sopenharmony_ci out_be32(&bes->task_size1, sbes.task_size1); 17162306a36Sopenharmony_ci out_be32(&bes->MDEDebug, sbes.MDEDebug); 17262306a36Sopenharmony_ci out_be32(&bes->ADSDebug, sbes.ADSDebug); 17362306a36Sopenharmony_ci out_be32(&bes->Value1, sbes.Value1); 17462306a36Sopenharmony_ci out_be32(&bes->Value2, sbes.Value2); 17562306a36Sopenharmony_ci out_be32(&bes->Control, sbes.Control); 17662306a36Sopenharmony_ci out_be32(&bes->Status, sbes.Status); 17762306a36Sopenharmony_ci out_be32(&bes->PTDDebug, sbes.PTDDebug); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* restore tasks */ 18062306a36Sopenharmony_ci for (i=0; i<16; i++) 18162306a36Sopenharmony_ci out_be16(&bes->tcr[i], sbes.tcr[i]); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* enable interrupts */ 18462306a36Sopenharmony_ci out_be32(&bes->IntPend, sbes.IntPend); 18562306a36Sopenharmony_ci out_be32(&bes->IntMask, sbes.IntMask); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* PIC */ 18962306a36Sopenharmony_ci out_be32(&pic->per_pri1, spic.per_pri1); 19062306a36Sopenharmony_ci out_be32(&pic->per_pri2, spic.per_pri2); 19162306a36Sopenharmony_ci out_be32(&pic->per_pri3, spic.per_pri3); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci out_be32(&pic->main_pri1, spic.main_pri1); 19462306a36Sopenharmony_ci out_be32(&pic->main_pri2, spic.main_pri2); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci out_be32(&pic->enc_status, spic.enc_status); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* unmask and enable interrupts */ 19962306a36Sopenharmony_ci out_be32(&pic->per_mask, spic.per_mask); 20062306a36Sopenharmony_ci out_be32(&pic->main_mask, spic.main_mask); 20162306a36Sopenharmony_ci out_be32(&pic->ctrl, spic.ctrl); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int lite5200_pm_enter(suspend_state_t state) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 20762306a36Sopenharmony_ci if (state == PM_SUSPEND_STANDBY) { 20862306a36Sopenharmony_ci return mpc52xx_pm_enter(state); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci lite5200_save_regs(); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* effectively save FP regs */ 21462306a36Sopenharmony_ci enable_kernel_fp(); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci lite5200_low_power(sram, mbar); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci lite5200_restore_regs(); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci iounmap(mbar); 22162306a36Sopenharmony_ci return 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic void lite5200_pm_finish(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 22762306a36Sopenharmony_ci if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) 22862306a36Sopenharmony_ci mpc52xx_pm_finish(); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void lite5200_pm_end(void) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci lite5200_pm_target_state = PM_SUSPEND_ON; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct platform_suspend_ops lite5200_pm_ops = { 23762306a36Sopenharmony_ci .valid = lite5200_pm_valid, 23862306a36Sopenharmony_ci .begin = lite5200_pm_begin, 23962306a36Sopenharmony_ci .prepare = lite5200_pm_prepare, 24062306a36Sopenharmony_ci .enter = lite5200_pm_enter, 24162306a36Sopenharmony_ci .finish = lite5200_pm_finish, 24262306a36Sopenharmony_ci .end = lite5200_pm_end, 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciint __init lite5200_pm_init(void) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci suspend_set_ops(&lite5200_pm_ops); 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 250