--- /opt/ecos/ecos2.0/packages/devs/watchdog/arm/at91/current/src/watchdog_at91.cxx 2002-08-06 17:33:29.000000000 +0200 +++ /opt/ecos/ecos2.1/packages/devs/watchdog/arm/at91/current/src/watchdog_at91.cxx 2004-07-27 23:27:23.000000000 +0200 @@ -9,6 +9,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Nick Garnett // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -41,8 +42,8 @@ //#####DESCRIPTIONBEGIN#### // // Author(s): tkoeller -// Contributors: tkoeller -// Date: 2002-05-05 +// Contributors: tkoeller, nickg, darnaud +// Date: 2004-07-23 // Purpose: Watchdog class implementation // Description: Contains an implementation of the Watchdog class for use // with the ATMEL AT91 watchdog timer. @@ -56,21 +57,29 @@ #include #include #include + #include #include #include #include -#include #include + #include + #if !defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) #include #include #endif -#define MCLK_FREQUENCY_KHZ 32768 +//========================================================================== + + +#if defined(CYGHWR_HAL_ARM_AT91_R40008) || \ + defined(CYGHWR_HAL_ARM_AT91_R40807) + +#define MCLK_FREQUENCY_KHZ (CYGNUM_HAL_ARM_AT91_CLOCK_SPEED/1000) #define MAX_TICKS 0x0000ffff -#define BASE_TICKS (MCLK_FREQUENCY_KHZ * CYGNUM_DEVS_WATCHDOG_ARM_AT91_DESIRED_TMEOUT_MS) +#define BASE_TICKS (MCLK_FREQUENCY_KHZ * CYGNUM_DEVS_WATCHDOG_ARM_AT91_DESIRED_TIMEOUT_MS) #if BASE_TICKS / 8 <= MAX_TICKS #define DIVIDER 0 @@ -91,104 +100,132 @@ #define TICKS ((BASE_TICKS / DIV_FACTOR) | 0xfff) #define RESOLUTION ((cyg_uint64) (TICKS * DIV_FACTOR ) * 1000000 / MCLK_FREQUENCY_KHZ) +#elif defined(CYGHWR_HAL_ARM_AT91_M42800A) +#define SCLK_FREQUENCY_HZ 32800 // Slow clock in hertz +#define MAX_TICKS 0x0000ffff +#define BASE_TICKS (SCLK_FREQUENCY_HZ * CYGNUM_DEVS_WATCHDOG_ARM_AT91_DESIRED_TIMEOUT_MS/1000) +#if BASE_TICKS/128 > MAX_TICKS +#error Desired resolution beyond hardware capabilities +#endif + +#define TICKS ((BASE_TICKS / 128) & 0xffff) +#define RESOLUTION ((cyg_uint64) (TICKS * 128) * 1000000000 / SCLK_FREQUENCY_HZ) +#endif + +//========================================================================== +// Reset on watchdog expiration #if defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) #define OMRVAL (AT91_WD_OMR_OKEY | AT91_WD_OMR_RSTEN | AT91_WD_OMR_WDEN) - -void -Cyg_Watchdog::init_hw(void) -{ - CYG_REPORT_FUNCTION(); - CYG_REPORT_FUNCARGVOID(); - resolution = RESOLUTION; - CYG_REPORT_RETURN(); -} +#define WDMRFLG (AT91_ST_WDMR_RSTEN | AT91_ST_WDMR_EXTEN) +#define IERFLG 0 #else /* defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) */ +//========================================================================== +// Action on watchdog expiration + #define OMRVAL (AT91_WD_OMR_OKEY | AT91_WD_OMR_IRQEN | AT91_WD_OMR_WDEN) +#define WDMRFLG 0 +#define IERFLG (AT91_ST_WDOVF) #define INT_PRIO 7 +//========================================================================== +// Private definitions -static void * -operator new(size_t size) -{ - static cyg_uint8 buf[sizeof (Cyg_Interrupt)]; - CYG_REPORT_FUNCTION(); - CYG_REPORT_FUNCARG1XV(size); - CYG_ASSERTC(size == sizeof buf); - CYG_REPORT_RETVAL(buf); - return buf; -} +static cyg_ISR watchdog_isr; +static Cyg_Watchdog *wd; -static cyg_uint32 -isr(cyg_vector vector, CYG_ADDRWORD data) -{ - Cyg_Watchdog &wd = *(Cyg_Watchdog *) data; +//========================================================================== + +static Cyg_Interrupt wdint +( + CYGNUM_HAL_INTERRUPT_WATCHDOG, + INT_PRIO, + 0, + watchdog_isr, + NULL + ); + +//========================================================================== + +cyg_uint32 watchdog_isr(cyg_vector vector, CYG_ADDRWORD data) +{ CYG_REPORT_FUNCTION(); CYG_REPORT_FUNCARG2XV(vector, data); - wd.trigger(); - Cyg_Interrupt::acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); + wd->trigger(); + wdint.acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); CYG_REPORT_RETVAL(Cyg_Interrupt::HANDLED); return Cyg_Interrupt::HANDLED; } -static Cyg_Interrupt * wdint; +#endif /* defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) */ +//========================================================================== +/* + * Init hardware watchdog timer. + */ void Cyg_Watchdog::init_hw(void) { CYG_REPORT_FUNCTION(); CYG_REPORT_FUNCARGVOID(); + wd = this; resolution = RESOLUTION; - wdint = new Cyg_Interrupt( - CYGNUM_HAL_INTERRUPT_WATCHDOG, - INT_PRIO, - (CYG_ADDRWORD) this, - isr, - NULL - ); - wdint->configure_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG, false, true); - wdint->attach(); - wdint->acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); - wdint->unmask_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); + CYG_REPORT_RETURN(); } - -#endif /* defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) */ - - - +//========================================================================== /* * Reset watchdog timer. This needs to be called regularly to prevent * the watchdog from firing. */ + void Cyg_Watchdog::reset(void) { CYG_REPORT_FUNCTION(); CYG_REPORT_FUNCARGVOID(); +#if defined(CYGHWR_HAL_ARM_AT91_M42800A) + /* Re-arm watchdog timer */ + HAL_WRITE_UINT32(AT91_ST + AT91_ST_CR, AT91_ST_CR_WDRST); +#else /* Write magic code to reset the watchdog. */ HAL_WRITE_UINT32(AT91_WD + AT91_WD_CR, AT91_WD_CR_RSTKEY); +#endif CYG_REPORT_RETURN(); } +//========================================================================== /* * Start watchdog to generate a hardware reset * or interrupt when expiring. */ + void Cyg_Watchdog::start(void) { CYG_REPORT_FUNCTION(); CYG_REPORT_FUNCARGVOID(); +#if !defined(CYGSEM_WATCHDOG_RESETS_ON_TIMEOUT) + wdint.configure_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG, false, true); + wdint.attach(); + wdint.acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); + wdint.unmask_interrupt(CYGNUM_HAL_INTERRUPT_WATCHDOG); +#endif + +#if defined(CYGHWR_HAL_ARM_AT91_M42800A) + HAL_WRITE_UINT32(AT91_ST + AT91_ST_WDMR, TICKS | WDMRFLG ); + HAL_WRITE_UINT32(AT91_ST + AT91_ST_IER, IERFLG ); + HAL_WRITE_UINT32(AT91_ST + AT91_ST_CR, AT91_ST_CR_WDRST ); +#else HAL_WRITE_UINT32(AT91_WD + AT91_WD_OMR, AT91_WD_OMR_OKEY); HAL_WRITE_UINT32( AT91_WD + AT91_WD_CMR, @@ -196,5 +233,9 @@ ); HAL_WRITE_UINT32(AT91_WD + AT91_WD_CR, AT91_WD_CR_RSTKEY); HAL_WRITE_UINT32(AT91_WD + AT91_WD_OMR, OMRVAL); +#endif CYG_REPORT_RETURN(); } + +//========================================================================== +// End of watchdog_at91.cxx