timer.c
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:17k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. /*++
  2. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. PARTICULAR PURPOSE.
  6. Copyright (c) 2001. Samsung Electronics, co. ltd  All rights reserved.
  7. Module Name:  
  8. Abstract:
  9.     Platform dependent PCMCIA initialization functions
  10. rev:
  11. 2002.4.11 : RTC function work (Hyojoon KIM, zzartto@samsung.com)
  12. 2002.4.3 : first S3C2410 version (SOC)
  13. 2002.2.5 : timer related bug fixups (kwangyoon LEE, kwangyoon@samsung.com)
  14.   prevent timer round-up
  15. - CPUSetSysTimerCount()
  16. - CPUClearSysTimerIRQ()
  17. - CPUGetSysTimerCountElapsed()
  18. 2002.1.29 : bug fixups (kwangyoon LEE, kwangyoon@samsung.com)
  19. - PerfCountFreq()
  20. - PerfCountSinceTick()
  21. - CPUSetSysTimerCount()
  22. - CPUClearSysTimerIRQ()
  23. - CPUGetSysTimerCountElapsed()
  24. - CPUGetSysTimerCountMax()
  25. 2002.1.28 : CE.NET initial port (kwangyoon LEE, kwangyoon@samsung.com)
  26. Notes: 
  27. --*/
  28. #include <windows.h>
  29. #include <nkintr.h>
  30. #include <S2440.h>
  31. extern DWORD CurMSec;
  32. extern DWORD DiffMSec;
  33. DWORD dwReschedIncrement;
  34. DWORD OEMCount1ms;
  35. static volatile DWORD dwCurReschedIncr;
  36. void EnterSlowMode();
  37. void ExitSlowMode();
  38. extern void MMU_WaitForInterrupt(void);
  39. unsigned __int64 RealTimeBias = 0;  // Number of 100-nanosecond intervals since
  40.                                     // January 1, 1601. 
  41. DWORD AlarmTime = 0;     // Alarm Off at startup
  42. volatile BOOL fInterruptFlag;
  43. volatile BOOL fSlowInterruptFlag;
  44. unsigned int saveREFRESH;
  45. //------------------------------------------------------------------------------
  46. //
  47. // When this is called we will set up GPIO<1> to be a falling edge interrupt  
  48. // InitClock sets up the OS timer to int via match reg 0 on the IRQ level
  49. // an int is requested in 1ms from now.
  50. //
  51. // Interrupts are disable when this is called. check with Thomas.
  52. //
  53. //------------------------------------------------------------------------------
  54. void 
  55. InitClock(void) 
  56. {
  57.     volatile PWMreg *s2440PWM =(PWMreg *)PWM_BASE;
  58.     volatile INTreg *s2440INT = (INTreg *)INT_BASE;  
  59.     DWORD ttmp;  
  60. // Timer4 as OS tick and disable it first.
  61.     s2440INT->rINTMSK |= BIT_TIMER4; // Mask timer4 interrupt.
  62.     s2440INT->rSRCPND = BIT_TIMER4; // Clear pending bit
  63.     s2440INT->rINTPND = BIT_TIMER4;
  64. // Operating clock : PCLK=101500000 (101.5 Mhz)    
  65. // IMPORTANT : MUST CHECK S2440.H DEFINITIONS !!!!
  66. s2440PWM->rTCFG1  = 0x8080; //;;; SHL
  67. s2440PWM->rTCFG0 &= ~(0xff << 8); /* Prescaler 1's Value */
  68. s2440PWM->rTCFG0 |= (PRESCALER << 8); // prescaler value=15
  69. /* Timer4 Divider field clear */
  70. s2440PWM->rTCFG1 = 0x11111; // ;;; SHL
  71. s2440PWM->rTCFG1 &= ~(0xf << 16);
  72. #if( SYS_TIMER_DIVIDER == D2 )
  73.    s2440PWM->rTCFG1  |=  (D1_2   << 16); /* 1/2 */
  74. #elif ( SYS_TIMER_DIVIDER == D4 )
  75. s2440PWM->rTCFG1  |=  (D1_4   << 16); /* 1/4 */
  76. #elif ( SYS_TIMER_DIVIDER == D8 )
  77.    s2440PWM->rTCFG1  |=  (D1_8   << 16); /* 1/8 */
  78. #elif ( SYS_TIMER_DIVIDER == D16 )
  79.    s2440PWM->rTCFG1  |=  (D1_16   << 16); /* 1/16 */
  80. #endif
  81. s2440PWM->rTCNTB4 = RESCHED_INCREMENT; //((RESCHED_PERIOD * OEM_CLOCK_FREQ) / 1000)  
  82. ttmp = s2440PWM->rTCON & (~(0xf << 20));
  83. s2440PWM->rTCON = ttmp | (2 << 20); /* update TCVNTB4, stop */
  84. s2440PWM->rTCON = ttmp | (1 << 20); /* one-shot mode,  start */
  85.     // Number of timer counts for reschedule interval
  86.     dwReschedIncrement = RESCHED_INCREMENT;
  87. // Set OEM timer count for 1 ms
  88.     OEMCount1ms = OEM_COUNT_1MS;
  89.     
  90.     // Set OEM clock frequency
  91.     OEMClockFreq = OEM_CLOCK_FREQ;
  92.     s2440INT->rINTMSK &= ~BIT_TIMER4;
  93.     return;
  94. }
  95. //------------------------------------------------------------------------------
  96. //------------------------------------------------------------------------------
  97. DWORD 
  98. GetTimerPeriod(void) 
  99. {
  100.     return RESCHED_PERIOD;
  101. }
  102. //------------------------------------------------------------------------------
  103. //------------------------------------------------------------------------------
  104. #define FROM_BCD(n) ((((n) >> 4) * 10) + ((n) & 0xf))
  105. // NOTE: The RTC on the SMDK2440 isn't battery-backed so RTC settings will be lost
  106. // when power is removed.
  107. //
  108. BOOL 
  109. OEMGetRealTime(LPSYSTEMTIME lpst) 
  110. {
  111. #if 0
  112. volatile RTCreg *s2440RTC = (RTCreg *)RTC_BASE;
  113. do
  114. {
  115. lpst->wYear = FROM_BCD(s2440RTC->rBCDYEAR) + 2000 ;
  116. lpst->wMonth = FROM_BCD(s2440RTC->rBCDMON   & 0x1f);
  117. lpst->wDay = FROM_BCD(s2440RTC->rBCDDAY   & 0x3f);
  118. lpst->wDayOfWeek = (s2440RTC->rBCDDATE - 1);
  119. lpst->wHour = FROM_BCD(s2440RTC->rBCDHOUR  & 0x3f);
  120. lpst->wMinute = FROM_BCD(s2440RTC->rBCDMIN   & 0x7f);
  121. lpst->wSecond = FROM_BCD(s2440RTC->rBCDSEC   & 0x7f);
  122. lpst->wMilliseconds = 0;
  123. }
  124. while(!(lpst->wSecond));
  125. return(TRUE);
  126. #else
  127. volatile RTCreg *s2440RTC; 
  128. s2440RTC = (RTCreg *)RTC_BASE;
  129.     
  130. //RETAILMSG(1, (_T("OEMGetRealTimern")));
  131.     
  132. // enable RTC control
  133. // s2440RTC->rRTCCON = 0x1;
  134. lpst->wMilliseconds = 0;
  135.     
  136. lpst->wSecond    = FROM_BCD(s2440RTC->rBCDSEC & 0x7f);
  137. lpst->wMinute  = FROM_BCD(s2440RTC->rBCDMIN & 0x7f);
  138. lpst->wHour  = FROM_BCD(s2440RTC->rBCDHOUR& 0x3f);
  139. lpst->wDayOfWeek = (s2440RTC->rBCDDATE - 1);
  140. lpst->wDay  = FROM_BCD(s2440RTC->rBCDDAY & 0x3f);
  141. lpst->wMonth  = FROM_BCD(s2440RTC->rBCDMON & 0x1f);
  142. // lpst->wYear  = (2000 + s2440RTC->rBCDYEAR) ; 
  143. lpst->wYear  = FROM_BCD(s2440RTC->rBCDYEAR) + 2000 ; 
  144. if ( lpst->wSecond == 0 )
  145. {
  146. lpst->wSecond    = FROM_BCD(s2440RTC->rBCDSEC & 0x7f);
  147. lpst->wMinute  = FROM_BCD(s2440RTC->rBCDMIN & 0x7f);
  148. lpst->wHour  = FROM_BCD(s2440RTC->rBCDHOUR& 0x3f);
  149. lpst->wDayOfWeek = (s2440RTC->rBCDDATE - 1);
  150. lpst->wDay  = FROM_BCD(s2440RTC->rBCDDAY & 0x3f);
  151. lpst->wMonth  = FROM_BCD(s2440RTC->rBCDMON & 0x1f);
  152. lpst->wYear = (2000 + s2440RTC->rBCDYEAR) ; 
  153. }
  154. // disable RTC control
  155. // s2440RTC->rRTCCON = 0;
  156. return TRUE;
  157. #endif
  158. }
  159. //------------------------------------------------------------------------------
  160. //------------------------------------------------------------------------------
  161. #define TO_BCD(n) ((((n) / 10) << 4) | ((n) % 10))
  162. // NOTE: The RTC on the SMDK2440 isn't battery-backed so RTC settings will be lost
  163. // when power is removed.
  164. //
  165. BOOL
  166. OEMSetRealTime(LPSYSTEMTIME lpst) 
  167. {
  168. #if 0
  169. volatile RTCreg *s2440RTC = (RTCreg *)RTC_BASE;
  170.  
  171. // Enable RTC control.
  172. //
  173. s2440RTC->rRTCCON |= 1;
  174. s2440RTC->rBCDSEC  = (unsigned char)TO_BCD(lpst->wSecond );
  175. s2440RTC->rBCDMIN  = (unsigned char)TO_BCD(lpst->wMinute );
  176. s2440RTC->rBCDHOUR = (unsigned char)TO_BCD(lpst->wHour   );
  177. s2440RTC->rBCDDATE = (unsigned char)(lpst->wDayOfWeek + 1);
  178. s2440RTC->rBCDDAY  = (unsigned char)TO_BCD(lpst->wDay    );
  179. s2440RTC->rBCDMON  = (unsigned char)TO_BCD(lpst->wMonth  );
  180. s2440RTC->rBCDYEAR = (unsigned char)TO_BCD((lpst->wYear % 100));
  181. RETAILMSG(1,(TEXT("OEMSetRealTime: Year: %x, Month: %x, Day: %x, Hour: %x, Minute: %x, second: %x rcnr=%Xhn"), 
  182.     s2440RTC->rBCDYEAR, s2440RTC->rBCDMON,s2440RTC->rBCDDAY, s2440RTC->rBCDHOUR, s2440RTC->rBCDMIN,s2440RTC->rBCDSEC,s2440RTC->rRTCCON));
  183. // Disable RTC control.
  184. //
  185. s2440RTC->rRTCCON &= ~1;
  186. return(TRUE);
  187. #else
  188. volatile RTCreg *s2440RTC = (RTCreg *)RTC_BASE;
  189.   static int firsttime = 0;
  190. // enable RTC control
  191. s2440RTC->rRTCCON =  0x1;
  192. s2440RTC->rBCDSEC  = (unsigned char)TO_BCD(lpst->wSecond );
  193. s2440RTC->rBCDMIN  = (unsigned char)TO_BCD(lpst->wMinute );
  194. s2440RTC->rBCDHOUR = (unsigned char)TO_BCD(lpst->wHour   );
  195. s2440RTC->rBCDDATE = (unsigned char)(lpst->wDayOfWeek + 1);
  196. if ( firsttime == 0 )
  197. {
  198. lpst->wYear = 2003; lpst->wMonth = 1; lpst->wDay = 1;
  199. firsttime = 1;
  200. }
  201. s2440RTC->rBCDDAY  = (unsigned char)TO_BCD(lpst->wDay    );
  202. s2440RTC->rBCDMON  = (unsigned char)TO_BCD(lpst->wMonth  );
  203. s2440RTC->rBCDYEAR = (unsigned char)TO_BCD((lpst->wYear % 100));
  204. RETAILMSG(1,(TEXT("OEMSetRealTime: Year: %u, Month: %u, Day: %u, Hour: %u, Minute: %u, second: %u rcnr=%Xhn"), lpst->wYear, lpst->wMonth,lpst->wDay, lpst->wHour, lpst->wMinute,lpst->wSecond,s2440RTC->rRTCCON));
  205. RETAILMSG(1,(TEXT("OEMSetRealTime(register): Year: %x, Month: %x, Day: %x, Hour: %x, Minute: %x, second: %x rcnr=%Xhn"), 
  206.     s2440RTC->rBCDYEAR, s2440RTC->rBCDMON,s2440RTC->rBCDDAY, s2440RTC->rBCDHOUR, s2440RTC->rBCDMIN,s2440RTC->rBCDSEC,s2440RTC->rRTCCON));
  207. // disable RTC control
  208. s2440RTC->rRTCCON = 0; //&= ~0x1;
  209. // Just certify heart bit
  210. // timer_cnt = 0;
  211. return TRUE;
  212. #endif
  213. }
  214. //------------------------------------------------------------------------------
  215. //------------------------------------------------------------------------------
  216. BOOL 
  217. OEMSetAlarmTime(LPSYSTEMTIME lpst) 
  218. {
  219. volatile INTreg *s2440INT = (INTreg *)INT_BASE; // for alarm 030818
  220. volatile RTCreg *s2440RTC = (RTCreg *)RTC_BASE;
  221. RETAILMSG(1,(TEXT("OEMSetAlarmTime: Year: %u, Month: %u, Day: %u, Hour: %u, Minute: %u, second: %u rcnr=%Xhn"), 
  222. lpst->wYear, lpst->wMonth,lpst->wDay, lpst->wHour, lpst->wMinute,lpst->wSecond,s2440RTC->rRTCCON));
  223. if ( !lpst || // for alarm 030818
  224. (lpst->wSecond > 59)   ||  // 0 - 59
  225. (lpst->wMinute > 59)   ||  // 0 - 59
  226. (lpst->wHour > 23)     ||  // 0 - 23
  227. (lpst->wDayOfWeek > 6) ||  // 0 - 6, Sun:0, Mon:1, ...
  228. (lpst->wDay > 31)      ||  // 0 - 31
  229. (lpst->wMonth > 12)    ||  // 1 - 12, Jan:1, Feb:2, ...
  230. (lpst->wMonth == 0)    ||
  231. (lpst->wYear < 2000)   ||  // We have a 100 year calander (2 BDC digits) with 
  232. (lpst->wYear > 2099)       // a leap year generator hard-wired to year 2000.
  233. )
  234. return FALSE;    
  235. s2440RTC->rRTCCON = (1 << 0); /* RTC Control Enable  */
  236.     
  237. s2440RTC->rALMSEC  = (unsigned char)TO_BCD(lpst->wSecond );
  238. s2440RTC->rALMMIN  = (unsigned char)TO_BCD(lpst->wMinute );
  239. s2440RTC->rALMHOUR = (unsigned char)TO_BCD(lpst->wHour   );
  240. s2440RTC->rALMDAY  = (unsigned char)TO_BCD(lpst->wDay    );
  241. s2440RTC->rALMMON  = (unsigned char)TO_BCD(lpst->wMonth  );
  242. s2440RTC->rALMYEAR = (unsigned char)TO_BCD((lpst->wYear % 100));
  243. s2440RTC->rRTCALM = 0x7f; // for alarm 030818
  244. s2440RTC->rRTCCON = (0 << 0); /* RTC Control Disable */
  245. // for alarm 030818
  246. s2440INT->rSRCPND  =  BIT_RTC;     /* RTC Alarm Interrupt Clear */
  247. s2440INT->rINTPND  =  BIT_RTC;
  248. s2440INT->rINTMSK &= ~BIT_RTC;     /* RTC Alarm Enable    */
  249.  
  250. return TRUE;
  251. }
  252. //------------------------------------------------------------------------------
  253. //------------------------------------------------------------------------------
  254. DWORD
  255. PerfCountFreq()
  256. {
  257.     return (OEMClockFreq);
  258. }
  259. //------------------------------------------------------------------------------
  260. //------------------------------------------------------------------------------
  261. DWORD
  262. PerfCountSinceTick()
  263. {
  264.     volatile PWMreg *s2440PWM;
  265.     DWORD dwCount;
  266.     s2440PWM = (PWMreg *)PWM_BASE;
  267.     dwCount= ((DWORD)s2440PWM->rTCNTO4);
  268.     
  269.     // Note: if dwCount is negative, the counter went past the match point.  The math
  270. // still works since it accounts for the dwReschedIncr time plus the time past
  271. // the match.
  272.     return dwCurReschedIncr - dwCount;
  273. }
  274. //------------------------------------------------------------------------------
  275. //------------------------------------------------------------------------------
  276. void
  277. CPUSetSysTimerCount(
  278.     DWORD dwCountdownMSec
  279.     )
  280. {
  281. DWORD dwMatch, ttmp;
  282. volatile PWMreg *s2440PWM;
  283.     s2440PWM = (PWMreg *)PWM_BASE;
  284.     dwCurReschedIncr = dwCountdownMSec * OEMCount1ms;
  285.     dwMatch = dwCurReschedIncr;
  286. s2440PWM->rTCNTB4 = dwMatch;
  287. ttmp = s2440PWM->rTCON & (~(0xf << 20));
  288. s2440PWM->rTCON = ttmp | (2 << 20); /* update TCVNTB4, stop */
  289. s2440PWM->rTCON = ttmp | (1 << 20); /* one-shot mode,  start */
  290. }
  291. //------------------------------------------------------------------------------
  292. //------------------------------------------------------------------------------
  293. BOOL
  294. CPUClearSysTimerIRQ(
  295.     void
  296.     )
  297. {
  298. volatile INTreg *s2440INT; 
  299. BOOL fPending;
  300. DWORD intstatus;
  301.     
  302. s2440INT = (INTreg *)INT_BASE;
  303. intstatus = s2440INT->rSRCPND;
  304. if ((intstatus & (BIT_TIMER4)) != 0) {
  305. s2440INT->rSRCPND = BIT_TIMER4;        
  306. s2440INT->rINTPND = BIT_TIMER4;
  307. fPending = TRUE;
  308. } else {
  309. fPending = FALSE;
  310. }
  311.     return fPending;
  312. }
  313. //------------------------------------------------------------------------------
  314. //------------------------------------------------------------------------------
  315. DWORD
  316. CPUGetSysTimerCountElapsed(
  317.     DWORD dwTimerCountdownMSec,
  318.     volatile DWORD *pCurMSec,
  319.     DWORD *pPartialCurMSec,
  320.     volatile ULARGE_INTEGER *pCurTicks
  321.     )
  322. {
  323.     volatile PWMreg *s2440PWM;
  324. DWORD dwTick, dwCount;
  325.     s2440PWM = (PWMreg *)PWM_BASE;
  326.     dwTick = dwTimerCountdownMSec * OEMCount1ms;
  327.     // If timer IRQ pending, a full resched period elapsed
  328.     if (CPUClearSysTimerIRQ( )) {
  329.         *pCurMSec += dwTimerCountdownMSec;
  330.         pCurTicks->QuadPart += dwTick;
  331.         return dwTimerCountdownMSec;
  332.     }
  333.     // No timer IRQ pending, calculate how much time has elapsed
  334. dwCount= ((DWORD)s2440PWM->rTCNTO4);
  335.     if (dwCount > dwTick) {
  336.         // This is an error case.  Recover gracefully.
  337.         dwCount = dwTick;
  338.     } else {
  339.         dwCount = dwTick - dwCount;
  340.     }
  341.     pCurTicks->QuadPart += dwCount;
  342.     dwCount += *pPartialCurMSec;
  343.     *pPartialCurMSec = dwCount % OEMCount1ms;
  344.     *pCurMSec += (dwCount /= OEMCount1ms);
  345.     return dwCount;
  346. }
  347. //------------------------------------------------------------------------------
  348. //------------------------------------------------------------------------------
  349. extern void CPUEnterIdleMode(void);
  350. extern void OEMWriteDebugLED(WORD wIndex, DWORD dwPattern);
  351. void
  352. CPUEnterIdle()
  353. {
  354. static volatile CLKPWRreg * s2440CLKPW = (CLKPWRreg *)CLKPWR_BASE;
  355. static volatile IOPreg    * s2440IOP   = (IOPreg    *)IOP_BASE;
  356. fInterruptFlag = FALSE;
  357. INTERRUPTS_ON();
  358. s2440IOP->rGPFDAT &= ~(1 << 5);
  359. s2440CLKPW->rCLKCON |=  (1 << 2); /* Enter IDLE Mode                              */
  360. while (!fInterruptFlag) {} /* Wait until S3C2440X enters IDLE mode         */
  361. s2440CLKPW->rCLKCON &= ~(1 << 2); /* turn-off IDLE bit.                           */
  362. /* Any interrupt will wake up from IDLE mode    */
  363. s2440IOP->rGPFDAT |= (1 << 5);
  364. }
  365. // Maximum idle is fixed a 1 ms because the PIT has to count down to 0 before reloading
  366. // the new countdown value.
  367. #define IDLE_MAX_MS  100
  368. //------------------------------------------------------------------------------
  369. //------------------------------------------------------------------------------
  370. DWORD
  371. CPUGetSysTimerCountMax(
  372.     DWORD dwIdleMSecRequested
  373.     )
  374. {
  375.     if (dwIdleMSecRequested > IDLE_MAX_MS) {
  376.         return IDLE_MAX_MS;
  377.     }
  378.     return dwIdleMSecRequested;
  379. }
  380. void EnterSlowMode()
  381. {
  382. static volatile CLKPWRreg * s2440CLKPW  = (CLKPWRreg *)CLKPWR_BASE;
  383. static volatile IOPreg    * s2440IOP    = (IOPreg    *)IOP_BASE;
  384. static volatile MEMreg   * s2440MemReg = (MEMreg      *)MEMCTRL_BASE;
  385. //RETAILMSG(1,(TEXT("EnterSlowMode rn")));
  386. fSlowInterruptFlag = TRUE;
  387. s2440IOP->rGPFDAT &= ~(1 << 7);
  388. //FCLK=FIN/1, SLOW mode, MPLL=off, UPLL=off
  389. s2440CLKPW->rCLKSLOW |= (1<<4)|(1<<5)|(1<<7);
  390. saveREFRESH = s2440MemReg->rREFRESH;
  391. s2440MemReg->rREFRESH=(1<<23)|(unsigned int)(2048+1-12*15.6);
  392. //Trp=2clk, Trc=4clk
  393. }
  394. void ExitSlowMode()
  395. {
  396. static volatile CLKPWRreg * s2440CLKPW  = (CLKPWRreg *)CLKPWR_BASE;
  397. static volatile IOPreg    * s2440IOP    = (IOPreg    *)IOP_BASE;
  398. static volatile MEMreg   * s2440MemReg = (MEMreg      *)MEMCTRL_BASE;
  399. // int i;
  400. //RETAILMSG(1,(TEXT("ExitSlowMode rn")));
  401. fSlowInterruptFlag = FALSE;
  402. s2440CLKPW->rCLKSLOW = 0|(1<<4)|(0<<5);// PLL on, MPLL=on
  403. //for ( i = 0; i < 2048; i++); //S/W MPLL lock-time
  404. s2440CLKPW->rCLKSLOW = 0|(0<<4)|(0<<5);// NORMAL mode, PLL=on, MPLL=on
  405. s2440MemReg->rREFRESH = saveREFRESH;
  406. s2440IOP->rGPFDAT |= (1 << 7);
  407. }
  408. void SetSysTimerInterval(DWORD dwTicks)
  409. {
  410.     volatile PWMreg *s2440PWM = (PWMreg *)PWM_BASE;
  411.     volatile INTreg *s2440INT = (INTreg *)INT_BASE;  
  412.     DWORD dwTimerTemp;  
  413. // Mask and clear timer interrupt.
  414. //
  415.     s2440INT->rINTMSK |= BIT_TIMER4;
  416.     s2440INT->rSRCPND  = BIT_TIMER4;
  417.     s2440INT->rINTPND  = BIT_TIMER4;
  418. // Change number of timer ticks in the period.
  419. //
  420. s2440PWM->rTCNTB4 = dwTicks;
  421. dwTimerTemp = s2440PWM->rTCON & (~(0xf << 20));
  422. s2440PWM->rTCON = dwTimerTemp | (2 << 20); // Update TCVNTB4 and stop.
  423. s2440PWM->rTCON = dwTimerTemp | (1 << 20); // One-shot mode and start.
  424. // Unmask the timer interrupt.
  425. //
  426.     s2440INT->rINTMSK &= ~BIT_TIMER4;
  427. }