linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] drivers/memory: Add deep sleep support for IFC
@ 2015-10-27 11:04 Raghav Dogra
  2015-10-29 16:21 ` Scott Wood
  0 siblings, 1 reply; 2+ messages in thread
From: Raghav Dogra @ 2015-10-27 11:04 UTC (permalink / raw)
  To: linux-kernel; +Cc: scottwood, Raghav Dogra

Add support of suspend, resume function to support deep sleep.
Also make sure of SRAM initialization  during resume.

Signed-off-by: Raghav Dogra <raghav@freescale.com>
---
 drivers/memory/fsl_ifc.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fsl_ifc.h  |  6 ++++++
 2 files changed, 62 insertions(+)

diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index e87459f..163ccf2 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/compiler.h>
 #include <linux/spinlock.h>
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/io.h>
@@ -35,6 +36,9 @@
 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
  * @addr_base:	base address of the memory bank
@@ -308,6 +312,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",
@@ -315,10 +366,15 @@ 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,
diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h
index 0023088..2776df2 100644
--- a/include/linux/fsl_ifc.h
+++ b/include/linux/fsl_ifc.h
@@ -270,6 +270,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 */
@@ -841,6 +843,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
 	bool little_endian;
 };
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH 1/2] drivers/memory: Add deep sleep support for IFC
  2015-10-27 11:04 [PATCH 1/2] drivers/memory: Add deep sleep support for IFC Raghav Dogra
@ 2015-10-29 16:21 ` Scott Wood
  0 siblings, 0 replies; 2+ messages in thread
From: Scott Wood @ 2015-10-29 16:21 UTC (permalink / raw)
  To: Raghav Dogra; +Cc: linux-kernel, prabhakar

On Tue, 2015-10-27 at 16:34 +0530, Raghav Dogra wrote:
> Add support of suspend, resume function to support deep sleep.
> Also make sure of SRAM initialization  during resume.
> 
> Signed-off-by: Raghav Dogra <raghav@freescale.com>
> ---
>  drivers/memory/fsl_ifc.c | 56 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/fsl_ifc.h  |  6 ++++++
>  2 files changed, 62 insertions(+)

Who are you asking to apply this?  If me, please send to 
 linuxppc-dev@lists.ozlabs.orgso it gets on patchwork.

Also keep Prabhakar CCed on IFC patches.

> diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
> index e87459f..163ccf2 100644
> --- a/drivers/memory/fsl_ifc.c
> +++ b/drivers/memory/fsl_ifc.c
> @@ -23,6 +23,7 @@
>  #include <linux/kernel.h>
>  #include <linux/compiler.h>
>  #include <linux/spinlock.h>
> +#include <linux/delay.h>
>  #include <linux/types.h>
>  #include <linux/slab.h>
>  #include <linux/io.h>
> @@ -35,6 +36,9 @@
>  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
>   * @addr_base:       base address of the memory bank
> @@ -308,6 +312,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;
> +}

Why _memcpy_fromio() rather than memcpy_fromio()?

> +/* 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));

This is too simplistic, and doesn't account for things like read-to-clear 
bits, or the possibility of reserved fields that expose internal state that 
shouldn't be messed with.  Registers that need state saving or 
reinitialization should be handled individually.

You should also make sure that interrupts are disabled at the device.

> +             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 */

Normally we do NAND SRAM init in the NAND driver.  Why are you doing it here? 
 How is SRAM going to be reset on older IFCs?

BTW, I see that Linux is missing SRAM init for IFCs newer than v1.1 -- we're 
relying on U-Boot to do so, which we shouldn't be.

-Scott


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-10-29 16:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-27 11:04 [PATCH 1/2] drivers/memory: Add deep sleep support for IFC Raghav Dogra
2015-10-29 16:21 ` Scott Wood

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).