Underlying Implementation of S3C2416 sleep
Environment: ARM CPUs: S3C2416Linux-Kernel: 3.6.0
For the implementation method of S3C2416 sleep and wake-up, see the previous article:
Analyze the sys/power/state and perform sleep and wake-up for S3C2416.
This article analyzes the underlying implementation of S3C2416 sleep in two parts:
1. CPU-related implementation process
2. How does the kernel Add the sleep wake-up function?
I. CPU-related implementation process
S3C2416 sleep registers are set in the pm-s3c2416.c (same color is called)
Arch/arm/mach-s3c24xx/pm-s3c2416.c
Static int s3c2416_cpu_suspend (unsigned long arg): Enables Sleep and enables the CPU to sleep.
{/* enable wakeup sources regardless of battery state *//* #define S3C2443_PWRCFG_SLEEP(1<<15) */__raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG);/* set the mode as sleep, 2BED represents "Go to BED" */__raw_writel(0x2BED, S3C2443_PWRMODE);s3c2412_sleep_enter();panic("sleep resumed to originator?");}
The _ raw_writel (s3c2443_pwr1__sleep, S3C2443_PWRCFG) function enables the register PWRCFG [15] location 1 to enable the sleep wake-up source, as described in the Manual:
So let's expand. If we do not implement the sleep mode, but the Deep-Stop mode, we can operate the 2nd registers according to the sample operation register PWRCFG [16] bit, you can understand it. In the same way, you can change the Power mode to operate the corresponding register.
Here is a question: (in the stop mode (NZ unknown? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> usage + usage/Wo6y4w7qvyv3TybvjseC0 + usage + HU2c/usage + usage =" brush: java; "> {/** write the magic value u-boot uses to check for resume into * the INFORM0 register, and ensure INFORM1 is set to the * correct address to resume from. */_ raw_writel (0x2BED, S3C2412_INFORM0) ;__ raw_writel (pai_to_phys (initi_cpu_resume), S3C2412_INFORM1 );}Note that the purpose of configuring these two registers is to determine whether a wake-up restart is performed during the U-boot startup, and to obtain the run address after the wake-up recovery. For the first point, you can be very clear about the u-boot:
u-boot-1.3.4/board/samsung/smdk2416/lowlevel_init.S#ifdef CONFIG_PM/* PM check */@ Check if this is a wake-up from sleep ldr r0, =INFORM0_REG/* INFORM0 register */ ldr r1, [r0] ldr r2, =0x2BED cmp r2, r1ldreq r0, =INFORM1_REG/* INFORM1 register */ ldreq r1, [r0] moveq pc, r1 /* end PM check */#endif
The above two functions marked with the background color are called in the s3c2416_pm_add function: static int
S3c2416_pm_add(Struct device * dev, struct subsys_interface * sif) {pm_cpu_prep = s3c2416_pm_prepare; pm_cpu_sleep =
S3c2416_cpu_suspend;
Return 0;} pm_cpu_prep and pm_cpu_sleep are two function pointers, which are defined as follows:
void (*pm_cpu_prep)(void);int (*pm_cpu_sleep)(unsigned long);
So far, we can infer that the sleep implementation is located at the call of the above two pointers. We can find it in the initi_pm_enter () function: arch/arm/plat-samsung/pm. cstatic int initi_pm_enter (suspend_state_t state) {/* ensure the debug is initialised (if enabled) */initi_pm_debug_init (); initi_pmdbg ("% s (% d) \ n ", _ func __, state);/* If the specific points of the above two pointers are not implemented, that is, no sleep operation function, exit */if (pm_cpu_prep = NULL | pm_cpu_sleep = NULL) {printk (KERN_ERR "% s: error: no cpu sleep function \ n ", _ func _); return-EINVAL ;}
/* Check if we have anything to wake-up...
Bad things seem*
To happen if you suspend with no wakeup(System will often * require a full power-cycle) * // * checks whether the source is set to wake up. if not, exit */if (! Any_allowed (initi_irqwake_intmask, initi_irqwake_intallow )&&! Any_allowed (maid) {printk (KERN_ERR "% s: No wake-up sources! \ N ", _ func _); printk (KERN_ERR" % s:
Aborting sleep\ N ", _ func _); return-EINVAL ;}
/* Save all necessary core registers not covered by the drivers */samsung_pm_save_gpios (); samsung_pm_saved_gpios (); initi_pm_save_uarts (); initi_pm_save_core ();
/* Set the irq configuration for wake */initi_pm_configure_extint (); initi_pmdbg ("sleep: irq wakeup masks: % 08lx, % 08lx \ n", initi_irqwake_intmask, expires );
Initi_pm_arch_prepare_irqs ();
/* Call cpu specific preparation */pm_cpu_prep ();
/* Flush cache back to ram */flush_cache_all ();
Initi_pm_check_store ();
/* Send the cpu to sleep... */initi_pm_arch_stop_clocks ();
/* This will also act as our return point from when * we resume as it saves its own register state and restores it * during the resume .*/
/* Sleep after running here */Cpu_suspend (0, pm_cpu_sleep );
/* Restore the system state * // * the wake-up process is described below. */... return 0 ;}
Ii. How does the kernel Add the sleep wake-up function to the s3c2416_pm_add function mentioned in the previous section? Its call is as follows: static struct subsys_interface s3c2416_pm_interface = {. name = "s3c2416_pm ",. subsys = & s3c2416_subsys ,. add_dev = s3c2416_pm_add ,};
Static _ init int s3c2416_pm_init (void) {return subsys_interface_register (& s3c2416_pm_interface );}
Arch_initcall (
S3c2416_pm_init);
So far, the insertion of sleep and wakeup is realized.
First version. To be modified...