MPC5200 and Lite5200b low power modes
Subsystems (5)
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
PATCH 1/7 mpc52xx suspend: bestcomm
Save and restore bestcomm registers and SRAM.
arch/powerpc/platforms/52xx/bestcomm.c +71 -0
@@ -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
@@ -473,6 +473,11 @@ extern void *sdma_sram_alloc(int size, iextern 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__ */
PATCH 2/7 mpc52xx suspend: UART
In reply to Domen PuncerMPC52xx 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
@@ -418,6 +418,22 @@ mpc52xx_uart_verify_port(struct uart_porreturn 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,
PATCH 3/7 mpc52xx suspend: FEC (ethernet)
In reply to Domen PuncerSuspend 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
@@ -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
@@ -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
@@ -71,3 +71,8 @@ extern int fec_mii_wait(struct net_devicextern 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
PATCH 4/7 mpc52xx suspend: USB
In reply to Domen PuncerTrivial suspend and resume OF OHCI.
On MPC52xx turn off and on power to ports.
drivers/usb/host/ohci-ppc-of.c +28 -2
@@ -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",
PATCH 5/7 mpc52xx suspend: deep-sleep
In reply to Domen PuncerImplement 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
@@ -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
PATCH 6/7 lite5200b suspend: PIC
In reply to Domen PuncerSave and restore MPC52xx PIC registers.
arch/powerpc/platforms/52xx/mpc52xx_pic.c +42 -0
@@ -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
PATCH 1/1 support lite5200b wakeup in u-boot
In reply to Domen PuncerU-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
@@ -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
@@ -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)
PATCH 7/7 lite5200b suspend: low-power mode
In reply to Domen PuncerLow-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
@@ -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
@@ -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
@@ -76,7 +76,7 @@ mpc52xx_find_ipb_freq(struct device_nodeEXPORT_SYMBOL (mpc52xx_find_ipb_freq); -void __init +void mpc52xx_setup_cpu (void ) {struct mpc52xx_cdm __iomem *cdm;
Re: [u-boot patch] support lite5200b wakeup in u-boot
In reply to Domen PuncerQuoted 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
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
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
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/powerpcLinux 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
Re: [PATCH 7/7] lite5200b suspend: low-power mode
In reply to Domen PuncerQuoted 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
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.patchThis 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 modeI would appreaciate any comments, suggestions etc.
Domen
_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
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_ioof 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
Re: [PATCH 7/7] lite5200b suspend: low-power mode
In reply to Scott WoodQuoted 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
Endianness versus too many byte swaps??
In reply to Domen PuncerThis 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:
=20pci->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
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_ioof 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
@@ -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);
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_ioof 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 fromMBAR+0x3B00seems 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);
Quoted 8 lines · Sylvain Munaut
Quoted 7 lines · Domen Puncer
Quoted 6 lines
Quoted 4 lines
- And if it is, won't a
memcpy_ioof 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 fromMBAR+0x3B00seems 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_cpuwill 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