📄 pm.c
字号:
left = CHECK_CHUNKSIZE; ptr = phys_to_virt(addr); if (in_region(ptr, left, crcs, crc_size)) { DBG("skipping %08lx, has crc block in\n", addr); goto skip_check; } if (in_region(ptr, left, save_at, 32*4 )) { DBG("skipping %08lx, has save block in\n", addr); goto skip_check; } /* calculate and check the checksum */ calc = crc32_le(~0, ptr, left); if (calc != *val) { printk(KERN_ERR PFX "Restore CRC error at " "%08lx (%08x vs %08x)\n", addr, calc, *val); DBG("Restore CRC error at %08lx (%08x vs %08x)\n", addr, calc, *val); } skip_check: val++; } return val;}/* s3c2410_pm_check_restore * * check the CRCs after the restore event and free the memory used * to hold them*/static void s3c2410_pm_check_restore(void){ if (crcs != NULL) { s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); kfree(crcs); crcs = NULL; }}#else#define s3c2410_pm_check_prepare() do { } while(0)#define s3c2410_pm_check_restore() do { } while(0)#define s3c2410_pm_check_store() do { } while(0)#endif/* helper functions to save and restore register state */void s3c2410_pm_do_save(struct sleep_save *ptr, int count){ for (; count > 0; count--, ptr++) { ptr->val = __raw_readl(ptr->reg); DBG("saved %p value %08lx\n", ptr->reg, ptr->val); }}/* s3c2410_pm_do_restore * * restore the system from the given list of saved registers * * Note, we do not use DBG() in here, as the system may not have * restore the UARTs state yet*/void s3c2410_pm_do_restore(struct sleep_save *ptr, int count){ for (; count > 0; count--, ptr++) { printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", ptr->reg, ptr->val, __raw_readl(ptr->reg)); __raw_writel(ptr->val, ptr->reg); }}/* s3c2410_pm_do_restore_core * * similar to s3c2410_pm_do_restore_core * * WARNING: Do not put any debug in here that may effect memory or use * peripherals, as things may be changing!*/static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count){ for (; count > 0; count--, ptr++) { __raw_writel(ptr->val, ptr->reg); }}/* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from)*/static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask){ int i; which &= ~mask; for (i = 0; i <= 31; i++) { if ((which) & (1L<<i)) { DBG("IRQ %d asserted at resume\n", start+i); } }}/* s3c2410_pm_check_resume_pin * * check to see if the pin is configured correctly for sleep mode, and * make any necessary adjustments if it is not*/static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs){ unsigned long irqstate; unsigned long pinstate; int irq = s3c2410_gpio_getirq(pin); if (irqoffs < 4) irqstate = s3c_irqwake_intmask & (1L<<irqoffs); else irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); pinstate = s3c2410_gpio_getcfg(pin); pinstate >>= S3C2410_GPIO_OFFSET(pin)*2; if (!irqstate) { if (pinstate == 0x02) DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); } else { if (pinstate == 0x02) { DBG("Disabling IRQ %d (pin %d)\n", irq, pin); s3c2410_gpio_cfgpin(pin, 0x00); } }}/* s3c2410_pm_configure_extint * * configure all external interrupt pins*/static void s3c2410_pm_configure_extint(void){ int pin; /* for each of the external interrupts (EINT0..EINT15) we * need to check wether it is an external interrupt source, * and then configure it as an input if it is not */ for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); } for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); }}#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))/* s3c2410_pm_enter * * central control for sleep/resume process*/static int s3c2410_pm_enter(suspend_state_t state){ unsigned long regs_save[16]; unsigned long tmp; /* ensure the debug is initialised (if enabled) */ s3c2410_pm_debug_init(); DBG("s3c2410_pm_enter(%d)\n", state); if (state != PM_SUSPEND_MEM) { printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); return -EINVAL; } /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); printk(KERN_ERR PFX "Aborting sleep\n"); return -EINVAL; } /* prepare check area if configured */ s3c2410_pm_check_prepare(); /* store the physical address of the register recovery block */ s3c2410_sleep_save_phys = virt_to_phys(regs_save); DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); /* ensure at least GESTATUS3 has the resume address */ __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); /* save all necessary core registers not covered by the drivers */ s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); /* set the irq configuration for wake */ s3c2410_pm_configure_extint(); DBG("sleep: irq wakeup masks: %08lx,%08lx\n", s3c_irqwake_intmask, s3c_irqwake_eintmask); __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); /* ack any outstanding external interrupts before we go to sleep */ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); /* flush cache back to ram */ arm920_flush_kern_cache_all(); s3c2410_pm_check_store(); /* send the cpu to sleep... */ __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ s3c2410_cpu_suspend(regs_save); /* restore the cpu state */ cpu_init(); /* unset the return-from-sleep flag, to ensure reset */ tmp = __raw_readl(S3C2410_GSTATUS2); tmp &= S3C2410_GSTATUS2_OFFRESET; __raw_writel(tmp, S3C2410_GSTATUS2); /* restore the system state */ s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); s3c2410_pm_debug_init(); /* check what irq (if any) restored the system */ DBG("post sleep: IRQs 0x%08x, 0x%08x\n", __raw_readl(S3C2410_SRCPND), __raw_readl(S3C2410_EINTPEND)); s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), s3c_irqwake_intmask); s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); DBG("post sleep, preparing to return\n"); s3c2410_pm_check_restore(); /* ok, let's return from sleep */ DBG("S3C2410 PM Resume (post-restore)\n"); return 0;}/* * Called after processes are frozen, but before we shut down devices. */static int s3c2410_pm_prepare(suspend_state_t state){ return 0;}/* * Called after devices are re-setup, but before processes are thawed. */static int s3c2410_pm_finish(suspend_state_t state){ return 0;}/* * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. */static struct pm_ops s3c2410_pm_ops = { .pm_disk_mode = PM_DISK_FIRMWARE, .prepare = s3c2410_pm_prepare, .enter = s3c2410_pm_enter, .finish = s3c2410_pm_finish,};/* s3c2410_pm_init * * Attach the power management functions. This should be called * from the board specific initialisation if the board supports * it.*/int __init s3c2410_pm_init(void){ printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); pm_set_ops(&s3c2410_pm_ops); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -