Powered By Blogger
Showing posts with label kernel. Show all posts
Showing posts with label kernel. Show all posts
Thursday, June 11, 2009

Adding a kernel IOCTL

It is assumed that , the OAL code is cloned to the BSP under development, including the ioctl code. For the purpose of explaining the process, the Mainstone III reference platform will be used.

The BSP specific, ioctl will be located under the directory, MAINSTONEIII\SRC\OAL\OALLIB\ioctl.c.

Now lets assume that we need to implement an ioctl to flag the backing up of system alarm setting during shutdown.

  • Define a new function in ioctl.c as:
BOOL OALIoCtlHalAlarmSet
( UINT32 code, VOID *pInpBuffer,
UINT32 inpSize, VOID *pOutBuffer,
UINT32 outSize, UINT32 *pOutSize)
{
g_oalIoCtlUserAlarmSet = TRUE;
return(TRUE);
}

  • Define a macro for the new IOCTL.
#define FILE_DEVICE_CUST_OEM   32806

#define IOCTL_DDK_SET_ALARM_FLAG \
CTL_CODE(FILE_DEVICE_CUST_OEM, 0x0100, METHOD_BUFFERED, FILE_ANY_ACCESS)
  • Modify g_oalIoCtlTable variable in ioctl.c to add the new ioctl mapping:
const OAL_IOCTL_HANDLER g_oalIoCtlTable[] = {
.....
{
IOCTL_DDK_SET_ALARM_FLAG,
0,
OALIoCtlHalAlarmSet
},
#include
.....
}

Now we have a kernel ioctl, which can be invoked from any section coming under kernel address space. For making this IOCTL accessible from User space, we need to customise (clone) OALIOCTL, which will be described in another post in detail

Tuesday, November 4, 2008

Another nice article about booting

Here is another really informative article by the Windows CE Base team.:)

http://blogs.msdn.com/ce_base/archive/2007/11/26/How-does-Windows-Embedded-CE-6.0-start_3F00_.aspx

Monday, September 29, 2008

Interrupt ... whats the big deal??

In most of the discussion forums I have seen that developers are not clear about how interrupts are handled in windows ce. I am familiar with the Xscale and arm architectures. This post will not explain about how to handle or register interrupt in drivers, as it is covered in some of the previous posts. Instead how kernel manages an interrupt in windows ce 6.0. Lets start off with the concept of EXCEPTIONS in arm architectures.

"Exceptions are generated by internal and external sources to cause the processor to handle an event, such as an externally generated interrupt or an attempt to execute an Undefined instruction."
- I took it from the arm reference manual, couldn't put it in any better way myself:)

There are seven types of exceptions supported by ARM:
  1. Reset
  2. Undefined Instruction
  3. Software Interrupt
  4. Prefetch Abort
  5. Data Abort
  6. IRQ
  7. FIQ
When an exception occurs, the processor execution is halted and branches to a predefined address called exception vector. For each exception type, there is predefined exception vector, for example, exception vector for Data abort is 0x00000010 and that of reset is 0x00000000. There is also high vectors in which the exception vectors can be moved to an alternative address range(0xFFFF0000-0xFFFF001C), using bit[13] of the coprocessor 15 register 1 .

In the exception handler the banked version of register such as R14 and SPSR are used to save and restore the processor state.

Starting point for analyzing the exception handling in Windows ce for ARM architectures can be
WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\exvector.s



Defenition to each of this hanlders can be found in armtrap.s (WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM)
This vector table will be loaded into the higher part of physical page at 0xffff0000 (same as the High vector address), along with other kernel data in ARM_HIGH structure (WINCE600\PRIVATE\WINCEOS\COREOS\NK\INC\nkarm.h)


Here are some references that you can start off with
- ARM Architecture Reference Manual

Wednesday, September 17, 2008

Adding Low Power modes in PXA - P4

So far,we have discussed about how to put pxa into low power mode, how to wake it up, and briefly on how operating system restore things to the prior state after a transition to low power mode. Now lets put the bits and pieces together and see how windows ce does the low power mode transition in case of PXA.


As I have mentioned in the previous posts, we need to add the wakeup configuration first and then put the processor in to the low power mode.

For purpoes of explaining the concept, I will how to add a wakeup for GPIO 11 which is connected to the activity line of a communication module.

Adding the wakeup source
1) In OAL interrupt code(intr.c and bsp_cfg.h), add the code for creating a new interrupt corresponding to the wakeup source.

bsp_cfg.h - Add the new sysintr for the wakeup line

....
#define SYSINTR_COMMMOD_WAKEPUP (SYSINTR_FIRMWARE+22)
....


intr.c - map the sysintr to gpio 11 and add code for managing that
BOOL BSPIntrInit()
{
....
OALIntrStaticTranslate (SYSINTR_COMMMOD_WAKEPUP,IRQ_GPIOXX_2_GPIO11);
....
}


2) In OAL power code (power.c), add code for setting the pwer register. In mainstone bsp, the wakeups are register while OS starts (BSPPowerOffInit function)and the pwer value is written only while going into low power mode (BSPPowerOff).

BSPSetWakeSrc function - add a case for gpio 11 and set the gpio11 bit in the pPwer global variable. This variable will be written to the actual PWER register while going into suspend.

......
case IRQ_GPIOXX_2_GPIO11:
pPwer->gpio11 = 1;
OALMSG(1, ( L"BSPSetWakeSrc: IRQ Communication module source\r\n", irq));
break;
......


BSPGetWakeSrc function - add case for gpio 11 here also.This function to return the IRQ value if the PEDR (Power manager edge detect register) bit for gpio 11 is set.

....
else if (pPedr->gpio11)
{
*pSrcIrq = IRQ_GPIOXX_2_GPIO11;
}
....

