1. 保证 在\oal\oallib 文件下 有 startup.s 如图
startup.s
2. 保证 在C:\WINCE600\PLATFORM\SMDK2440A\SRC\OAL\OALLIB 文件夹下 有 power.c
此文件中 主要实现 几个 休眠和 唤醒需要的几个函数3.1. 系统进入睡眠状态的过程
3.1.1 硬件相关电路
我们的产品使用GPF0/EINT0作为系统进入睡眠和从睡眠中唤醒的唤醒源,如下图所示:
EINT0作为唤醒源,而EINT0在S3C2443的datasheet中相关描述如下:
那么我们就需要知道触发这个中断(EINT0)的电平变化情况,是低电平触发?或是高电平触发?或是下降沿触发?或是上升沿触发?或是上升沿和下降沿触发?上面的设计是:在未按下按键(S5)时,EINT0是低电平,当按下按键时,EINT0是高电平,我们以松开按键时作为触发条件,也即下降沿时触发,初始化代码如下所示
3.1.2 系统进入睡眠的方式
WINCE6.0有三种方式让系统进入睡眠的状态,如下所示:
我们系统是采用第三种方式使系统进入睡眠状态的,
3.1.3 系统进入睡眠状态的调用流程
3.1.3.1 SetSystemPowerState()
在power按键驱动的IST中,当我们按下power键,在松开按键时,会调用SetSystemPowerState()函数,如下:
SetSystemPowerState( NULL, POWER_STATE_ON, POWER_FORCE );
下图是这个函数的定义
3.1.3.2 Power manager的相关调用
当OEM调用了SetSystemPowerState()函数,就转入power manager的工作流,执行下面的动作:
⑴ FileSystemPowerFunction():
⑵ PowerOffSystem()
⑶ Sleep()
3.1.3.3 内核的相关调用
Power manager的以上调用之后,接下来转入内核的调用流程,执行以下操作
其中power off GWES和文件系统进程是内核的工作,下面重点介绍OEMPowerOff()函数,这个函数在\Src\Common\Power\off.c下定义,这个函数体所实现的内容就对应到S3C2243 CPU的相关部分了,下图是系统进入睡眠状态之前的工作:
3.1.3.4 OEMPowerOff()函数
根据OEMPowerOff函数的流程图来说明这个函数体的功能。
下面分别介绍这个函数体主体部分:
⑴BSPPowerOff()函数
à pRTCPort->RTCCON=0x0;
这句主要目的就是在系统进入睡眠之前,禁止RTC控制使能,预防在系统进入睡眠状态后意外修改RTC寄存器的值,CPU的相关描述如下
à pADCPort->ADCCON|=(1<<2);
设置ADC的工作模式为standby mode,在睡眠状态下,触摸屏不需要工作,所以设置为standy mode,见下图:
à pIOPort->MISCCR|=(1<<12); //USB port = suspend
设置USB port为挂起模式,降低在睡眠时的功耗。
à pCLKPWR->USB_PHYPWR |= (0xf<<0);
见下图:
à pCLKPWR->PWRCFG &= ~(1<<4);
关闭对usb物理端口的供电。
à pCLKPWR->USB_CLKCON &= ~(1<<31);
见下图
à pCLKPWR->INFORM0 = 0x2BED;
这个寄存器可用于在进入睡眠前保留一些重要或者特别目的的数据,以便唤醒过程或唤醒后可以使用。
à 关闭背光灯和LCD
⑵ save system registers
…………………………………..
saveArea[5] = INPORT32(&pIOPort->GPCCON);
saveArea[6] = INPORT32(&pIOPort->GPCDAT);
saveArea[7] = INPORT32(&pIOPort->GPCUDP);
…………………………………
把GPIO寄存器的值保存在saveArea[]数组中,以便唤醒后恢复寄存器保存的数值。
⑶ ConfigStopGPIO函数
在这个函数可以设置好作为唤醒睡眠的GPIO口,比如GPF0/EINT0作为唤醒的GPIO口,就要在这里设置好,也可在OALCPUPowerOff函数中设置好,其他GPIO口一般设置为输入,已减少系统在睡眠时的功耗。
⑷ OALCPUPowerOff函数
这个函数在\Src\Oal\Oallib\startup.s中定义,如下所示
LEAF_ENTRY OALCPUPowerOff
; 1. Push SVC state onto our stack
stmdb sp!, {r4-r12}
stmdb sp!, {lr}
/***************************************************************/
我们知道R13常用作堆栈指针(sp),用于保存当前堆栈地址。SVC:表示处理器模式为管理模式。Stm指令是多寄存器存储指令,在此表示把r4到r12这9个寄存器中的值存储到基址寄存器(sp)所指示的一片连续存储器中,stm后面的db表示每次传送前地址值减;!表示数据加载与存储完毕之后,将最后的地址写入基址寄存器,如不使用!,则基址寄存器的内容不改变。假设sp=0x90020,stmdb sp!, {r4-r12}的操作如下:
第一步:在存储前,0x90050的值减4(对于ARM指令是4,对Thumb指令是2),也即为0x9004c。
第二步:把寄存器r12的值存储到0x9004c指向的存储区域。
第三步:0x9004c-4=0x90048。
第四步:把寄存器r11的值存储到0x90048指向的存储区域。
……………………………………
最后一步:就是sp=0x90030
lr:R14寄存器也称为子程序连接器(Subroutine Link Register)或连接寄存器LR。
/***************************************************************/
; 2. Save MMU & CPU Register to RAM
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage
ldr r2, =Awake_address ; store Virtual return address
str r2, [r3], #4
mrc p15, 0, r2, c1, c0, 0 ; load r2 with MMU Control
ldr r0, =MMU_CTL_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store MMU Control data
mrc p15, 0, r2, c2, c0, 0 ; load r2 with TTB address.
ldr r0, =MMU_TTB_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store TTB address
mrc p15, 0, r2, c3, c0, 0 ; load r2 with domain access control.
str r2, [r3], #4 ; store domain access control
str sp, [r3], #4 ; store SVC stack pointer
mrs r2, spsr
str r2, [r3], #4 ; store SVC status register
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts
msr cpsr, r1
mrs r2, spsr
stmia r3!, {r2, r8-r12, sp, lr} ; store the FIQ mode registers
mov r1, #Mode_ABT:OR:I_Bit:OR:F_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the ABT mode Registers
mov r1, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the IRQ Mode Registers
mov r1, #Mode_UND:OR:I_Bit:OR:F_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the UND mode Registers
mov r1, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
stmia r3!, {sp, lr} ; store the SYS mode Registers
mov r1, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Back to SVC mode, no interrupts
msr cpsr, r1
; 3. do Checksum on the Sleepdata
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; get pointer to SLEEPDATA
mov r2, #0
ldr r0, =SLEEPDATA_SIZE ; get size of data structure (in words)
30
ldr r1, [r3], #4
and r1, r1, #0x1
mov r1, r1, LSL #31
orr r1, r1, r1, LSR #1
add r2, r2, r1
subs r0, r0, #1
bne %b30
/****************************************************************/
计算睡眠数据的checksum,保存在r2寄存器中
/****************************************************************/
ldr r0, =vINFORM3
str r2, [r0] ; Store in Power Manager Scratch pad register
/****************************************************************/
把保存在r2寄存器中的睡眠数据的checksum保存到INFORM3寄存器中,以便唤醒过程计算checksum时比较。
/****************************************************************/
; 4. Interrupt Disable
ldr r0, =vINTBASE
mvn r2, #0
str r2, [r0, #oINTMSK]
str r2, [r0, #oSRCPND]
str r2, [r0, #oINTPND]
;; 5. Cache Flush
[ {TRUE}
bl OALClearUTLB
bl OALFlushICache
ldr r0, = (DCACHE_LINES_PER_SET - 1)
ldr r1, = (DCACHE_NUM_SETS - 1)
ldr r2, = DCACHE_SET_INDEX_BIT
ldr r3, = DCACHE_LINE_SIZE
bl OALFlushDCache
]
; 6. Setting Wakeup External Interrupt(EINT0) Mode
ldr r0, =vGPIOBASE
ldr r1, =0x5502
str r1, [r0, #oGPFCON]
/****************************************************************/
设置GPF0为EINT0,并且设置为下降沿触发,只要这里的设置准确才能正常从睡眠状态唤醒系统。
/****************************************************************/
ldr r4, =vRSTCON
ldr r5, =0x0ff80
str r5, [r4]
/****************************************************************/
/****************************************************************/
ldr r4, =vOSCSET
ldr r5, =0x8000
str r5, [r4]
/****************************************************************/
/****************************************************************/
ldr r4, =vPWRCFG
ldr r5, =0x8201
str r5, [r4]
/****************************************************************/
/****************************************************************/
ldr r4, =vPWRMODE
ldr r5, [r4]
bic r5, r5, #0xff00
bic r5, r5, #0x00ff
ldr r6, =0x2BED
orr r5, r5, r6 ; Power Off Mode
str r5, [r4] ; Power Off !!
b .
/****************************************************************/
/****************************************************************/
3.1.4 系统进入休眠前必须的动作
在系统进入休眠前,正确设置外部唤醒中断,才能够唤醒CPU.一般来说,正确设置唤醒中断源,有三个要点。
⑴ 把对应的GPIO设置为中断功能
⑵明确外部中断触发条件,比如我们把这个唤醒用的中断源所对应的IO接到一个按键上,希望通过按下按键来实现唤醒。那么就得明确,当按下这个按键时,IO口上的电平会发生什么样的变化。
⑶ 设置EXTINTn寄存器,按照按键按下时IO电平的变化条件来设置。比如当按下按键时,IO口上的电平会发生从高到低的变化,那么我们就设置对应的EXTINTn,使得中断触发条件为Falling edge trigeerde,即下降沿触发。
3.2. 系统从睡眠状态唤醒的过程
3.2.1 唤醒
当按下power键(GPF0/EINT0端口产生下降沿),程序就从nboot开始执行,也即从\Src\Bootloader\Stepldr\statup.s文件的入口ResetHandler开始
Stepldr的入口函数startup.s是由stepldr目录下的sources文件下“EXEENTRY=StartUp”来指定的,startup.s函数的主要功能如下所示:
1)startup.s函数的入口处
STARTUPTEXT
LEAF_ENTRY StartUp ;用于指定Startup.s函数的入口点
b ResetHandler ;无条件跳转到ResetHandler函数
b .
……………………….
b .
;-----------------------------------
; Steppingstone loader entry point.
;-----------------------------------
ResetHandler
ldr r0, =WTCON ; disable the watchdog timer.
mov r1,#0
str r1, [r0]
……………………
2) 禁止看门狗,屏蔽所有的中断及设置中断模式
ResetHandler
ldr r0, =WTCON ; disable the watchdog timer.
mov r1,#0
str r1, [r0]
ldr r0, = GPACDH
ldr r1, = 0x1AA8A
str r1, [r0]
/**********************************************************************/
GPACON和GPADAT在S3C2443中已不存在,被GPACDL和GPACDH代替,其作用如下:
GPACDL:Configuration and data register for port A low
GPACDH:Configuration and data register for port A high
配置为功能端,但不甚清楚如此配置的原因。
/**********************************************************************/
ldr r0, = GPFCON
ldr r1, = 0x5500
2
str r1, [r0]
ldr r0, =INTMSK ; mask all first-level interrupts.
ldr r1, =0xffffffff
str r1, [r0]
ldr r0, =INTSUBMSK ; mask all second-level interrupts.
ldr r1, =0x1fffffff
str r1, [r0]
/**********************************************************************/
屏蔽子中断和中断,从而在stepldr阶段不能使用中断服务功能。
/**********************************************************************/
ldr r0, = INTMOD
mov r1, #0x0 ; set all interrupt as IRQ
str r1, [r0]
/**********************************************************************/
设置所有的中断为IRQ中断。
/**********************************************************************/
3)设置时钟频率
ldr r0,=CLKDIV0 ; Set Clock Divider
ldr r1,[r0]
bic r1,r1,#0x37 ; clear HCLKDIV, PREDIV, PCLKDIV
bic r1,r1,#(0xf<<9) ; clear ARMCLKDIV
ldr r2,=((Startup_ARMCLKdiv<<9)+(Startup_PREdiv<<4)+(Startup_PCLKdiv<<2)+(Startup_HCLKdiv))
orr r1,r1,r2
str r1,[r0]
/**********************************************************************/
先清除PREDIV、PCLKDIV、HCLKDIV和ARMCLKDIV,在重新根据系统的需要来设置这几个参数,Startup_ARMCLKdiv等这几个参数在stepldr目录下的option.inc下定义。
ldr r0,=LOCKCON0 ; Set lock time of MPLL. added by junon
mov r1,#0xe10 ; Fin = 12MHz - 0x800, 16.9844MHz - 0xA00
str r1,[r0]
LOCKCON0是MPLL锁存时间的统计寄存器,启用PLL之后,由这个寄存器的值来决定为ARMCLK,HCLK和PCLK服务的MPLL锁存时间的计数值,典型情况下,这个值必须大于300us。
/**********************************************************************/
ldr r0,=LOCKCON1 ; Set lock time of EPLL. added by junon
mov r1,#0x800 ; Fin = 12MHz - 0x800, 16.9844MHz - 0xA00
str r1,[r0]
/**********************************************************************/
LOCKCON1是EPLL锁存时间的统计寄存器,启用PLL之后,由这个寄存器的值来决定为ARMCLK,HCLK和PCLK服务的MPLL锁存时间的计数值,典型情况下,这个值必须大于150。
/**********************************************************************/
ldr r0,=MPLLCON ; Set MPLL
ldr r1,=((0<<24)+(Startup_Mdiv<<16)+(Startup_Pdiv<<8)+(Startup_Sdiv))
str r1,[r0]
ldr r0,=EPLLCON ; Set EPLL
ldr r1,=((0<<24)+(Startup_EMdiv<<16)+(Startup_EPdiv<<8)+(Startup_ESdiv))
str r1,[r0]
PLL的输出频率由MPLLCON和EPLLCON寄存器的值来决定,其值尽量根据S3C2443用户手册中推荐使用的表来选择
MPLLCON相关参数的表:
EPLLCON相关参数的表:
ldr r0,=CLKSRC ; Select MPLL clock out for SYSCLK
ldr r1,[r0]
orr r1,r1,#0x50
str r1,[r0]
设置CLKSRC中的ESYSCLK选择方式为EPLL输出和MSYSCLK选择方式为MPLL输出,见下图:
4) 设置总线的同步方式
bl MMU_SetAsyncBusMode
这个函数的代码如下所示:
LEAF_ENTRY MMU_SetAsyncBusMode
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #R1_nF:OR:R1_iA
mcr p15, 0, r0, c1, c0, 0
mov pc, lr
5) 初始化内存控制器
bl InitMEM
这个函数体如下所示:
InitMEM
ldr r0,=GPKCON
ldr r1,=0xaaaaaaaa ; set Sdata[31:16]
str r1, [r0]
/**********************************************************************/
GPKCON就是SDATACFG寄存器,这是32位SDRAM的配置寄存器,为了控制32位的SDRAM,在内存初始化之前,SDATACFG应该设置为0xAAAAAAAA
/**********************************************************************/
add r0, pc, #MEMDATA - (. + 8)
ldr r1,=BANKCFG ;
add r2, r0, #16 ;End address of MEMDATA
110
/**********************************************************************/
先将存储器地址为r0的字数据读入到寄存器r3中,然后将新地址r0+4写入r0.
ldr r3, [r0], #4
将寄存器r3的值写入存储器地址为r0的寄存器,也即BANKCFG,也就是把MEMDATA标号处的第一个分配的单元数据给BANKCFG(0x48000000)赋值,然后将新地址r1+4写入r1,这时的r1指向BANKCON1(0x48000008)
str r3, [r1], #4
比较r2和r0的值,如果相等,表示对BANKCFG、BANKCON1、BANKCON2和BANKCON3这四个寄存器的初始化已经完成,如果没有,则跳到上面110处继续执行,直到对这四个寄存器始
化完成。
cmp r2, r0
bne %B110
先清除BANKCON1的最低两位,再赋值01给这两位,用于产生一个PALL命令
ldr r2,=BANKCON1
ldr r1,[r2]
bic r1,r1,#(0x3<<0)
orr r1,r1,#(0x1<<0) ; 4nd : Issue a PALL command
str r1,[r2]
对REFRESH的DRAM刷新周期赋值,这个值REFCYC=refresh period(这个和SDRAM的刷新周期有关,本系统使用K4S56163PF,其刷新周期为64ms,计算时是以s为单位的)*HCLK
ldr r4,=REFRESH ; 5fh : refresh cycle every 255-clock cycles
ldr r0,=0xff
str r0,[r4]
mov r0, #0x100 ; 6th : wait 2 auto - clk
120 subs r0, r0,#1;
bne %B120
bic r1,r1,#(0x3<<0) ; 7th : Issue a MRS command
orr r1,r1,#(0x2<<0)
str r1,[r2]
ldr r4,=REFRESH ; 8fh : refresh normal
ldr r0,=REFCYC
str r0,[r4]
orr r1,r1,#(0x3<<0) ; 9th : Issue a EMRS command
str r1,[r2]
bic r1,r1,#(0x3<<0) ; 10th : Issue a Normal mode
str r1,[r2]
// R14也称作子程序连接寄存器lr,当执行BL子程序调用指令时,lr得到R15(程序计数器PC)的备份,下面这行语句可以实现返回到跳转的地址处。
mov pc, lr
6)静态内存控制器(staic memory controller,SMC)的初始化,这个控制器在本开发板中用于控制nor flash,而mx300没有使用nor flash,所以应该不需要对SMC进行初始化.
bl InitSSMC
InitSSMC函数的定义如下:
InitSSMC
;Set SSMC Memory parameter control registers : AMD Flash
ldr r0,=SMBIDCYR0
ldr r1,=IDCY0
str r1,[r0]
ldr r0,=SMBWSTRDR0
ldr r1,=WSTRD0
str r1,[r0]
ldr r0,=SMBWSTWRR0
ldr r1,=WSTWR0
str r1,[r0]
ldr r0,=SMBWSTOENR0
ldr r1,=WSTOEN0
str r1,[r0]
ldr r0,=SMBWSTWENR0
ldr r1,=WSTWEN0
str r1,[r0]
ldr r0,=SMBCR0
ldr r1,=(SMBCR0_2+SMBCR0_1+SMBCR0_0)
str r1,[r0]
ldr r0,=SMBWSTBRDR0
ldr r1,=WSTBRD0
str r1,[r0]
ldr r0,=SMBWSTBRDR0
ldr r1,=WSTBRD0
str r1,[r0]
ldr r0,=SSMCCR
ldr r1,=((MemClkRatio<<1)+(SMClockEn<<0))
str r1,[r0]
;ldr r0,=SMBWSTRDR5
;ldr r1,=0xe
;str r1,[r0]
mov pc, lr
7) S3C2443X的系统控制器(system controller)有三大功能:复位管理,产生时钟和电源管理,下面先介绍复位管理。
当给S3C2443X的系统上电(power-on)时,外部设备必须插入复位来初始化S3C2443X的内部状态,S3C2443X有四种复位类型,在复位时,系统控制器的复位控制器能够使系统进入四种复位类型预先定义的状态中,这四种复位类型是:硬件复位,看门狗复位,软件复位和唤醒复位
I:硬件复位,当nRESET引脚插入低电平时产生硬件复位,这种类型的复位是一种uncompromised,unmaskable和complete reset,以硬件复位方式启动时,除了RTC以外的系统所有单元都被初始化为可知的状态(初始化状态)。
II:看门狗复位,看门狗计数器监测到设备异常的状态时就会产生看门狗复位。
III:软件复位(software reset),当对SWRST寄存器的每一位写1时,就产生软件复位。
IV:唤醒复位(wakeup reset),当系统从sleep mode中唤醒时,就产生唤醒复位。
通过reset状态寄存器来得到复位状态。
ldr r1, =RSTSTAT
ldr r0, [r1]
如果是从sleep中唤醒,则RSTSTAT[3]=1,否认RSTSTAT[3]=0。如果是从sleep中唤醒,则指令TST运算结果为非零,影响CPSR的Z标志位,这时Z=0;如果不是从sleep中唤醒,则指令TST运算结果为零,此时Z=1。
tst r0, #0x8
如果从sleep中唤醒,则接着执行下面的指令;如果不是(正常的启动),则跳到下面标号为2处接着执行。beq指令在Z标志位置位时(Z=1,表示上面的TST指令运算结果为0,从而知//道RSTSTAT[3]=0,而这表明系统不是从sleep中唤醒。)跳转。
beq %F2 ; if not wakeup from PowerOffmode Skip
如果是从sleep mode中唤醒,接下来深入及具体判断是通过RTC tick,或是RTC alarm,还是EINT终端模式来从sleep mode中唤醒。
ldr r1, =WKUPSTAT
ldr r0, [r1]
判断是否通过RTC alarm来从sleep mode中唤醒系统
tst r0, #(1<<1)
如果是通过RTC alarm来唤醒,则WKUPSTAT[1]=1,那么上面tst运算结果为非零,则CPSR的Z=0,那么就接着往下执行;如果不是通过alarm来唤醒,则WKUPSTAT[1]=0,那么上面tst运算结果为零,则CPSR的Z=1,那么跳转到下面标号6处执行
beq %f6 ; if not wakeup from PowerOffmode Skip
如果是通过RTC alarm来唤醒,则接着到此处执行,设置RTCCON[0]=1:启动RTC控制。
ldr r1,=RTCCON
ldr r3,[r1]
orr r3,r3,#0x1
str r3,[r1]
enable RTC alarm控制的相关功能项
ldr r1,=RTCALM
ldr r3,=0x7f
str r3,[r1]
设置RTC alarm秒,分,小时,日,月和年控制寄存器,以便下次唤醒所用。
ldr r1, =BCDSEC
ldr r2, =ALMSEC
ldr r3,[r1]
str r3,[r2]
ldr r1, =BCDMIN
ldr r2, =ALMMIN
ldr r3,[r1]
str r3,[r2]
ldr r1, =BCDHOUR
ldr r2, =ALMHOUR
ldr r3,[r1]
str r3,[r2]
ldr r1, =BCDDATE
ldr r2, =ALMDATE
ldr r3,[r1]
str r3,[r2]
ldr r1, =BCDMON
ldr r2, =ALMMON
ldr r3,[r1]
str r3,[r2]
ldr r1, =BCDYEAR
ldr r2, =ALMYEAR
ldr r3,[r1]
str r3,[r2]
ldr r1,=RTCCON
ldr r3,[r1]
bic r3,r3,#0x1
str r3,[r1]
唤醒的复位方式启动,但又不是通过RTC alarm唤醒,则直接跳到此处执行;如果是通过RTC alarm唤醒,则先重新启动RTC alarm控制及设置相应的控制寄存器再接着到标号6处执行。
6
ldr r2, =0x200000 ; offset into the RAM
add r2, r2, #0x30000000 ; add physical base
mov pc, r2 ; & jump to StartUp address
nop
nop
nop
b .
跳转到 RAM中的一个地址去执行,这个地址是0x32000000。那么熟悉2443 WINCE启动的朋友们应该明白了,这个地址就是Bootloader把NandFlash里的数据装载完毕后,跳转执行的地址。那么在这里,跳转到0x302000000这个地址后,WINCE系统就会被装载了,也就是说WINCE的操作系统被唤醒了。
2
如果不是从sleep中唤醒,而是其他的复位方式,将接着从这里执行。
ldr r1, =RSTSTAT
ldr r0, [r1]
tst指令用于判断当前的复位方式是否时软件复位:如果是软件复位,则RSTSTAT[5]=1,tst指令的运行结果为非零,则CPSR的Z=0;如果不是,则RSTSTAT[5]=0,tst指令的运算结果为零,则CPSR的Z=1
tst r0, #(1<<5)
如果是软件复位,根据上面tst指令的运算,知道CPSR的Z=0,则接着执行下面的语句;如果不是软件复位,则跳转到BringUpWinCE处接着执行
beq BringUpWinCE ; if not wakeup from PowerOffmode Skip
如果是软件复位,从此处接着执行
JumpToRAM
0x30200000(=0x30000000+0x200000)是NK.bin的image start地址
ldr r2, =0x200000 ; offset into the RAM
add r2, r2, #0x30000000 ; add physical base
直接跳转到SDRAM的0x30200000从WINCE操作系统内核映像的入口处执行,软件复位方式只用到了stepldr,然后就直接跳转到内核中执行了。
mov pc, r2 ; & jump to StartUp address
nop
nop
nop
b .//???????????????????????????????????????????????????????????????????????
如果不是软件复位,这时应该是硬件复位(或是看门狗复位,应该也是最常用的上电启动),紧接着此处执行
BringUpWinCE
[ {TRUE} ; DonGo
; Clear RAM.
;
mov r1,#0
mov r2,#0
mov r3,#0
mov r4,#0
mov r5,#0
mov r6,#0
mov r7,#0
mov r8,#0
ldr r0,=0x30000000 ; Start address (physical 0x3000.0000).
ldr r9,=0x04000000 ; 64MB of RAM.
20
stm指令用于将寄存器列表(在此r1到r8)所指示的多个寄存器中的值存入到由基址寄存器所指向的一片连续存储器中,条件码ia表示每次传送后地址值(基址寄存器的值,在此的初始值为0x30000000)加,下面stmia指令的实际意义:用r1的值(0)给0x30000000指向的存储器赋值,在此实际是对SDRAM清零,因为0x30000000到0x34000000这64MB的空间是用于SDRAM的,用r2的值给0x30000004指向的存储器赋值,如此类推,用r8的值给0x30000028指向的存储器赋值,这次传送完成后,使r0=0x30000032。
stmia r0!, {r1-r8}
上面stmia指令每进行一次数据传送,0x04000000相应减去32(4*8),用于判断对64MB的
SDRAM清零动作是否完成
subs r9, r9, #32
如果清零完成,则接着执行下面的语句;否则会跳到到上面标号为20处继续对SDRAM的清零。
bne %B20
]
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;
; Use of this source code is subject to the terms of the Microsoft end-user
; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
; If you did not accept the terms of the EULA, you are not authorized to use
; this source code. For a copy of the EULA, please see the LICENSE.RTF on your
; install media.
;
;------------------------------------------------------------------------------
;
; File: startup.s
;
; Kernel startup routine for Samsung SMDK2440A board. Hardware is
; initialized in boot loader - so there isn''t much code at all.
;
;------------------------------------------------------------------------------
INCLUDE kxarm.h
INCLUDE s3c2440a.inc
IMPORT OALClearUTLB
IMPORT OALFlushICache
IMPORT OALFlushDCache
vGPIOBASE EQU 0xb1600000 ;Port A control
oGPFCON EQU 0x50 ;Port F control
oGPFDAT EQU 0x54
oGPGCON EQU 0x60
oGPGDAT EQU 0x64
oGSTATUS3 EQU 0xb8 ;Saved data0(32-bit) before entering POWER_OFF mode
oGSTATUS4 EQU 0xbc ;Saved data0(32-bit) before entering POWER_OFF mode
vINTBASE EQU 0xb0a00000 ;Interrupt request status
oSRCPND EQU 0x00 ;Interrupt request status
oINTMSK EQU 0x08 ;Interrupt mask control
oINTPND EQU 0x10 ;Interrupt request status
vMISCCR EQU 0xb1600080 ;Miscellaneous control
vCLKCON EQU 0xb0c0000c ;Clock generator control
vCLKDIVN EQU 0xb0c00014 ;Clock divider control
vCAMDIVN EQU 0xb0c00018 ;Camera clock divider
vREFRESH EQU 0xb0800024 ;DRAM/SDRAM refresh
; Data Cache Characteristics.
;
DCACHE_LINES_PER_SET_BITS EQU 6
DCACHE_LINES_PER_SET EQU 64
DCACHE_NUM_SETS EQU 8
DCACHE_SET_INDEX_BIT EQU (32 - DCACHE_LINES_PER_SET_BITS)
DCACHE_LINE_SIZE EQU 32
SLEEPDATA_BASE_VIRTUAL EQU 0xA0028000 ; keep in sync w/ config.bib
SLEEPDATA_BASE_PHYSICAL EQU 0x30028000
SleepState_Data_Start EQU (0)
SleepState_WakeAddr EQU (SleepState_Data_Start )
SleepState_MMUCTL EQU (SleepState_WakeAddr + WORD_SIZE )
SleepState_MMUTTB EQU (SleepState_MMUCTL + WORD_SIZE )
SleepState_MMUDOMAIN EQU (SleepState_MMUTTB + WORD_SIZE )
SleepState_SVC_SP EQU (SleepState_MMUDOMAIN + WORD_SIZE )
SleepState_SVC_SPSR EQU (SleepState_SVC_SP + WORD_SIZE )
SleepState_FIQ_SPSR EQU (SleepState_SVC_SPSR + WORD_SIZE )
SleepState_FIQ_R8 EQU (SleepState_FIQ_SPSR + WORD_SIZE )
SleepState_FIQ_R9 EQU (SleepState_FIQ_R8 + WORD_SIZE )
SleepState_FIQ_R10 EQU (SleepState_FIQ_R9 + WORD_SIZE )
SleepState_FIQ_R11 EQU (SleepState_FIQ_R10 + WORD_SIZE )
SleepState_FIQ_R12 EQU (SleepState_FIQ_R11 + WORD_SIZE )
SleepState_FIQ_SP EQU (SleepState_FIQ_R12 + WORD_SIZE )
SleepState_FIQ_LR EQU (SleepState_FIQ_SP + WORD_SIZE )
SleepState_ABT_SPSR EQU (SleepState_FIQ_LR + WORD_SIZE )
SleepState_ABT_SP EQU (SleepState_ABT_SPSR + WORD_SIZE )
SleepState_ABT_LR EQU (SleepState_ABT_SP + WORD_SIZE )
SleepState_IRQ_SPSR EQU (SleepState_ABT_LR + WORD_SIZE )
SleepState_IRQ_SP EQU (SleepState_IRQ_SPSR + WORD_SIZE )
SleepState_IRQ_LR EQU (SleepState_IRQ_SP + WORD_SIZE )
SleepState_UND_SPSR EQU (SleepState_IRQ_LR + WORD_SIZE )
SleepState_UND_SP EQU (SleepState_UND_SPSR + WORD_SIZE )
SleepState_UND_LR EQU (SleepState_UND_SP + WORD_SIZE )
SleepState_SYS_SP EQU (SleepState_UND_LR + WORD_SIZE )
SleepState_SYS_LR EQU (SleepState_SYS_SP + WORD_SIZE )
SleepState_Data_End EQU (SleepState_SYS_LR + WORD_SIZE )
SLEEPDATA_SIZE EQU ((SleepState_Data_End - SleepState_Data_Start) / 4)
IMPORT KernelStart
;TEXTAREA
STARTUPTEXT
LEAF_ENTRY StartUp
; Compute the OEMAddressTable''s physical address and
; load it into r0. KernelStart expects r0 to contain
; the physical address of this table. The MMU isn''t
; turned on until well into KernelStart.
[ {TRUE}
ldr r0, =WTCON ; disable the watchdog timer.
ldr r1, =0x0
str r1, [r0]
ldr r0, =INTMSK ; mask all first-level interrupts.
ldr r1, =0xffffffff
str r1, [r0]
ldr r0, =INTSUBMSK ; mask all second-level interrupts.
ldr r1, =0x7fff
str r1, [r0]
; CLKDIVN
ldr r0,=CLKDIVN
ldr r1,=0x5 ; 0x0 = 1:1:1 , 0x1 = 1:1:2 , 0x2 = 1:2:2 , 0x3 = 1:2:4, 0x4 = 1:4:4, 0x5 = 1:4:8, 0x6 = 1:3:3, 0x7 = 1:3:6
str r1,[r0]
; MMU_SetAsyncBusMode FCLK:HCLK= 1:2
ands r1, r1, #0x0e
beq %F5
mrc p15,0,r0,c1,c0,0
orr r0,r0,#R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
5
; TODO: to reduce PLL lock time, adjust the LOCKTIME register.
ldr r0, =LOCKTIME
ldr r1, =0xffffff
str r1, [r0]
ldr r0, = UPLLCON
ldr r1, = ((56 << 12) + (2 << 4) + 2)
str r1, [r0]
nop
nop
nop
nop
nop
nop
nop
ldr r0, = MPLLCON
ldr r1, = ((92 << 12) + (1 << 4) + 1)
str r1, [r0]
mov r0, #0x2000
1
subs r0, r0, #1
bne %B1
]
mov r0, #0
mov r1, #0x32000000
mov r2, #0x20000
90
str r0, [r1]
add r1, r1, #4
subs r2, r2, #4
bne %B90
add r0, pc, #g_oalAddressTable - (. + 8)
bl KernelStart
INCLUDE oemaddrtab_cfg.inc
ENTRY_END
LTORG
LEAF_ENTRY OALCPUPowerOff1
; 1. Push SVC state onto our stack
stmdb sp!, {r4-r12}
stmdb sp!, {lr}
; 2. Save MMU & CPU Register to RAM
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage
ldr r2, =Awake_address ; store Virtual return address
str r2, [r3], #4
mrc p15, 0, r2, c1, c0, 0 ; load r2 with MMU Control
ldr r0, =MMU_CTL_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store MMU Control data
mrc p15, 0, r2, c2, c0, 0 ; load r2 with TTB address.
ldr r0, =MMU_TTB_MASK ; mask off the undefined bits
bic r2, r2, r0
str r2, [r3], #4 ; store TTB address
mrc p15, 0, r2, c3, c0, 0 ; load r2 with domain access control.
str r2, [r3], #4 ; store domain access control
str sp, [r3], #4 ; store SVC stack pointer
mrs r2, spsr
str r2, [r3], #4 ; store SVC status register
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts
msr cpsr, r1
mrs r2, spsr
stmia r3!, {r2, r8-r12, sp, lr} ; store the FIQ mode registers
mov r1, #Mode_ABT:OR:I_Bit:OR:F_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the ABT mode Registers
mov r1, #Mode_IRQ:OR:I_Bit:OR:F_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the IRQ Mode Registers
mov r1, #Mode_UND:OR:I_Bit:OR:F_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
mrs r0, spsr
stmia r3!, {r0, sp, lr} ; store the UND mode Registers
mov r1, #Mode_SYS:OR:I_Bit:OR:F_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
stmia r3!, {sp, lr} ; store the SYS mode Registers
mov r1, #Mode_SVC:OR:I_Bit:OR:F_Bit ; Back to SVC mode, no interrupts
msr cpsr, r1
; 3. do Checksum on the Sleepdata
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; get pointer to SLEEPDATA
ldr r2, =0x0
ldr r0, =(SLEEPDATA_SIZE-1) ; get size of data structure (in words)
30
ldr r1, [r3], #4
and r1, r1, #0x1
mov r1, r1, ROR #31
add r2, r2, r1
subs r0, r0, #1
bne %b30
ldr r0, =vGPIOBASE
;;;add r2, r2, #1 ; test checksum of the Sleep data error
str r2, [r0, #oGSTATUS3] ; Store in Power Manager Scratch pad register
ldr r0, =vGPIOBASE
; ldr r1, =0x550a
ldr r1, =0x0a
str r1, [r0, #oGPFCON]
; ldr r1, =0x30
; str r1, [r0, #oGPFDAT]
; 4. Interrupt Disable
ldr r0, =vINTBASE
mvn r2, #0
str r2, [r0, #oINTMSK]
str r2, [r0, #oSRCPND]
str r2, [r0, #oINTPND]
;; 5. Cache Flush
bl OALClearUTLB
bl OALFlushICache
ldr r0, = (DCACHE_LINES_PER_SET - 1)
ldr r1, = (DCACHE_NUM_SETS - 1)
ldr r2, = DCACHE_SET_INDEX_BIT
ldr r3, = DCACHE_LINE_SIZE
bl OALFlushDCache
; 6. Setting Wakeup External Interrupt(EINT0,1,2) Mode
ldr r0, =vGPIOBASE
; ldr r1, =0x550a
ldr r1, =0xaaaa
str r1, [r0, #oGPFCON]
; ldr r1, =0x55550100
ldr r1, =0x00000000
str r1, [r0, #oGPGCON]
; 7. Go to Power-Off Mode
ldr r0, =vMISCCR ; hit the TLB
ldr r0, [r0]
ldr r0, =vCLKCON
ldr r0, [r0]
ldr r0, =vREFRESH
ldr r1, [r0] ; r1=rREFRESH
orr r1, r1, #(1 << 22)
ldr r2, =vMISCCR
ldr r3, [r2]
orr r3, r3, #(3<<17) ; Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up
; orr r3, r3, #(7<<17) ; Make sure that SCLK0:SCLK->0, SCLK1:SCLK->0, SCKE=L during boot-up
bic r3, r3, #(7<<20)
orr r3, r3, #(6<<20)
ldr r4, =vCLKCON
ldr r5, =0x1ffff8 ; Power Off Mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sometimes it is not working in cache mode. So I modify to jump to ROM area.
;
;;; ldr r6, =0x92000000 ; make address to 0x9200 0020
;;; add r6, r6, #0x20 ;
;;; mov pc, r6 ; jump to Power off code in ROM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
b SelfRefreshAndPowerOff
ALIGN 32 ; for I-Cache Line(32Byte, 8 Word)
SelfRefreshAndPowerOff ; run with Instruction Cache''s code
str r1, [r0] ; Enable SDRAM self-refresh
str r3, [r2] ; MISCCR Setting
str r5, [r4] ; Power Off !!
b .
LTORG
; This point is called from EBOOT''s startup code(MMU is enabled)
; in this routine, left information(REGs, INTMSK, INTSUBMSK ...)
Awake_address
; 1. Recover CPU Registers
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; Sleep mode information data structure
add r2, r3, #SleepState_FIQ_SPSR
mov r1, #Mode_FIQ:OR:I_Bit:OR:F_Bit ; Enter FIQ mode, no interrupts - also FIQ
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr r8, [r2], #4
ldr r9, [r2], #4
ldr r10, [r2], #4
ldr r11, [r2], #4
ldr r12, [r2], #4
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_ABT:OR:I_Bit ; Enter ABT mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_IRQ:OR:I_Bit ; Enter IRQ mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_UND:OR:I_Bit ; Enter UND mode, no interrupts
msr cpsr, r1
ldr r0, [r2], #4
msr spsr, r0
ldr sp, [r2], #4
ldr lr, [r2], #4
mov r1, #Mode_SYS:OR:I_Bit ; Enter SYS mode, no interrupts
msr cpsr, r1
ldr sp, [r2], #4
ldr lr, [r2]
mov r1, #Mode_SVC:OR:I_Bit ; Enter SVC mode, no interrupts - FIQ is available
msr cpsr, r1
ldr r0, [r3, #SleepState_SVC_SPSR]
msr spsr, r0
; 2. Recover Last mode's REG's, & go back to caller of OALCPUPowerOff()
ldr sp, [r3, #SleepState_SVC_SP]
ldr lr, [sp], #4
ldmia sp!, {r4-r12}
mov pc, lr ; and now back to our sponsors
ENTRY_END
;------------------------------------------------------------------------------
; Clock Division Change funtion for DVS on S3C2440A.
;------------------------------------------------------------------------------
LEAF_ENTRY CLKDIV124
ldr r0, = vCLKDIVN
ldr r1, = 0x3 ; 0x3 = 1:2:4
str r1, [r0]
mov pc, lr
LEAF_ENTRY CLKDIV144
ldr r0, = vCLKDIVN
ldr r1, = 0x4 ; 0x4 = 1:4:4
str r1, [r0]
mov pc, lr
LEAF_ENTRY CLKDIV136
ldr r0, = vCLKDIVN
ldr r1, = 0x7 ; 1:6:12
str r1, [r0]
ldr r0, = vCAMDIVN
ldr r1, [r0]
bic r1, r1, #(0x3<<8)
orr r1, r1, #(0x0<<8) ; 1:3:6
str r1, [r0]
mov pc, lr
LEAF_ENTRY CLKDIV166
ldr r0, = vCAMDIVN
ldr r1, [r0]
bic r1, r1, #(0x3<<8)
orr r1, r1, #(0x1<<8) ; 1:6:12
str r1, [r0]
ldr r0, = vCLKDIVN
ldr r1, = 0x6 ; 1:6:6
str r1, [r0]
mov pc, lr
LEAF_ENTRY CLKDIV148
ldr r0, = vCLKDIVN
ldr r1, = 0x5 ; 1:8:16
ldr r2, = vCAMDIVN
ldr r3, [r2]
bic r3, r3, #(0x3<<8)
orr r3, r3, #(0x0<<8) ; 1:4:8
str r1, [r0]
str r3, [r2]
mov pc, lr
LEAF_ENTRY CLKDIV188
ldr r0, = vCAMDIVN
ldr r1, [r0]
bic r1, r1, #(0x3<<8)
orr r1, r1, #(0x2<<8) ; 1:8:16
ldr r2, = vCLKDIVN
ldr r3, = 0x4 ; 1:8:8
str r1, [r0]
str r3, [r2]
mov pc, lr
LEAF_ENTRY DVS_ON
ldr r0, = vCAMDIVN
ldr r1, [r0]
orr r1, r1, #(0x1<<12) ; DVS_EN bit = 1(FCLK = HCLK)
str r1, [r0]
mov pc, lr
LEAF_ENTRY DVS_OFF
ldr r0, = vCAMDIVN
ldr r1, [r0]
bic r1, r1, #(0x1<<12) ; DVS_EN bit = 0(FCLK = MPLL clock)
str r1, [r0]
mov pc, lr
END
;------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// -----------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// -----------------------------------------------------------------------------
#include <windows.h>
#include <bsp.h>
#define Clear_FrameBuffer 0xA0100000
void InitTimer(void);
void ConfigStopGPIO(void);
void TurnOffBackLight(void);
VOID BSPPowerOff()
{
volatile S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
volatile S3C2440A_ADC_REG *pADCPort = (S3C2440A_ADC_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_ADC, FALSE);
volatile S3C2440A_RTC_REG *pRTCPort = (S3C2440A_RTC_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_RTC, FALSE);
volatile S3C2440A_LCD_REG *pLCDPort = (S3C2440A_LCD_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_LCD, FALSE);
ULONG *FrameBufferPtr = (ULONG *)Clear_FrameBuffer;
ULONG FrameBufferCount;
//RETAILMSG(1,(TEXT("BSPPowerOff\r\n")));
pRTCPort->RTCCON=0x0; // R/W disable, 1/32768, Normal(merge), No reset
pADCPort->ADCCON|=(1<<2); // ADC StanbyMode
pIOPort->MISCCR|=(1<<12); //USB port0 = suspend
pIOPort->MISCCR|=(1<<13); //USB port1 = suspend
pIOPort->MISCCR|=(1<<2); //Previous state at STOP(?) mode (???)
//D[31:0] pull-up off. The data bus will not be float by the external bus holder.
//If the pull-up resitsers are turned on,
//there will be the leakage current through the pull-up resister
pIOPort->MISCCR=pIOPort->MISCCR|(3<<0);
// In the evaluation board, Even though in sleep mode, the devices are all supplied the power.
pIOPort->MSLCON = (0<<11)|(0<<10)|(0<<9)|(0<<8)|(0<<7)|(0<<6)|(0<<5)|(0<<4)|(0<<3)|(0<<2)|(0<<1)|(0<<0);
pIOPort->DSC0 = (1<<31)|(3<<8)|(3<<0);
pIOPort->DSC1 = (3<<28)|(3<<26)|(3<24)|(3<<22)|(3<<20)|(3<<18);
// Clear frame buffer & wait until framebuffer refresh
for (FrameBufferCount = 0 ; FrameBufferCount < 480*800/2 ; FrameBufferCount++)
*FrameBufferPtr++ = 0;//0xffffffff;
pLCDPort->LCDSRCPND = 0x2;
while((pLCDPort->LCDSRCPND & 0x2) == 0);
pLCDPort->LCDSRCPND = 0x2;
while((pLCDPort->LCDSRCPND & 0x2) == 0);
pLCDPort->LCDSRCPND = 0x2;
while((pLCDPort->LCDSRCPND & 0x2) == 0);
pLCDPort->LCDSRCPND = 0x2;
//TurnOffBackLight();
/* LCD Controller Disable */
// CLRPORT32(&pIOPort->GPGDAT, 1 << 4);
}
void ConfigStopGPIO(void)
{
volatile S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
// Check point
// 1) NC pin: input pull-up on
// 2) If input is driver externally: input pull-up off
// 3) If a connected component draws some current: output low.
// 4) If a connected component draws no current: output high.
//chip # = 5
//CAUTION:Follow the configuration order for setting the ports.
// 1) setting value(GPnDAT)
// 2) setting control register (GPnCON)
// 3) configure pull-up resistor(GPnUP)
//32bit data bus configuration
//*** PORT A GROUP
//Ports : GPA22 GPA21 GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12
//Signal : nFCE nRSTOUT nFRE nFWE ALE CLE nGCS5 nGCS4 nGCS3 nGCS2 nGCS1
//Binary : 1 1 1, 1 1 1 1, 1 1 1 1,
//POFF : 1 0 1, 1 0 0 1, 1 1 1 1,
//-------------------------------------------------------------------------------------------
//Ports : GPA11 GPA10 GPA9 GPA8 GPA7 GPA6 GPA5 GPA4 GPA3 GPA2 GPA1 GPA0
//Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0
//Binary : 1 1 1 1, 1 1 1 1, 1 1 1 1
//POFF : 0 0 0 0, 0 0 0 0, 0 0 0 0
pIOPort->GPACON = 0x7fffff;
//**** PORT B GROUP
//Ports : GPB10 GPB9 GPB8 GPB7 GPB6 GPB5 GPB4 GPB3 GPB2 GPB1 GPB0
//Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard
//Setting: INPUT OUTPUT INPUT OUTPUT INPUT OUT OUT OUT OUT INPUT INPUT
//Binary : 00, 01 00, 01 00, 01 01, 01 01, 00 00
//PU_OFF : 0 1 0, 1 1(ext) 1(*) 1, 1 1 1(ext) 1(ext)
//*:nDIS_OFF:4.7K external pull-down resistor
// pIOPort->GPBDAT= 0x0|(0<<9)|(1<<7)|(0<<5)|(1<<4)|(1<<3)|(1<<2); // SHLIM 040116
pIOPort->GPBDAT= 0x0|(1<<9)|(1<<7)|(0<<5)|(1<<4)|(1<<3)|(1<<2); // SHLIM 040116
pIOPort->GPBCON = 0x044550;
pIOPort->GPBUP = (0x2ff)&(~(0x1<<1)); //0x2fd->2ff, 3uA is reduced. Why?
pIOPort->GPBCON &=~(0x3<<18);
pIOPort->GPBCON |= (0x1<<18);
pIOPort->GPBUP &= ~(0x1<<9); //控制电源
pIOPort->GPBDAT |= (0x1<<9);
pIOPort->GPBUP &= ~(0x1<<1); //控制电源
pIOPort->GPBCON &= ~(0x3<<2);
pIOPort->GPBCON |= (0x1<<2);
pIOPort->GPBDAT &= ~(0x1<<1);
//*** PORT C GROUP
//Ports : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0
//Signal : VD7 VD6 VD5 VD4 VD3 VD2 VD1 VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND
//Setting: IN IN IN IN IN IN IN IN OUT OUT OUT IN IN IN IN IN
//Binary : 00 00, 00 00, 00 00, 00 00, 01 01, 01 00, 00 00, 00 00
//PU_OFF : 0 0 0 0, 0 0 0 0, 1 1 1 0, 0 0 0 0
pIOPort->GPCDAT = 0x0;
pIOPort->GPCCON = 0x00005400; //0x00000000;
pIOPort->GPCUP = 0x00e0; //0x0000;
pIOPort->GPCUP &= ~(0x1<<6); //关灯 方便调试的 以后需要删除 long
pIOPort->GPCCON &= ~(0x3<<12);
pIOPort->GPCCON |= (0x1<<12);
pIOPort->GPCDAT |= (0x1<<6);
//LCDVFn is connected the analog circuit in LCD. So, this signal should be output L.
//*** PORT D GROUP
//Ports : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
//Signal : VD23 VD22 VD21 VD20 VD19 VD18 VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9 VD8
//Setting: IN IN IN IN IN IN IN IN IN IN IN IN IN IN IN IN
//Binary : 00 00, 00 00, 00 00, 00 00, 00 00, 00 00, 00 00, 00 00
//PU_OFF : 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0
pIOPort->GPDDAT= 0x0;
pIOPort->GPDCON = 0x0;
pIOPort->GPDUP = 0x0;
//*** PORT E GROUP
//Ports : GPE15 GPE14 GPE13 GPE12 GPE11 GPE10 GPE9 GPE8 GPE7 GPE6 GPE5 GPE4
//Signal : IICSDA IICSCL SPICLK0 SPIMOSI0 SPIMISO0 SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK I2SSDO
//Setting: IN IN IN IN IN IN IN IN IN IN IN OUT
//Binary : 00 00, 00 00, 00 00, 00 00, 00 00, 00 01,
//PU_OFF : 1-ext 1-ext 0 0, 0 0 0 0, 0 0 0 1,
//------------------------------------------------------------------------------------------------
//Ports : GPE3 GPE2 GPE1 GPE0
//Signal : I2SSDI CDCLK I2SSCLK I2SLRCK
//Setting: IN OUT OUT OUT
//Binary : 00 01, 01 01
//PU_OFF : 1-ext 1 1 1
pIOPort->GPEDAT = 0x0|(1<<4)|(1<<2)|(1<<1)|(1<<0);
pIOPort->GPECON = 0x00000115;
pIOPort->GPEUP = 0xc01f;
//*** PORT F GROUP
//Ports : GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0
//Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0
//Setting: Output Output Output Output IN IN IN EINT0
//Binary : 01 01, 01 01, 00 00, 00 10
//PU_OFF : 1 1 1 1, 0-ext 1-ext 1-ext 1-ext
pIOPort->GPFDAT = 0x0 |(0xf<<4);
pIOPort->GPFCON = 0x5502;
pIOPort->GPFUP = 0xf7;
pIOPort->GPFCON &= ~(0x3<<8) ; //设置GPF4 为 EINT4
pIOPort->GPFCON |= (0x2<<8) ; //设置GPF4 为 EINT4
//*** PORT G GROUP
//Ports : GPG15 GPG14 GPG13 GPG12 GPG11 GPG10 GPG9 GPG8 GPG7 GPG6
//Signal : nYPON YMON nXPON XMON EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI
//Setting: OUT OUT OUT OUT OUT OUT OUT OUT OUT OUT
//Binary : 01 01, 01 01, 01-dbg 01, 01 01, 01 01
//PU_OFF : 1 1 1 1, 1-ext 1 1 1, 1 1
//---------------------------------------------------------------------------------------
//Ports : GPG5 GPG4 GPG3 GPG2 GPG1 GPG0
//Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA
//Setting: IN IN EINT11 IN IN IN
//Binary : 00 00, 10 00, 00 00
//PU_OFF : 0-ext 0, 1-ext 0 0 0
#if 0
pIOPort->GPGDAT = 0x0 |(1<<11)|(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<9)|(1<<8)|(1<<7)|(1<<6) ;
pIOPort->GPGCON = 0x55455080; //GPG11=OUT //for debug
pIOPort->GPGUP = 0xfbc8;
#else // Modified for 2440
pIOPort->GPGDAT = 0;
pIOPort->GPGCON = 0x00000000;
pIOPort->GPGUP = 0x0;
#endif
//*** PORT H GROUP
//Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0
//Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
//Setting: IN IN IN IN IN IN OUT RXD0 TXD0 OUT IN
//Binary : 00, 00 00, 00 00, 00 01, 10 10, 01 00
//PU_OFF : 0 0 0, 1-ext 1-ext 1-ext 1, 1-ext 1 1 1-ext
pIOPort->GPHDAT = 0x0|(1<<6)|(1<<1)|(1<<4);
pIOPort->GPHCON = 0x0001a4; //0x0011a4->0x0001a4 reduces 12uA why -> MAX3232C may sink 12uA.
pIOPort->GPHUP = 0x0ff; // The pull up function is disabled GPH[10:0]
pIOPort->GPBUP &= ~(0x1<<10); //控制电源
pIOPort->GPHCON &= ~(0x3<<20);
pIOPort->GPHCON |= (0x1<<20);
pIOPort->GPHDAT &= ~(0x1<<10); //为0 wifi sleep
//PORT J GROUP
//Ports : GPJ12 GPJ11 GPJ10 GPJ9 GPJ8 GPJ7 GPJ6 GPJ5 GPJ4 GPJ3 GPJ2 GPJ1 GPJ0
//Signal : CAMRESET CAMCLKOUT CAMHREF CAMVS CAMPCLKIN CAMD7 CAMD6 CAMD5 CAMD4 CAMD3 CAMD2 CAMD1 CAMD0
//Setting: Out Out Out Out Out Out Out Out Out Out Out Out Out
//Binary : 01 01 01 01 01 01 01 01 01 01 01 01 01
//PU_OFF : 0 0 1 1 1 1 1 1 1 1 1 1 1
//---------------------------------------------------------------------------------------
pIOPort->GPJCON = 0x02aaaaaa;
pIOPort->GPJUP = 0x1fff; // The pull up function is disabled GPH[10:0]
//External interrupt will be falling edge triggered.
// pIOPort->rEXTINT0 = 0x22222222; // EINT[7:0]
pIOPort->EXTINT0 = 0x22222224; // EINT[7:0] // charlie. button glich
pIOPort->EXTINT1 = 0x22222222; // EINT[15:8]
pIOPort->EXTINT2 = 0x22222022; // EINT[23:16]
}
VOID BSPPowerOn()
{
volatile S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
volatile S3C2440A_LCD_REG *pLCD = (S3C2440A_LCD_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_LCD, FALSE);
OEMInitDebugSerial();
InitTimer();
pIOPort->EXTINT0 = 0x22222222; // EINT[7:0]
pIOPort->EXTINT1 = 0x22222222; // EINT[15:8]
pIOPort->EXTINT2 = 0x22222222; // EINT[23:16]
pIOPort->GSTATUS2 = pIOPort->GSTATUS2;
pIOPort->MISCCR &= ~(1<<12); //USB port0 = normal mode
pIOPort->MISCCR &= ~(1<<13); //USB port1 = normal mode
pLCD->LCDCON1 &= ~(0x1);
lcd_spi_init();
pLCD->LCDCON1 |= (0x1);
// LCD Controller Enable
//SETPORT32(&pIOPort->GPGDAT, 1 << 4);
}
//------------------------------------------------------------------------------
//
// Function: InitClock
//
// This function is now considered obsolete. It is called by kernel after OAL
// returns from OEMPowerOff. All its function should be moved to OEMPowerOff.
//
// This function is defined on \common\src\common\other\clock.c
//
VOID InitTimer()
{
volatile S3C2440A_PWM_REG *g_pPWMRegs = (S3C2440A_PWM_REG*)OALPAtoUA(S3C2440A_BASE_REG_PA_PWM);
UINT32 tcon;
RETAILMSG(1,(TEXT("InitClock\r\n")));
// Hardware Setup
g_pPWMRegs = (S3C2440A_PWM_REG*)OALPAtoUA(S3C2440A_BASE_REG_PA_PWM);
OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) & ~0x0000FF00);
OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) | (25-1) <<8); // charlie, Timer4 scale value
OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) & ~(0xF << 16));
OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (0 << 16)); // charlie, Timer4 Division
OUTREG32(&g_pPWMRegs->TCNTB4, g_oalTimer.countsPerSysTick);
// Start timer in auto reload mode
tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20);
OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) );
OUTREG32(&g_pPWMRegs->TCON, tcon | (0x5 << 20) );
}
//------------------------------------------------------------------------------
//==========================================
// add by long
//==========================================
void TurnOffBackLight(void)
{
volatile S3C2440A_IOPORT_REG *pIOPort = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
pIOPort->GPBCON &= (~0x3);
pIOPort->GPBCON |= 0x01;
pIOPort->GPBUP |= 0x01;
pIOPort->GPCDAT &= ~0x1;
}