Skip to contentSkip to conversation

MPC5200 and Lite5200b low power modes

PATCH Superseded Domen Puncer 7 participants 21 messages Mar 1, 2007 – Mar 5, 2007

Subsystems (5)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover MPC5200 and Lite5200b low power modes

Hi!

Patches are based on latest mainline git tree + fec patches:
Fec_MPC5200_eth_driver.patch Copy_bestcomm_support_files_into_arch_powerpc.patch Make_FEC_work_on_the_lite5200.patch

This patchset includes the following patches:
- [PATCH 1/7] mpc52xx suspend: bestcomm
- [PATCH 2/7] mpc52xx suspend: UART
- [PATCH 3/7] mpc52xx suspend: FEC (ethernet)
- [PATCH 4/7] mpc52xx suspend: USB
- [PATCH 5/7] mpc52xx suspend: deep-sleep
- [PATCH 6/7] lite5200b suspend: PIC
- [u-boot patch] support lite5200b wakeup in u-boot
- [PATCH 7/7] lite5200b suspend: low-power mode

I would appreaciate any comments, suggestions etc.

Domen

#1 lore raw

PATCH 1/7 mpc52xx suspend: bestcomm

Save and restore bestcomm registers and SRAM.

arch/powerpc/platforms/52xx/bestcomm.c +71 -0
Index: grant.git/arch/powerpc/platforms/52xx/bestcomm.c
===================================================================
@@ -395,4 +395,75 @@ EXPORT_SYMBOL(sdma_set_initiator);
 EXPORT_SYMBOL(sdma_free);
 EXPORT_SYMBOL(sdma);
 
+#ifdef CONFIG_PM
+static struct mpc52xx_sdma sdma_regs;
+static char saved_sram[0x4000]; /* copy of 16kB internal SRAM */
 
