18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/init.h> 38c2ecf20Sopenharmony_ci#include <linux/suspend.h> 48c2ecf20Sopenharmony_ci#include <asm/io.h> 58c2ecf20Sopenharmony_ci#include <asm/time.h> 68c2ecf20Sopenharmony_ci#include <asm/mpc52xx.h> 78c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* defined in lite5200_sleep.S and only used here */ 108c2ecf20Sopenharmony_ciextern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic struct mpc52xx_cdm __iomem *cdm; 138c2ecf20Sopenharmony_cistatic struct mpc52xx_intr __iomem *pic; 148c2ecf20Sopenharmony_cistatic struct mpc52xx_sdma __iomem *bes; 158c2ecf20Sopenharmony_cistatic struct mpc52xx_xlb __iomem *xlb; 168c2ecf20Sopenharmony_cistatic struct mpc52xx_gpio __iomem *gps; 178c2ecf20Sopenharmony_cistatic struct mpc52xx_gpio_wkup __iomem *gpw; 188c2ecf20Sopenharmony_cistatic void __iomem *pci; 198c2ecf20Sopenharmony_cistatic void __iomem *sram; 208c2ecf20Sopenharmony_cistatic const int sram_size = 0x4000; /* 16 kBytes */ 218c2ecf20Sopenharmony_cistatic void __iomem *mbar; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic suspend_state_t lite5200_pm_target_state; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int lite5200_pm_valid(suspend_state_t state) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci switch (state) { 288c2ecf20Sopenharmony_ci case PM_SUSPEND_STANDBY: 298c2ecf20Sopenharmony_ci case PM_SUSPEND_MEM: 308c2ecf20Sopenharmony_ci return 1; 318c2ecf20Sopenharmony_ci default: 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int lite5200_pm_begin(suspend_state_t state) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (lite5200_pm_valid(state)) { 398c2ecf20Sopenharmony_ci lite5200_pm_target_state = state; 408c2ecf20Sopenharmony_ci return 0; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci return -EINVAL; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int lite5200_pm_prepare(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct device_node *np; 488c2ecf20Sopenharmony_ci const struct of_device_id immr_ids[] = { 498c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5200-immr", }, 508c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc5200b-immr", }, 518c2ecf20Sopenharmony_ci { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ 528c2ecf20Sopenharmony_ci { .type = "builtin", .compatible = "mpc5200", }, /* efika */ 538c2ecf20Sopenharmony_ci {} 548c2ecf20Sopenharmony_ci }; 558c2ecf20Sopenharmony_ci u64 regaddr64 = 0; 568c2ecf20Sopenharmony_ci const u32 *regaddr_p; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 598c2ecf20Sopenharmony_ci if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) 608c2ecf20Sopenharmony_ci return mpc52xx_pm_prepare(); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (lite5200_pm_target_state != PM_SUSPEND_MEM) 638c2ecf20Sopenharmony_ci return -EINVAL; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* map registers */ 668c2ecf20Sopenharmony_ci np = of_find_matching_node(NULL, immr_ids); 678c2ecf20Sopenharmony_ci regaddr_p = of_get_address(np, 0, NULL, NULL); 688c2ecf20Sopenharmony_ci if (regaddr_p) 698c2ecf20Sopenharmony_ci regaddr64 = of_translate_address(np, regaddr_p); 708c2ecf20Sopenharmony_ci of_node_put(np); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci mbar = ioremap((u32) regaddr64, 0xC000); 738c2ecf20Sopenharmony_ci if (!mbar) { 748c2ecf20Sopenharmony_ci printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); 758c2ecf20Sopenharmony_ci return -ENOSYS; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci cdm = mbar + 0x200; 798c2ecf20Sopenharmony_ci pic = mbar + 0x500; 808c2ecf20Sopenharmony_ci gps = mbar + 0xb00; 818c2ecf20Sopenharmony_ci gpw = mbar + 0xc00; 828c2ecf20Sopenharmony_ci pci = mbar + 0xd00; 838c2ecf20Sopenharmony_ci bes = mbar + 0x1200; 848c2ecf20Sopenharmony_ci xlb = mbar + 0x1f00; 858c2ecf20Sopenharmony_ci sram = mbar + 0x8000; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* save and restore registers not bound to any real devices */ 918c2ecf20Sopenharmony_cistatic struct mpc52xx_cdm scdm; 928c2ecf20Sopenharmony_cistatic struct mpc52xx_intr spic; 938c2ecf20Sopenharmony_cistatic struct mpc52xx_sdma sbes; 948c2ecf20Sopenharmony_cistatic struct mpc52xx_xlb sxlb; 958c2ecf20Sopenharmony_cistatic struct mpc52xx_gpio sgps; 968c2ecf20Sopenharmony_cistatic struct mpc52xx_gpio_wkup sgpw; 978c2ecf20Sopenharmony_cistatic char spci[0x200]; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void lite5200_save_regs(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci _memcpy_fromio(&spic, pic, sizeof(*pic)); 1028c2ecf20Sopenharmony_ci _memcpy_fromio(&sbes, bes, sizeof(*bes)); 1038c2ecf20Sopenharmony_ci _memcpy_fromio(&scdm, cdm, sizeof(*cdm)); 1048c2ecf20Sopenharmony_ci _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); 1058c2ecf20Sopenharmony_ci _memcpy_fromio(&sgps, gps, sizeof(*gps)); 1068c2ecf20Sopenharmony_ci _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); 1078c2ecf20Sopenharmony_ci _memcpy_fromio(spci, pci, 0x200); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci _memcpy_fromio(saved_sram, sram, sram_size); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void lite5200_restore_regs(void) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci int i; 1158c2ecf20Sopenharmony_ci _memcpy_toio(sram, saved_sram, sram_size); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* PCI Configuration */ 1188c2ecf20Sopenharmony_ci _memcpy_toio(pci, spci, 0x200); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * GPIOs. Interrupt Master Enable has higher address then other 1228c2ecf20Sopenharmony_ci * registers, so just memcpy is ok. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci _memcpy_toio(gpw, &sgpw, sizeof(*gpw)); 1258c2ecf20Sopenharmony_ci _memcpy_toio(gps, &sgps, sizeof(*gps)); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* XLB Arbitrer */ 1298c2ecf20Sopenharmony_ci out_be32(&xlb->snoop_window, sxlb.snoop_window); 1308c2ecf20Sopenharmony_ci out_be32(&xlb->master_priority, sxlb.master_priority); 1318c2ecf20Sopenharmony_ci out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* enable */ 1348c2ecf20Sopenharmony_ci out_be32(&xlb->int_enable, sxlb.int_enable); 1358c2ecf20Sopenharmony_ci out_be32(&xlb->config, sxlb.config); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* CDM - Clock Distribution Module */ 1398c2ecf20Sopenharmony_ci out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel); 1408c2ecf20Sopenharmony_ci out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en); 1438c2ecf20Sopenharmony_ci out_8(&cdm->fd_enable, scdm.fd_enable); 1448c2ecf20Sopenharmony_ci out_be16(&cdm->fd_counters, scdm.fd_counters); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci out_be32(&cdm->clk_enables, scdm.clk_enables); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci out_8(&cdm->osc_disable, scdm.osc_disable); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1); 1518c2ecf20Sopenharmony_ci out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2); 1528c2ecf20Sopenharmony_ci out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3); 1538c2ecf20Sopenharmony_ci out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* BESTCOMM */ 1578c2ecf20Sopenharmony_ci out_be32(&bes->taskBar, sbes.taskBar); 1588c2ecf20Sopenharmony_ci out_be32(&bes->currentPointer, sbes.currentPointer); 1598c2ecf20Sopenharmony_ci out_be32(&bes->endPointer, sbes.endPointer); 1608c2ecf20Sopenharmony_ci out_be32(&bes->variablePointer, sbes.variablePointer); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci out_8(&bes->IntVect1, sbes.IntVect1); 1638c2ecf20Sopenharmony_ci out_8(&bes->IntVect2, sbes.IntVect2); 1648c2ecf20Sopenharmony_ci out_be16(&bes->PtdCntrl, sbes.PtdCntrl); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci for (i=0; i<32; i++) 1678c2ecf20Sopenharmony_ci out_8(&bes->ipr[i], sbes.ipr[i]); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci out_be32(&bes->cReqSelect, sbes.cReqSelect); 1708c2ecf20Sopenharmony_ci out_be32(&bes->task_size0, sbes.task_size0); 1718c2ecf20Sopenharmony_ci out_be32(&bes->task_size1, sbes.task_size1); 1728c2ecf20Sopenharmony_ci out_be32(&bes->MDEDebug, sbes.MDEDebug); 1738c2ecf20Sopenharmony_ci out_be32(&bes->ADSDebug, sbes.ADSDebug); 1748c2ecf20Sopenharmony_ci out_be32(&bes->Value1, sbes.Value1); 1758c2ecf20Sopenharmony_ci out_be32(&bes->Value2, sbes.Value2); 1768c2ecf20Sopenharmony_ci out_be32(&bes->Control, sbes.Control); 1778c2ecf20Sopenharmony_ci out_be32(&bes->Status, sbes.Status); 1788c2ecf20Sopenharmony_ci out_be32(&bes->PTDDebug, sbes.PTDDebug); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* restore tasks */ 1818c2ecf20Sopenharmony_ci for (i=0; i<16; i++) 1828c2ecf20Sopenharmony_ci out_be16(&bes->tcr[i], sbes.tcr[i]); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* enable interrupts */ 1858c2ecf20Sopenharmony_ci out_be32(&bes->IntPend, sbes.IntPend); 1868c2ecf20Sopenharmony_ci out_be32(&bes->IntMask, sbes.IntMask); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* PIC */ 1908c2ecf20Sopenharmony_ci out_be32(&pic->per_pri1, spic.per_pri1); 1918c2ecf20Sopenharmony_ci out_be32(&pic->per_pri2, spic.per_pri2); 1928c2ecf20Sopenharmony_ci out_be32(&pic->per_pri3, spic.per_pri3); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci out_be32(&pic->main_pri1, spic.main_pri1); 1958c2ecf20Sopenharmony_ci out_be32(&pic->main_pri2, spic.main_pri2); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci out_be32(&pic->enc_status, spic.enc_status); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* unmask and enable interrupts */ 2008c2ecf20Sopenharmony_ci out_be32(&pic->per_mask, spic.per_mask); 2018c2ecf20Sopenharmony_ci out_be32(&pic->main_mask, spic.main_mask); 2028c2ecf20Sopenharmony_ci out_be32(&pic->ctrl, spic.ctrl); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int lite5200_pm_enter(suspend_state_t state) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 2088c2ecf20Sopenharmony_ci if (state == PM_SUSPEND_STANDBY) { 2098c2ecf20Sopenharmony_ci return mpc52xx_pm_enter(state); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci lite5200_save_regs(); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* effectively save FP regs */ 2158c2ecf20Sopenharmony_ci enable_kernel_fp(); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci lite5200_low_power(sram, mbar); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci lite5200_restore_regs(); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci iounmap(mbar); 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic void lite5200_pm_finish(void) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci /* deep sleep? let mpc52xx code handle that */ 2288c2ecf20Sopenharmony_ci if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) 2298c2ecf20Sopenharmony_ci mpc52xx_pm_finish(); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void lite5200_pm_end(void) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci lite5200_pm_target_state = PM_SUSPEND_ON; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops lite5200_pm_ops = { 2388c2ecf20Sopenharmony_ci .valid = lite5200_pm_valid, 2398c2ecf20Sopenharmony_ci .begin = lite5200_pm_begin, 2408c2ecf20Sopenharmony_ci .prepare = lite5200_pm_prepare, 2418c2ecf20Sopenharmony_ci .enter = lite5200_pm_enter, 2428c2ecf20Sopenharmony_ci .finish = lite5200_pm_finish, 2438c2ecf20Sopenharmony_ci .end = lite5200_pm_end, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint __init lite5200_pm_init(void) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci suspend_set_ops(&lite5200_pm_ops); 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 251