Power callout

The power callout is a piece of code that resides as part of the startup and is used to put the CPU and SDRAM into low-power states. The Neutrino kernel doesn't automatically call the power callout to put the system into a low-power mode. A user application (typically a Power Manager application) will make the decision to power down the system and call the power callout via the sysmgr_cpumode() kernel call (see the sample program later in this technote).

The advantage of putting the power-down code into the power callout is that the kernel will lock the system to prevent applications from running. The Power Manager application is responsible for notifying any other applications and device drivers of any power-state changes before calling the power callout, so that they can prepare for the upcoming power-mode change (i.e. save their state). The function prototype to invoke the power callout is:

int sysmgr_cpumode(int mode);

A power callout may support multiple modes to put the CPU into different power modes. The mode parameter is used by the Power Manager to select the power mode the power callout will put the system into.

Note: In the case of IFS Restoration, the mode parameter may not be used, since there may be only one power mode: turning the CPU off.

The power callout code is custom for each CPU/board. It must be position-independent code (PIC) and written in assembly. For more information on writing a power callout, see "Callout information" and "Writing your own kernel callout" in the Customizing Image Startup Programs chapter of Building Embedded Systems.

As an overview, the easiest way to start writing a power callout is to copy the reboot callout. For example, in the EDOSK7780 startup, make a copy of callout_reboot_edosk7780.s and rename it to callout_power_edosk7780.s. In the CALLOUT_START and CALLOUT_END, change the reboot_sh_edosk7780 references to power_sh_edosk7780. In between CALLOUT_START and CALLOUT_END, insert the assembly instructions required to put the SDRAM into self-refresh and power off the CPU.

# Power Callout Example
    .include "callout.ah"
    .include "asmoff.def"

CALLOUT_START    power_sh_edosk7780, 0, 0

    # Assembly code to power down CPU
    # Globally disable interrupts
    # Pre-fetch final instructions into icache, or jump to code in flash
    # Put SDRAM into self-refresh
    # Sequence to power off CPU (i.e. set GPIO pin connected to external
    #               power controller chip)

CALLOUT_END      power_sh_edosk7780
Note: Because the power callout runs out of RAM that will be put into a self-refresh state (meaning that instructions in RAM can't be accessed), you may need to prefetch the instructions that follow the RAM going into self-refresh into the instruction cache. This will ensure that the instructions can be run when the SDRAM is in self-refresh. Alternatively, you can place a portion of your power callout in static RAM or flash, and then jump to this location to execute the final assembly instructions.

You also need to modify the main.c of startup to tell the kernel the about the power callout:

/* Callout prototypes */
extern struct callout_rtn reboot_sh_edosk7780;
extern struct callout_rtn power_sh_edosk7780;

/* Kernel callout array */
const struct callout_slot callouts[] = {
    { CALLOUT_SLOT( reboot, _sh_edosk7780 ) },
    { CALLOUT_SLOT( power, _sh_edosk7780 ) }, 
};