BSPPowerOffInit function - use the OALIoCtlHalEnableWake function to set the global variable (g_oalWakeMask, an array) with the sysintr value corresponding to gpio11.
UINT32 commSysIntr = SYSINTR_COMMMOD_WAKEPUP;
...

OALIoCtlHalEnableWake(IOCTL_HAL_ENABLE_WAKE, &commSysIntr, sizeof(commSysIntr), NULL, 0, NULL);
...



While the BSPPowerOff function finds out which sysintr is mapped as a wakeup using OALPowerWakeSource and OALIntrTranslateSysIntr functions and sets the pwer bits with BSPSetWakeSrc function call.

When system resumes, BSPGetWakeSrc is used to get the wake cause and is stored in g_oalWakeSource variable which can be retrieved using kernel ioctl IOCTL_HAL_GET_WAKE_SOURCE



Wakeup Sources

When PXA is in low power modes such as Standby, Sleep or DeepSleep, the processor can be brought out using "Wakeups".

Wakeup is an "external or selected internal event". For example, assume that the power button is connected to GPIO0 of the processor, pressing of power button can be a wakeup source to the processor. Not all the GPIOs can act as wakeup for processor. For PXA the GPIO <116,> can act as wakeup sources. Also there are other wakeup sources such as USB host & client, RTC are wakeup sources.

Now we may not need to wakeup the processor for activity from any of these sources. Hence we can select the required wakeup source using the Power Manager Wake-up Enable (PWER) register. Also for GPIO wakeup sources, the edges needs to be configured using the Power Manager Rising Edge Detect Enable (PRER) and Falling Edge Detect Enable (PFER) register, so that wakeup will only happen for the selected edge of the transition on the GPIO.

NOTE: Take special care in configuring the direction of the GPIO which is chosen as a wakeup. If a wakeup source is configured for a GPIO which is configured as output, some undesirable results can happen.

For keypad and usim wakup there are seperate set of registers too for configuring specifics.

So in short, while configuring a gpio wake source in pxa, the following things should be taken into consideration:
  • PWER, selecting the wakeup source
  • PFER and PRER, fo which edge of GPIO transition , system needs to wakeup
  • GPDR, gpio should be configured as input

Tuesday, September 16, 2008

Adding Low Power modes in PXA - P2

Power Modes in PXA

PXA has the following power modes
  • Normal mode
  • Idle mode
  • Deep idle mode
  • Standby mode
  • Sleep mode
  • Deep Sleep mode
Each mode is characterized by the power domains that will be kept active and the clocks that will be running. For example in Sleep mode all the external low voltage power domains (i.e. domains controlled by PWR_EN pin of PXA) is disabled. While on the other hand, in Deep Sleep mode both the external low voltage and high voltage power domains are disabled as both PWR_EN and SYS_EN pins are de-asserted while entering the low power mode. The choice of which power mode to use for each depends solely on the power consumption requirements of the product.

In the beginning of the project, we mapped the Standby mode of PXA to POWER_STATE_SUSPEND state of Windows CE. But as we had a tight power consumption requirement for the Suspend mode, we had to re map the state to Sleep mode of PXA instead of standby.

Transition of Power Modes

For initiating a power mode transition in PXA, we need write in to the coprocessor 14 , register C7 (PWRMODE). Writing the bit pattern for each pattern corresponding to the power mode in to the PWRMODE[M] bits initiates the transition. For eg:

XllpPmEnterDeepSleep FUNCTION

ldr r3, =0x00000007
mcr p14, 0, r3, c7, c0, 0
nop
.......


A call to this assembly routine will initiate a transition to deep sleep mode.

Context Restoration


While going into low power modes such as Sleep or Deep Sleep, the processor contents can get corrupted.

Lets take the example of Sleep mode. In Sleep mode, the PC (Program Counter) value is corrupted along with some other set of registers. So in order to tackle this situation, operating systems are doing a context storage and restoration while going into low power mode. It stores the status of all the required registers such as GPIO configurations, level, stack address, core configuration registers in to a memory area. The address of this memory area is kept in a register which will be retained during the low power mode. In the case of PXA, it is the Power Manager Scratch Pad Register (PSPR). This register value will be maintained during a sleep reset, but will be cleared during GPIO, power on , hardware or watch dog resets.

So while going in to sleep mode, the required information is stored in a data area in RAM and the address to this area is stored in PSPR register. While resuming from sleep mode, the boot loader will check the PSPR register and will restore the configuration that is stored in the data area.

NOTE: bear in mind that the data area is in RAM, so the RAM needs to be properly initialized after a sleep reset, otherwise the boot loader can hand while trying to access the restoration area.

Monday, September 15, 2008

Adding Low Power modes in PXA - P1

For the windows ce project that we were working on had a lot of power states. As it was a PXA based board, with Mainstone III as the reference platform, we had to map these states to that of PXA.

The low power mode mappings were chosen as below:

  • POWER_STATE_SUSPEND - Sleep mode of PXA
  • POWER_STATE_OFF - Deep Sleep mode PXA
As you may have noticed in the Mainstone BSP's OAL code (the common soc code for pxa, i.e., WINCE600\PLATFORM\COMMON\SRC\SOC\PXA27X_MS_V1\OAL\POWER\off.c), the OemPowerOff Function uses the Deep Sleep mode of PXA. This function will be invoked from kernel when power manager issues a power off system.

Now with the new requirement for our software, we had to modify the existing OAL code and the power manager to add and map the new states to that of the PXA.

In this post I will walk you through on steps involved in adding a wakeup source in OAL.

We can splits the process in to two parts
  1. Mapping a SYSINTR value to the wakeup
  2. Adding the wakeup configuration specific to the processor
The detailed steps, I will explain in next post...