From 504b615e3dd04d0e347174a7fb6d41da3b06cfb9 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Wed, 19 Mar 2014 11:14:22 +0530 Subject: powerpc/mpc85xx: Add deep sleep support for IFC Add support of suspend, resume function to support deep sleep. Also make sure of SRAM initialization during resume. Signed-off-by: Prabhakar Kushwaha Change-Id: Ia3d484ff272d6c7feebb74a5ad95f74fb91cdd68 Reviewed-on: http://git.am.freescale.net:8181/9444 Tested-by: Review Code-CDREVIEW Reviewed-by: Dongsheng Wang Reviewed-by: Jose Rivera (cherry picked from commit 82a066c3f93441a7e80c1a603ff185ee4d16bf25) Reviewed-on: http://git.am.freescale.net:8181/9928 diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h index f49ddb1..e06473b 100644 --- a/arch/powerpc/include/asm/fsl_ifc.h +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -261,6 +261,8 @@ */ /* Auto Boot Mode */ #define IFC_NAND_NCFGR_BOOT 0x80000000 +/* SRAM INIT EN */ +#define IFC_NAND_SRAM_INIT_EN 0x20000000 /* Addressing Mode-ROW0+n/COL0 */ #define IFC_NAND_NCFGR_ADDR_MODE_RC0 0x00000000 /* Addressing Mode-ROW0+n/COL0+n */ @@ -830,6 +832,10 @@ struct fsl_ifc_ctrl { u32 nand_stat; wait_queue_head_t nand_wait; +#ifdef CONFIG_PM_SLEEP + /* save regs when system go to deep-sleep */ + struct fsl_ifc_regs *saved_regs; +#endif }; extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; diff --git a/arch/powerpc/sysdev/fsl_ifc.c b/arch/powerpc/sysdev/fsl_ifc.c index d7fc722..592e029 100644 --- a/arch/powerpc/sysdev/fsl_ifc.c +++ b/arch/powerpc/sysdev/fsl_ifc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; EXPORT_SYMBOL(fsl_ifc_ctrl_dev); +#define FSL_IFC_V1_3_0 0x01030000 +#define IFC_TIMEOUT_MSECS 100000 /* 100ms */ /* * convert_ifc_address - convert the base address @@ -283,6 +286,53 @@ err: return ret; } +#ifdef CONFIG_PM_SLEEP +/* save ifc registers */ +static int fsl_ifc_suspend(struct device *dev) +{ + struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); + struct fsl_ifc_regs __iomem *ifc = ctrl->regs; + + ctrl->saved_regs = kzalloc(sizeof(struct fsl_ifc_regs), GFP_KERNEL); + if (!ctrl->saved_regs) + return -ENOMEM; + + _memcpy_fromio(ctrl->saved_regs, ifc, sizeof(struct fsl_ifc_regs)); + + return 0; +} + +/* restore ifc registers */ +static int fsl_ifc_resume(struct device *dev) +{ + struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); + struct fsl_ifc_regs __iomem *ifc = ctrl->regs; + uint32_t ver = 0, ncfgr, status; + + if (ctrl->saved_regs) { + _memcpy_toio(ifc, ctrl->saved_regs, + sizeof(struct fsl_ifc_regs)); + kfree(ctrl->saved_regs); + ctrl->saved_regs = NULL; + } + + ver = in_be32(&ctrl->regs->ifc_rev); + ncfgr = in_be32(&ifc->ifc_nand.ncfgr); + if (ver >= FSL_IFC_V1_3_0) { + out_be32(&ifc->ifc_nand.ncfgr, ncfgr | IFC_NAND_SRAM_INIT_EN); + + /* wait for SRAM_INIT bit to be clear or timeout */ + status = spin_event_timeout(!(in_be32(&ifc->ifc_nand.ncfgr) + & IFC_NAND_SRAM_INIT_EN), + IFC_TIMEOUT_MSECS, 0); + if (!status) + dev_err(ctrl->dev, "Timeout waiting for IFC SRAM INIT"); + } + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static const struct of_device_id fsl_ifc_match[] = { { .compatible = "fsl,ifc", @@ -290,16 +340,25 @@ static const struct of_device_id fsl_ifc_match[] = { {}, }; +static const struct dev_pm_ops ifc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fsl_ifc_suspend, fsl_ifc_resume) +}; + static struct platform_driver fsl_ifc_ctrl_driver = { .driver = { .name = "fsl-ifc", .of_match_table = fsl_ifc_match, + .pm = &ifc_pm_ops, }, .probe = fsl_ifc_ctrl_probe, .remove = fsl_ifc_ctrl_remove, }; -module_platform_driver(fsl_ifc_ctrl_driver); +static int __init fsl_ifc_init(void) +{ + return platform_driver_register(&fsl_ifc_ctrl_driver); +} +subsys_initcall(fsl_ifc_init); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductor"); -- cgit v0.10.2