+int mpc52xx_sdma_suspend(void)
+{
+	int i;
+
+	sdma_regs.taskBar =	in_be32(&sdma.io->taskBar);
+	sdma_regs.currentPointer = in_be32(&sdma.io->currentPointer);
+	sdma_regs.endPointer =	in_be32(&sdma.io->endPointer);
+	sdma_regs.variablePointer = in_be32(&sdma.io->variablePointer);
+	sdma_regs.IntVect1 =	in_8(&sdma.io->IntVect1);
+	sdma_regs.IntVect2 =	in_8(&sdma.io->IntVect2);
+	sdma_regs.PtdCntrl =	in_be16(&sdma.io->PtdCntrl);
+	sdma_regs.IntPend =	in_be32(&sdma.io->IntPend);
+	sdma_regs.IntMask =	in_be32(&sdma.io->IntMask);
+
+	for (i=0; i<16; i++)
+		sdma_regs.tcr[i] = in_be16(&sdma.io->tcr[i]);
+	for (i=0; i<32; i++)
+		sdma_regs.ipr[i] = in_8(&sdma.io->ipr[i]);
+
+	sdma_regs.cReqSelect =	in_be32(&sdma.io->cReqSelect);
+	sdma_regs.task_size0 = in_be32(&sdma.io->task_size0);
+	sdma_regs.task_size1 = in_be32(&sdma.io->task_size1);
+	sdma_regs.MDEDebug =	in_be32(&sdma.io->MDEDebug);
+	sdma_regs.ADSDebug =	in_be32(&sdma.io->ADSDebug);
+	sdma_regs.Value1 =	in_be32(&sdma.io->Value1);
+	sdma_regs.Value2 =	in_be32(&sdma.io->Value2);
+	sdma_regs.Control =	in_be32(&sdma.io->Control);
+	sdma_regs.Status =	in_be32(&sdma.io->Status);
+	sdma_regs.PTDDebug =	in_be32(&sdma.io->PTDDebug);
+
+	memcpy(saved_sram, sdma.sram, sdma.sram_size);
+	return 0;
+}
+
+int mpc52xx_sdma_resume(void)
+{
+	int i;
+
+	memcpy(sdma.sram, saved_sram, sdma.sram_size);
+
+	out_be32(&sdma.io->taskBar, sdma_regs.taskBar);
+	out_be32(&sdma.io->currentPointer, sdma_regs.currentPointer);
+	out_be32(&sdma.io->endPointer, sdma_regs.endPointer);
+	out_be32(&sdma.io->variablePointer, sdma_regs.variablePointer);
+	out_8(&sdma.io->IntVect1, sdma_regs.IntVect1);
+	out_8(&sdma.io->IntVect2, sdma_regs.IntVect2);
+	out_be16(&sdma.io->PtdCntrl, sdma_regs.PtdCntrl);
+	out_be32(&sdma.io->IntPend, sdma_regs.IntPend);
+	out_be32(&sdma.io->IntMask, sdma_regs.IntMask);
+
+	for (i=0; i<16; i++)
+		out_be16(&sdma.io->tcr[i], sdma_regs.tcr[i]);
+	for (i=0; i<32; i++)
+		out_8(&sdma.io->ipr[i], sdma_regs.ipr[i]);
+
+	out_be32(&sdma.io->cReqSelect, sdma_regs.cReqSelect);
+	out_be32(&sdma.io->task_size0, sdma_regs.task_size0);
+	out_be32(&sdma.io->task_size1, sdma_regs.task_size1);
+	out_be32(&sdma.io->MDEDebug, sdma_regs.MDEDebug);
+	out_be32(&sdma.io->ADSDebug, sdma_regs.ADSDebug);
+	out_be32(&sdma.io->Value1, sdma_regs.Value1);
+	out_be32(&sdma.io->Value2, sdma_regs.Value2);
+	out_be32(&sdma.io->Control, sdma_regs.Control);
+	out_be32(&sdma.io->Status, sdma_regs.Status);
+	out_be32(&sdma.io->PTDDebug, sdma_regs.PTDDebug);
+	return 0;
+}
+#endif
arch/powerpc/platforms/52xx/bestcomm.h +5 -0
Index: grant.git/arch/powerpc/platforms/52xx/bestcomm.h
===================================================================
@@ -473,6 +473,11 @@ extern void *sdma_sram_alloc(int size, i
 extern void sdma_init_bd(struct sdma *s);
 extern void sdma_init_bd2(struct sdma *s);
 
+#ifdef CONFIG_PM
+extern int mpc52xx_sdma_suspend(void);
+extern int mpc52xx_sdma_resume(void);
+#endif
+
 #define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
 
 #endif  /* __BESTCOMM_BESTCOMM_H__ */
#2 lore raw

PATCH 2/7 mpc52xx suspend: UART

In reply to Domen Puncer

MPC52xx uart power management.
Not sure how exactly this should be written, but this seems to work, and works around a few seconds delay in resume.

drivers/serial/mpc52xx_uart.c +20 -2
Index: grant.git/drivers/serial/mpc52xx_uart.c
===================================================================
@@ -418,6 +418,22 @@ mpc52xx_uart_verify_port(struct uart_por
 	return 0;
 }
 
+/* just Reenable TX and RX */
+static void mpc52xx_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+	struct mpc52xx_psc __iomem *psc = PSC(port);
+	unsigned long flags;
+
+	/* Get the lock */
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Reenable TX & RX */
+	out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
+	out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
+
+	/* We're all set, release the lock */
+	spin_unlock_irqrestore(&port->lock, flags);
+}
 
 static struct uart_ops mpc52xx_uart_ops = {
 	.tx_empty	= mpc52xx_uart_tx_empty,
@@ -432,8 +448,10 @@ static struct uart_ops mpc52xx_uart_ops 
 	.startup	= mpc52xx_uart_startup,
 	.shutdown	= mpc52xx_uart_shutdown,
 	.set_termios	= mpc52xx_uart_set_termios,
-/*	.pm		= mpc52xx_uart_pm,		Not supported yet */
-/*	.set_wake	= mpc52xx_uart_set_wake,	Not supported yet */
+
+	.pm		= mpc52xx_uart_pm,
+/*	.set_wake	= mpc52xx_uart_set_wake,*/
+
 	.type		= mpc52xx_uart_type,
 	.release_port	= mpc52xx_uart_release_port,
 	.request_port	= mpc52xx_uart_request_port,
#3 lore raw

PATCH 3/7 mpc52xx suspend: FEC (ethernet)

In reply to Domen Puncer

Suspend and resume for FEC on MPC52xx.

It just turns off (and on) leds, and even this in a hackish way. The right way is probably to figure out how BMCR_PDOWN works.

drivers/net/fec_mpc52xx/fec.c +54 -2
Index: grant.git/drivers/net/fec_mpc52xx/fec.c
===================================================================
@@ -801,6 +801,58 @@ mpc52xx_fec_remove(struct device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+int mpc52xx_fec_suspend(struct of_device *op, pm_message_t state)
+{
+	struct net_device *ndev = dev_get_drvdata(&op->dev);
+	struct fec_priv *priv = ndev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	netif_stop_queue(ndev);
+	out_be32(&fec->imask, 0x0);
+
+	/* Disable the rx and tx tasks. */
+	sdma_disable(priv->rx_sdma);
+	sdma_disable(priv->tx_sdma);
+
+	fec_free_rx_buffers(priv->rx_sdma);
+
+	/* Stop FEC */
+	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~0x2);
+
+	fec_mii_suspend(ndev);
+
+	return 0;
+}
+
+int mpc52xx_fec_resume(struct of_device *op)
+{
+	struct net_device *ndev = dev_get_drvdata(&op->dev);
+	struct fec_priv *priv = ndev->priv;
+	struct mpc52xx_fec *fec = priv->fec;
+
+	//fec_mii_resume(ndev);
+
+	fec_mii_init(ndev);
+
+	fec_hw_init(ndev);
+
+	/* restore leds. ugly hack, but fec_mii_resume doesn't work for me */
+	out_be32(&fec->mii_data, 0x50020000 | (0x14 << 18) | 0x0422);
+
+	/* Restart the DMA tasks */
+	sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo, FEC_RX_BUFFER_SIZE);
+	sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
+
+	if (priv->sequence_done) {		 /* redo the fec_open() */
+		fec_free_rx_buffers(priv->rx_sdma);
+		fec_open(ndev);
+	}
+
+	return 0;
+}
+#endif
+
 #if defined(CONFIG_PPC_MERGE)
 static struct of_device_id mpc52xx_fec_of_match[] = {
 	{ .compatible = "mpc5200-ethernet", },
@@ -815,8 +867,8 @@ static struct of_platform_driver mpc52xx
 	.probe = mpc52xx_fec_probe,
 	.remove = mpc52xx_fec_remove,
 #ifdef CONFIG_PM
-/*	.suspend = mpc52xx_fec_suspend, TODO */
-/*	.resume = mpc52xx_fec_resume, TODO */
+	.suspend = mpc52xx_fec_suspend,
+	.resume = mpc52xx_fec_resume,
 #endif
 	.driver = {
 		.name = DRIVER_NAME,
drivers/net/fec_mpc52xx/fec_phy.c +18 -0
Index: grant.git/drivers/net/fec_mpc52xx/fec_phy.c
===================================================================
@@ -77,6 +77,7 @@ static int mii_queue(struct net_device *
 #define MII_REG_ANER	 6	/* A-N Expansion Register */
 #define MII_REG_ANNPTR	 7	/* A-N Next Page Transmit Register */
 #define MII_REG_ANLPRNPR 8	/* A-N Link Partner Received Next Page Reg. */
+#define MII_REG_LED	20	/* LED Configuration Register */
 
 /* values for phy_status */
 
@@ -527,6 +528,23 @@ int fec_mii_wait(struct net_device *dev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+phy_cmd_t phy_cmd_leds_off[] ={ { mk_mii_write(MII_REG_LED, 0x9992), NULL },
+				{ mk_mii_end, } };
+phy_cmd_t phy_cmd_leds_on[] = {	{ mk_mii_write(MII_REG_LED, 0x0422), NULL },
+				{ mk_mii_end, } };
+
+void fec_mii_suspend(struct net_device *dev)
+{
+	mii_do_cmd(dev, phy_cmd_leds_off);
+}
+
+void fec_mii_resume(struct net_device *dev)
+{
+	mii_do_cmd(dev, phy_cmd_leds_on);
+}
+#endif
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Dale Farnsworth");
 MODULE_DESCRIPTION("PHY driver for Motorola MPC52xx FEC");
drivers/net/fec_mpc52xx/fec_phy.h +5 -0
Index: grant.git/drivers/net/fec_mpc52xx/fec_phy.h
===================================================================
@@ -71,3 +71,8 @@ extern int fec_mii_wait(struct net_devic
 extern void fec_mii(struct net_device *dev);
 
 extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
+
+#ifdef CONFIG_PM
+extern void fec_mii_suspend(struct net_device *dev);
+extern void fec_mii_resume(struct net_device *dev);
+#endif
#4 lore raw

PATCH 4/7 mpc52xx suspend: USB

In reply to Domen Puncer

Trivial suspend and resume OF OHCI.
On MPC52xx turn off and on power to ports.

drivers/usb/host/ohci-ppc-of.c +28 -2
Index: grant.git/drivers/usb/host/ohci-ppc-of.c
===================================================================
@@ -214,6 +214,32 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_
 #endif
 
 
+#ifdef CONFIG_PM
+static u32 descr_a;
+static int ohci_hcd_ppc_soc_drv_suspend(struct of_device *op,
+		pm_message_t state)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+#ifdef CONFIG_PPC_MPC52xx
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	descr_a = in_be32(&ohci->regs->roothub.a);
+	out_be32(&ohci->regs->roothub.a, (descr_a & ~0x200) | 0x100);
+#endif
+	return 0;
+}
+static int ohci_hcd_ppc_soc_drv_resume(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+#ifdef CONFIG_PPC_MPC52xx
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	out_be32(&ohci->regs->roothub.a, descr_a);
+#endif
+	return 0;
+}
+#endif
+
 static struct of_platform_driver ohci_hcd_ppc_of_driver = {
 	.name		= "ppc-of-ohci",
 	.match_table	= ohci_hcd_ppc_of_match,
@@ -221,8 +247,8 @@ static struct of_platform_driver ohci_hc
 	.remove		= ohci_hcd_ppc_of_remove,
 	.shutdown 	= ohci_hcd_ppc_of_shutdown,
 #ifdef CONFIG_PM
-	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
-	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+	.suspend	= ohci_hcd_ppc_soc_drv_suspend,
+	.resume		= ohci_hcd_ppc_soc_drv_resume,
 #endif
 	.driver		= {
 		.name	= "ppc-of-ohci",
#5 lore raw

PATCH 5/7 mpc52xx suspend: deep-sleep

In reply to Domen Puncer

Implement deep-sleep on MPC52xx.
SDRAM is put into self-refresh with help of SRAM code (alternatives would be code in FLASH, I-cache). Interrupt code must also not be in SDRAM, so put it in I-cache.
MPC52xx core is static, so contents will remain intact even with clocks turned off.

There seems to be a race with decrementer interrupt (uncomment #define TESTING, and execute echo standby > /sys/power/state couple thousands of times to reproduce it). :-(

arch/powerpc/platforms/52xx/Makefile +2 -0
Index: grant.git/arch/powerpc/platforms/52xx/Makefile
===================================================================
@@ -10,3 +10,5 @@ endif
 
 obj-$(CONFIG_PPC_EFIKA)		+= efika.o
 obj-$(CONFIG_PPC_LITE5200)	+= lite5200.o
+
+obj-$(CONFIG_PM)		+= mpc52xx_sleep.o mpc52xx_pm.o
arch/powerpc/platforms/52xx/mpc52xx_pm.c new file +123 -0

123 lines not on this page · raw message

arch/powerpc/platforms/52xx/mpc52xx_sleep.S new file +277 -0

277 lines not on this page · raw message

#6 lore raw

PATCH 6/7 lite5200b suspend: PIC

In reply to Domen Puncer

Save and restore MPC52xx PIC registers.

arch/powerpc/platforms/52xx/mpc52xx_pic.c +42 -0
Index: grant.git/arch/powerpc/platforms/52xx/mpc52xx_pic.c
===================================================================
@@ -471,3 +471,45 @@ unsigned int mpc52xx_get_irq(void)
 
 	return irq_linear_revmap(mpc52xx_irqhost, irq);
 }
+
+#ifdef CONFIG_PM
+/* save and restore registers for suspend to ram */
+static struct mpc52xx_intr saved_intr;
+void mpc52xx_pic_suspend(void)
+{
+	saved_intr.per_mask = in_be32(&intr->per_mask);
+	saved_intr.per_pri1 = in_be32(&intr->per_pri1);
+	saved_intr.per_pri2 = in_be32(&intr->per_pri2);
+	saved_intr.per_pri3 = in_be32(&intr->per_pri3);
+	saved_intr.ctrl =     in_be32(&intr->ctrl);
+	saved_intr.main_mask = in_be32(&intr->main_mask);
+	saved_intr.main_pri1 = in_be32(&intr->main_pri1);
+	saved_intr.main_pri2 = in_be32(&intr->main_pri2);
+	saved_intr.reserved1 = in_be32(&intr->reserved1);
+	saved_intr.enc_status = in_be32(&intr->enc_status);
+	saved_intr.crit_status = in_be32(&intr->crit_status);
+	saved_intr.main_status = in_be32(&intr->main_status);
+	saved_intr.per_status = in_be32(&intr->per_status);
+	saved_intr.reserved2 = in_be32(&intr->reserved2);
+	saved_intr.per_error = in_be32(&intr->per_error);
+}
+
+void mpc52xx_pic_resume(void)
+{
+	out_be32(&intr->per_mask, saved_intr.per_mask);
+	out_be32(&intr->per_pri1, saved_intr.per_pri1);
+	out_be32(&intr->per_pri2, saved_intr.per_pri2);
+	out_be32(&intr->per_pri3, saved_intr.per_pri3);
+	out_be32(&intr->ctrl,     saved_intr.ctrl);
+	out_be32(&intr->main_mask, saved_intr.main_mask);
+	out_be32(&intr->main_pri1, saved_intr.main_pri1);
+	out_be32(&intr->main_pri2, saved_intr.main_pri2);
+	out_be32(&intr->reserved1, saved_intr.reserved1);
+	out_be32(&intr->enc_status, saved_intr.enc_status);
+	out_be32(&intr->crit_status, saved_intr.crit_status);
+	out_be32(&intr->main_status, saved_intr.main_status);
+	out_be32(&intr->per_status, saved_intr.per_status);
+	out_be32(&intr->reserved2, saved_intr.reserved2);
+	out_be32(&intr->per_error, saved_intr.per_error);
+}
+#endif
#7 lore raw

PATCH 1/1 support lite5200b wakeup in u-boot

In reply to Domen Puncer

U-Boot part of Lite5200b low power mode support. Puts SDRAM out of self-refresh and transfers control to address saved at physical 0x0

board/icecube/icecube.c +50 -0
index 9b222da..4b35776 100644
@@ -42,6 +42,54 @@ # else
 #include "mt48lc16m16a2-75.h"
 # endif
 #endif
+
+#ifdef CONFIG_LITE5200B
+/* u-boot part of low-power mode implementation */
+#define SAVED_ADDR (*(void **)0x00000000)
+#define PSC2_4 0x02
+
+void lite5200b_wakeup(void)
+{
+	unsigned char wakeup_pin;
+	void (*linux_wakeup)(void);
+
+	/* check PSC2_4, if it's down "QT" is signaling we have a wakeup
+	 * from low power mode */
+	*(vu_char *)MPC5XXX_WU_GPIO_ENABLE = PSC2_4;
+	__asm__ volatile ("sync");
+
+	wakeup_pin = *(vu_char *)MPC5XXX_WU_GPIO_DATA_I;
+	if (wakeup_pin & PSC2_4)
+		return;
+
+	/* acknowledge to "QT"
+	 * by holding pin at 1 for 10 uS */
+	*(vu_char *)MPC5XXX_WU_GPIO_DIR = PSC2_4;
+	__asm__ volatile ("sync");
+	*(vu_char *)MPC5XXX_WU_GPIO_DATA = PSC2_4;
+	__asm__ volatile ("sync");
+	udelay(10);
+
+	/* put ram out of self-refresh */
+	*(vu_long *)MPC5XXX_SDRAM_CTRL |= 0x80000000;	// mode_en
+	__asm__ volatile ("sync");
+	*(vu_long *)MPC5XXX_SDRAM_CTRL |= 0x50000000;	// cke ref_en
+	__asm__ volatile ("sync");
+	*(vu_long *)MPC5XXX_SDRAM_CTRL &= ~0x80000000;	// !mode_en
+	__asm__ volatile ("sync");
+	udelay(10); /* wait a bit */
+
+	/* jump back to linux kernel code */
+	linux_wakeup = SAVED_ADDR;
+	printf("\n\nLooks like we just woke, transferring control to 0x%08lx\n",
+			linux_wakeup);
+	linux_wakeup();
+}
+#else
+#define lite5200b_wakeup
+#endif
+
+
 #ifndef CFG_RAMBOOT
 static void sdram_start (int hi_addr)
 {
@@ -208,6 +256,8 @@ #endif /* CFG_RAMBOOT */
 		__asm__ volatile ("sync");
 	}
 
+	lite5200b_wakeup();
+
 	return dramsize + dramsize2;
 }
 
include/mpc5xxx.h +1 -0
index 1d20d1d..c7eb090 100644
@@ -189,6 +189,7 @@ #define MPC5XXX_WU_GPIO_ENABLE  (MPC5XXX
 #define MPC5XXX_WU_GPIO_ODE     (MPC5XXX_WU_GPIO + 0x0004)
 #define MPC5XXX_WU_GPIO_DIR     (MPC5XXX_WU_GPIO + 0x0008)
 #define MPC5XXX_WU_GPIO_DATA    (MPC5XXX_WU_GPIO + 0x000c)
+#define MPC5XXX_WU_GPIO_DATA_I  (MPC5XXX_WU_GPIO + 0x0020)
 
 /* PCI registers */
 #define MPC5XXX_PCI_CMD		(MPC5XXX_PCI + 0x04)
#8 lore raw

Re: [u-boot patch] support lite5200b wakeup in u-boot

Quoted 3 lines · Domen Puncer

U-Boot part of Lite5200b low power mode support. Puts SDRAM out of self-refresh and transfers control to address saved at physical 0x0

Please post this patch to the U-Boot mailing list.

Best regards,
Stefan

#9 lore raw

PATCH 7/7 lite5200b suspend: low-power mode

In reply to Domen Puncer

Low-power mode implementation for Lite5200b.

A patch to U-Boot that wakes up SDRAM, and transfers control to address saved at physical 0x0 is needed.

arch/powerpc/platforms/52xx/lite5200_pm.c new file +101 -0
Index: grant.git/arch/powerpc/platforms/52xx/lite5200_pm.c
===================================================================
@@ -0,0 +1,101 @@
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include "bestcomm.h"
+
+extern void lite5200_low_power(void *sram, void *mbar);
+extern int mpc52xx_pm_enter(suspend_state_t);
+extern void mpc52xx_pic_suspend(void);
+extern void mpc52xx_pic_resume(void);
+
+static int lite5200_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int lite5200_pm_prepare(suspend_state_t state)
+{
+	return 0;
+}
+
+static int lite5200_pm_enter(suspend_state_t state)
+{
+	int err = 0;
+	struct mpc52xx_gpio __iomem *gpio;
+	void __iomem *mbar;
+	u32 gpio_saved_pc;
+
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY)
+		return mpc52xx_pm_enter(state);
+
+	if (state != PM_SUSPEND_MEM)
+		return -ENOSYS;
+
+	/* Map zones */
+	gpio = mpc52xx_find_and_map("mpc5200-gpio");
+	if (!gpio) {
+		printk(KERN_ERR "%s:%i Error mapping io zones\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+
+	/* save ie. ethernet pins configuration */
+	gpio_saved_pc = in_be32(&gpio->port_config);
+
+	mpc52xx_sdma_suspend();
+	mpc52xx_pic_suspend();
+
+
+	mbar = ioremap_nocache(0xf0000000, 0x8000);
+	/* is there a nicer way? */
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		err = -ENOSYS;
+		goto out_unmap;
+	}
+	lite5200_low_power(sdma.sram, mbar);
+	iounmap(mbar);
+
+
+	out_be32(&gpio->port_config, gpio_saved_pc);
+	iounmap(gpio);
+
+	mpc52xx_setup_cpu();
+
+	mpc52xx_pic_resume();
+	mpc52xx_sdma_resume();
+
+	return 0;
+
+ out_unmap:
+	iounmap(gpio);
+	return err;
+}
+
+static int lite5200_pm_finish(suspend_state_t state)
+{
+	return 0;
+}
+
+static struct pm_ops lite5200_pm_ops = {
+	.valid		= lite5200_pm_valid,
+	.prepare	= lite5200_pm_prepare,
+	.enter		= lite5200_pm_enter,
+	.finish		= lite5200_pm_finish,
+};
+
+static int __init lite5200_pm_init(void)
+{
+	pm_set_ops(&lite5200_pm_ops);
+	return 0;
+}
+
+arch_initcall(lite5200_pm_init);
arch/powerpc/platforms/52xx/lite5200_sleep.S new file +419 -0

419 lines not on this page · raw message

arch/powerpc/platforms/52xx/Makefile +3 -0
Index: grant.git/arch/powerpc/platforms/52xx/Makefile
===================================================================
@@ -12,3 +12,6 @@ obj-$(CONFIG_PPC_EFIKA)		+= efika-setup.
 obj-$(CONFIG_PPC_LITE5200)	+= lite5200.o
 
 obj-$(CONFIG_PM)		+= mpc52xx_sleep.o mpc52xx_pm.o
+ifeq ($(CONFIG_PPC_LITE5200),y)
+	obj-$(CONFIG_PM)	+= lite5200_sleep.o lite5200_pm.o
+endif
arch/powerpc/platforms/52xx/mpc52xx_common.c +1 -1
Index: grant.git/arch/powerpc/platforms/52xx/mpc52xx_common.c
===================================================================
@@ -76,7 +76,7 @@ mpc52xx_find_ipb_freq(struct device_node
 EXPORT_SYMBOL(mpc52xx_find_ipb_freq);
 
 
-void __init
+void
 mpc52xx_setup_cpu(void)
 {
 	struct mpc52xx_cdm  __iomem *cdm;
#10 lore raw

Re: [PATCH 7/7] lite5200b suspend: low-power mode

Quoted 2 lines · Domen Puncer
(quoted diff) +2 -0
+static int lite5200_pm_enter(suspend_state_t state)
+{

[snip]

arch/powerpc/platforms/52xx/lite5200_pm.c line 57

Quoted 1 line
arch/powerpc/platforms/52xx/lite5200_pm.c new file +1 -0
+	mbar = ioremap_nocache(0xf0000000, 0x8000);

You can't do ioremap with interrupts disabled (it will fail with spinlock debugging enabled); the mapping should be set up at boot time.

-Scott

#11 lore raw

Re: [PATCH 7/7] lite5200b suspend: low-power mode

Quoted 10 lines · Scott Wood
Quoted 2 lines · Domen Puncer
(quoted diff) +2 -0
+static int lite5200_pm_enter(suspend_state_t state)
+{

[snip]

arch/powerpc/platforms/52xx/lite5200_pm.c line 57

Quoted 1 line
arch/powerpc/platforms/52xx/lite5200_pm.c new file +1 -0
+	mbar = ioremap_nocache(0xf0000000, 0x8000);

You can't do ioremap with interrupts disabled (it will fail with spinlock debugging enabled); the mapping should be set up at boot time.

From what I see, it could also be set up in prepare(), no?

I'll try that with spinlock debugging on monday.

Thanks!

Domen

Quoted 2 lines

-Scott

#12 lore raw
In reply to Domen Puncer
Quoted 7 lines · Domen Puncer

Hi!

Patches are based on latest mainline git tree + fec patches:
Fec_MPC5200_eth_driver.patch Copy_bestcomm_support_files_into_arch_powerpc.patch Make_FEC_work_on_the_lite5200.patch

---8<---snip--->8---

Quoted 2 lines

I would appreaciate any comments, suggestions etc.

Cool, good work. I'll try to do a proper review today.

Note on the Bestcomm stuff; the patches that you've referenced above will not be going into mainline. They will be replaced by a new set of bestcomm/FEC patches, hopfully in the .22 timeframe, so your patches there will need some rework.

Cheers,
g.

Signature · 4 lines
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
[email protected]
(403) 399-0195
#13 lore raw

New Bestcomm/FEC patches (was: Re: [PATCH 0/7] MPC5200 and Lite5200b low power modes)

Quoted 9 lines · Grant Likely
Quoted 7 lines · Domen Puncer

Hi!

Patches are based on latest mainline git tree + fec patches:
Fec_MPC5200_eth_driver.patch Copy_bestcomm_support_files_into_arch_powerpc.patch Make_FEC_work_on_the_lite5200.patch

---8<---snip--->8---

Quoted 8 lines
Quoted 1 line

I would appreaciate any comments, suggestions etc.

Cool, good work. I'll try to do a proper review today.

Note on the Bestcomm stuff; the patches that you've referenced above will not be going into mainline. They will be replaced by a new set of bestcomm/FEC patches, hopfully in the .22 timeframe, so your patches there will need some rework.

Hello,

I am working on porting arch/powerpc Linux to a custom MPC5200B-based board, and currently using your 52xx-dev branch. Is this new set of bestcomm/FEC patches already in any of your publicly available branches, or is it something completely fresh? I am seeing some networking problems, and would be interested in giving new patches a try.

Regards,
Bartlomiej

#14 lore raw

Re: New Bestcomm/FEC patches (was: Re: [PATCH 0/7] MPC5200 and Lite5200b low power modes)

Quoted 19 lines · Bartlomiej Sieka
Quoted 9 lines · Grant Likely
Quoted 7 lines · Domen Puncer

Hi!

Patches are based on latest mainline git tree + fec patches:
Fec_MPC5200_eth_driver.patch Copy_bestcomm_support_files_into_arch_powerpc.patch Make_FEC_work_on_the_lite5200.patch

---8<---snip--->8---

Quoted 8 lines
Quoted 1 line

I would appreaciate any comments, suggestions etc.

Cool, good work. I'll try to do a proper review today.

Note on the Bestcomm stuff; the patches that you've referenced above will not be going into mainline. They will be replaced by a new set of bestcomm/FEC patches, hopfully in the .22 timeframe, so your patches there will need some rework.

Quoted 7 lines

Hello,

I am working on porting arch/powerpc Linux to a custom MPC5200B-based board, and currently using your 52xx-dev branch. Is this new set of bestcomm/FEC patches already in any of your publicly available branches, or is it something completely fresh? I am seeing some networking problems, and would be interested in giving new patches a try.

Patches I used were from Grant's 52xx-dev branch.

Domen

Quoted 10 lines

Regards,
Bartlomiej

_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

#15 lore raw
In reply to Domen Puncer

Hi,

Thanks for providing theses.
I hadn't a chance to test them yet, I'll try that this week end. A couple of comments already though :

- Is saving the SDMA / PIC registers necessary ? Doesn't the cpu keep
those when at sleep ?
- And if it is, won't a memcpy_io of the whole zone do the trick ?
- On a more general note, there seem to be a lot of stuff decided by
#ifdef ... that's not really good as we can build a single kernel that could run on several platform so those need to somehow be enable disabled dynamically.
- I may miss something but turning port power off for USB seem like a
sane thing to do for every one. Isn't that implemented somehow for all controller somewhere ?

Sylvain

Quoted 29 lines · Domen Puncer

Hi!

Patches are based on latest mainline git tree + fec patches:
Fec_MPC5200_eth_driver.patch Copy_bestcomm_support_files_into_arch_powerpc.patch Make_FEC_work_on_the_lite5200.patch

This patchset includes the following patches:
- [PATCH 1/7] mpc52xx suspend: bestcomm
- [PATCH 2/7] mpc52xx suspend: UART
- [PATCH 3/7] mpc52xx suspend: FEC (ethernet)
- [PATCH 4/7] mpc52xx suspend: USB
- [PATCH 5/7] mpc52xx suspend: deep-sleep
- [PATCH 6/7] lite5200b suspend: PIC
- [u-boot patch] support lite5200b wakeup in u-boot
- [PATCH 7/7] lite5200b suspend: low-power mode

I would appreaciate any comments, suggestions etc.

Domen
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

#16 lore raw
Quoted 8 lines · Sylvain Munaut

Hi,

Thanks for providing theses.
I hadn't a chance to test them yet, I'll try that this week end. A couple of comments already though :

- Is saving the SDMA / PIC registers necessary ? Doesn't the cpu keep
those when at sleep ?

For deep-sleep this is true, but not for low-power mode (the CPU isn't even powered in that case).

Quoted 1 line

- And if it is, won't a memcpy_io of the whole zone do the trick ?

Oh, nice. I wasn't aware of _memcpy_{to,from}io. I'll try it.

Quoted 4 lines

- On a more general note, there seem to be a lot of stuff decided by
#ifdef ... that's not really good as we can build a single kernel that could run on several platform so those need to somehow be enable disabled dynamically.

CONFIG_PM - well... it doesn't make sense too keep the code if
power management is disabled.
SELF_REFRESH, TESTING - both are provided for debugging, final
version is former on, latter off.

Quoted 3 lines

- I may miss something but turning port power off for USB seem like a
sane thing to do for every one. Isn't that implemented somehow for all controller somewhere ?

The "USB power led" on lite5200b says it isn't.

Thanks!

Domen

#17 lore raw

Endianness versus too many byte swaps??

This is probably a Timur question, but any enlightment is appreciated. = This concerns Linux-2.6.17.11 from kernel.org with some modifications = for our custom 8541 board. The original BSP was evolved from = mpc85xx_cds.
=20
Down in the guts of arch/ppc/syslib/ppc85xx_seteup.c is a routine called = mpc85xx_setup_pci1(). In this routine we do an assignment of some = outbound window registers and I am most interested in POTAR2, POWAR2 & = POWBAR2 right now.
=20
This routine uses a ccsr_pci struct to assign potar2, powar2, powbar2 = and others like this:
=20
pci->potar2 =3D 0x00100000;
pci->powar2 =3D 0x8004401a;
pci->powbar2 =3D 0x00888000;
=20
Where I have changed the constants for our board. The issue is that when = I call readl to read back these same registers at the end of this same = subroutine, I get into endianess issues. That is, I read back =20
POTAR2 =3D=3D 0x00001000
POWAR2 =3D=3D 0x1A400480
POWBAR2 =3D=3D 0x00800800
=20
Where the four bytes in each 32bit word are now exchanged so that = 80_04_40_1A became 1A_40_04_80.
=20
I understand big versus little endian, that isn't the question. The = question is "What is really in the POTAR2, POWAR2 & POWBAR2 registers = and how can I prove that what is in the registers is really what I wish = to be in the registers?"
=20
It may be that one or more endian swap things are going on within Linux = and I have inherited some source from others, so actually proving what = is in the registers is becoming important.
=20
Charles

#18 lore raw
In reply to Domen Puncer
Quoted 10 lines · Domen Puncer
Quoted 8 lines · Sylvain Munaut

Hi,

Thanks for providing theses.
I hadn't a chance to test them yet, I'll try that this week end. A couple of comments already though :

- Is saving the SDMA / PIC registers necessary ? Doesn't the cpu keep
those when at sleep ?

Quoted 6 lines

For deep-sleep this is true, but not for low-power mode (the CPU isn't even powered in that case).

Quoted 1 line

- And if it is, won't a memcpy_io of the whole zone do the trick ?

Oh, nice. I wasn't aware of _memcpy_{to,from}io. I'll try it.

OK, one can't copy the whole zone :-(
Ie. reading from MBAR+0x3B00 seems to freeze Linux.

Currently I'm having something like (obsoletes PIC and SDMA patches):

arch/powerpc/platforms/52xx/lite5200_pm.c new file +125 -0
Index: grant.git/arch/powerpc/platforms/52xx/lite5200_pm.c
===================================================================
@@ -0,0 +1,125 @@
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include "mpc52xx_pic.h"
+#include "bestcomm.h"
+
+extern void lite5200_low_power(void *sram, void *mbar);
+extern int mpc52xx_pm_enter(suspend_state_t);
+extern int mpc52xx_pm_prepare(suspend_state_t);
+
+static void __iomem *mbar;
+
+static int lite5200_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int lite5200_pm_prepare(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY)
+		return mpc52xx_pm_prepare(state);
+
+	if (state != PM_SUSPEND_MEM)
+		return -EINVAL;
+
+	/* map registers */
+	mbar = ioremap_nocache(0xf0000000, 0x8000);
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+/* save and restore registers not bound to any real devices */
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_cdm scdm;
+static struct mpc52xx_intr __iomem *pic;
+static struct mpc52xx_intr spic;
+static struct mpc52xx_sdma __iomem *bes;
+static struct mpc52xx_sdma sbes;
+static struct mpc52xx_xlb __iomem *xlb;
+static struct mpc52xx_xlb sxlb;
+static struct mpc52xx_gpio __iomem *gps;
+static struct mpc52xx_gpio sgps;
+static struct mpc52xx_gpio_wkup __iomem *gpw;
+static struct mpc52xx_gpio_wkup sgpw;
+extern char saved_sram[0x4000];
+
+static void lite5200_save_regs(void)
+{
+	_memcpy_fromio(&sbes, bes, sizeof(*bes));
+	_memcpy_fromio(&spic, pic, sizeof(*pic));
+	_memcpy_fromio(&scdm, cdm, sizeof(*cdm));
+	_memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
+	_memcpy_fromio(&sgps, gps, sizeof(*gps));
+	_memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
+
+	memcpy(saved_sram, sdma.sram, sdma.sram_size);
+}
+
+static void lite5200_restore_regs(void)
+{
+	memcpy(sdma.sram, saved_sram, sdma.sram_size);
+
+	_memcpy_toio(gpw, &sgpw, sizeof(*gpw));
+	_memcpy_toio(gps, &sgps, sizeof(*gps));
+	_memcpy_toio(xlb, &sxlb, sizeof(*xlb));
+	_memcpy_toio(cdm, &scdm, sizeof(*cdm));
+	_memcpy_toio(pic, &spic, sizeof(*pic));
+	_memcpy_toio(bes, &sbes, sizeof(*bes));
+}
+
+static int lite5200_pm_enter(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY) {
+		return mpc52xx_pm_enter(state);
+	}
+
+	cdm = mbar + 0x200;
+	pic = mbar + 0x500;
+	gps = mbar + 0xb00;
+	gpw = mbar + 0xc00;
+	bes = mbar + 0x1200;
+	xlb = mbar + 0x1f00;
+	lite5200_save_regs();
+
+	lite5200_low_power(sdma.sram, mbar);
+
+	lite5200_restore_regs();
+
+	iounmap(mbar);
+	return 0;
+}
+
+static int lite5200_pm_finish(suspend_state_t state)
+{
+	return 0;
+}
+
+static struct pm_ops lite5200_pm_ops = {
+	.valid		= lite5200_pm_valid,
+	.prepare	= lite5200_pm_prepare,
+	.enter		= lite5200_pm_enter,
+	.finish		= lite5200_pm_finish,
+};
+
+static int __init lite5200_pm_init(void)
+{
+	pm_set_ops(&lite5200_pm_ops);
+	return 0;
+}
+
+arch_initcall(lite5200_pm_init);
#19 lore raw
Quoted 19 lines · Domen Puncer
Quoted 17 lines · Domen Puncer
Quoted 9 lines · Sylvain Munaut

Hi,

Thanks for providing theses.
I hadn't a chance to test them yet, I'll try that this week end. A couple of comments already though :

- Is saving the SDMA / PIC registers necessary ? Doesn't the cpu keep
those when at sleep ?

For deep-sleep this is true, but not for low-power mode (the CPU isn't even powered in that case).

Quoted 2 lines

- And if it is, won't a memcpy_io of the whole zone do the trick ?

Quoted 8 lines
Quoted 2 lines

Oh, nice. I wasn't aware of _memcpy_{to,from}io. I'll try it.

OK, one can't copy the whole zone :-(
Ie. reading from MBAR+0x3B00 seems to freeze Linux.

Currently I'm having something like (obsoletes PIC and SDMA patches):

And does that work ?

I was also wondering if some registers don't need to be restored last. For example,
the task status in sdma would be restored to 0 then just at the end set to their "real value".

Saving / Restoring all theses system zones makes more sense to me than to just save / restore the pic & sdma and hoping than mpc52xx_setup_cpu will make the rest ...

But saving/restoring all the mbar isn't good either because peripheral drivers should handle their own setup restore. The suspend / resume method of the peripheral should differentiate how deep their suspending / resuming and do what's necessary accordingly.

Sylvain

Quoted 133 lines

Index: grant.git/arch/powerpc/platforms/52xx/lite5200_pm.c
===================================================================

arch/powerpc/platforms/52xx/lite5200_pm.c new file +125 -0
@@ -0,0 +1,125 @@
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include "mpc52xx_pic.h"
+#include "bestcomm.h"
+
+extern void lite5200_low_power(void *sram, void *mbar);
+extern int mpc52xx_pm_enter(suspend_state_t);
+extern int mpc52xx_pm_prepare(suspend_state_t);
+
+static void __iomem *mbar;
+
+static int lite5200_pm_valid(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int lite5200_pm_prepare(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY)
+		return mpc52xx_pm_prepare(state);
+
+	if (state != PM_SUSPEND_MEM)
+		return -EINVAL;
+
+	/* map registers */
+	mbar = ioremap_nocache(0xf0000000, 0x8000);
+	if (!mbar) {
+		printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+/* save and restore registers not bound to any real devices */
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_cdm scdm;
+static struct mpc52xx_intr __iomem *pic;
+static struct mpc52xx_intr spic;
+static struct mpc52xx_sdma __iomem *bes;
+static struct mpc52xx_sdma sbes;
+static struct mpc52xx_xlb __iomem *xlb;
+static struct mpc52xx_xlb sxlb;
+static struct mpc52xx_gpio __iomem *gps;
+static struct mpc52xx_gpio sgps;
+static struct mpc52xx_gpio_wkup __iomem *gpw;
+static struct mpc52xx_gpio_wkup sgpw;
+extern char saved_sram[0x4000];
+
+static void lite5200_save_regs(void)
+{
+	_memcpy_fromio(&sbes, bes, sizeof(*bes));
+	_memcpy_fromio(&spic, pic, sizeof(*pic));
+	_memcpy_fromio(&scdm, cdm, sizeof(*cdm));
+	_memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
+	_memcpy_fromio(&sgps, gps, sizeof(*gps));
+	_memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
+
+	memcpy(saved_sram, sdma.sram, sdma.sram_size);
+}
+
+static void lite5200_restore_regs(void)
+{
+	memcpy(sdma.sram, saved_sram, sdma.sram_size);
+
+	_memcpy_toio(gpw, &sgpw, sizeof(*gpw));
+	_memcpy_toio(gps, &sgps, sizeof(*gps));
+	_memcpy_toio(xlb, &sxlb, sizeof(*xlb));
+	_memcpy_toio(cdm, &scdm, sizeof(*cdm));
+	_memcpy_toio(pic, &spic, sizeof(*pic));
+	_memcpy_toio(bes, &sbes, sizeof(*bes));
+}
+
+static int lite5200_pm_enter(suspend_state_t state)
+{
+	/* deep sleep? let mpc52xx code handle that */
+	if (state == PM_SUSPEND_STANDBY) {
+		return mpc52xx_pm_enter(state);
+	}
+
+	cdm = mbar + 0x200;
+	pic = mbar + 0x500;
+	gps = mbar + 0xb00;
+	gpw = mbar + 0xc00;
+	bes = mbar + 0x1200;
+	xlb = mbar + 0x1f00;
+	lite5200_save_regs();
+
+	lite5200_low_power(sdma.sram, mbar);
+
+	lite5200_restore_regs();
+
+	iounmap(mbar);
+	return 0;
+}
+
+static int lite5200_pm_finish(suspend_state_t state)
+{
+	return 0;
+}
+
+static struct pm_ops lite5200_pm_ops = {
+	.valid		= lite5200_pm_valid,
+	.prepare	= lite5200_pm_prepare,
+	.enter		= lite5200_pm_enter,
+	.finish		= lite5200_pm_finish,
+};
+
+static int __init lite5200_pm_init(void)
+{
+	pm_set_ops(&lite5200_pm_ops);
+	return 0;
+}
+
+arch_initcall(lite5200_pm_init);
#20 lore raw
Quoted 8 lines · Sylvain Munaut
Quoted 7 lines · Domen Puncer
Quoted 6 lines
Quoted 4 lines

- And if it is, won't a memcpy_io of the whole zone do the trick ?

Oh, nice. I wasn't aware of _memcpy_{to,from}io. I'll try it.

Quoted 6 lines
Quoted 5 lines

OK, one can't copy the whole zone :-(
Ie. reading from MBAR+0x3B00 seems to freeze Linux.

Currently I'm having something like (obsoletes PIC and SDMA patches):

And does that work ?

Yes, it does.

Quoted 5 lines

I was also wondering if some registers don't need to be restored last. For example,
the task status in sdma would be restored to 0 then just at the end set to their "real value".

I was wondering about that, but it seems to work as-is. Any real test cases for which it would matter?

Quoted 9 lines

Saving / Restoring all theses system zones makes more sense to me than to just save / restore the pic & sdma and hoping than mpc52xx_setup_cpu will make the rest ...

But saving/restoring all the mbar isn't good either because peripheral drivers should handle their own setup restore. The suspend / resume method of the peripheral should differentiate how deep their suspending / resuming and do what's necessary accordingly.

I was aiming for that.

Domen