mirror of
https://github.com/Stichting-MINIX-Research-Foundation/netbsd.git
synced 2025-08-07 21:19:47 -04:00
553 lines
14 KiB
C
553 lines
14 KiB
C
|
|
/*
|
|
* Copyright (c) 2013 Sughosh Ganu
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain this list of conditions
|
|
* and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce this list of conditions
|
|
* and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__KERNEL_RCSID(0, "$NetBSD: omapl1x_timer.c,v 1.1 2013/10/02 16:48:26 matt Exp $");
|
|
|
|
#include "opt_timer.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/time.h>
|
|
#include <sys/timetc.h>
|
|
#include <sys/device.h>
|
|
#include <sys/bus.h>
|
|
|
|
#include <dev/clock_subr.h>
|
|
|
|
#include <machine/intr.h>
|
|
|
|
#include <arm/cpufunc.h>
|
|
#include <arm/pic/picvar.h>
|
|
|
|
#include <arm/omap/omap_tipb.h>
|
|
#include <arm/omap/omapl1x_reg.h>
|
|
#include <arm/omap/omapl1x_misc.h>
|
|
|
|
typedef struct timer_factors {
|
|
uint32_t tf_counts_per_usec;
|
|
uint32_t tf_period;
|
|
uint32_t tf_enamode;
|
|
uint32_t tf_ctr_reg;
|
|
uint32_t tf_prd_reg;
|
|
uint32_t tf_enamode_shift;
|
|
uint32_t tf_intr_prd_en_shift;
|
|
uint32_t tf_intr_prd_stat_shift;
|
|
} timer_factors_t;
|
|
|
|
typedef struct omapl1xtmr_softc {
|
|
struct device sc_dev;
|
|
uint sc_timerno;
|
|
uint sc_timer_freq;
|
|
bus_space_tag_t sc_iot;
|
|
bus_space_handle_t sc_ioh;
|
|
bus_addr_t sc_addr;
|
|
size_t sc_size;
|
|
int sc_intr;
|
|
timer_factors_t sc_tf;
|
|
uint sc_bot;
|
|
} omapl1xtmr_softc_t;
|
|
|
|
static struct omapl1x_wdt {
|
|
bus_space_tag_t wdt_iot; /* Bus tag */
|
|
bus_addr_t wdt_addr; /* Address */
|
|
bus_space_handle_t wdt_ioh;
|
|
bus_size_t wdt_size;
|
|
} wdt;
|
|
|
|
static int omapl1xtimer_match(device_t, struct cfdata *, void *);
|
|
static void omapl1xtimer_attach(device_t, device_t, void *);
|
|
|
|
static int omapl1xtimer_clockintr(void *frame);
|
|
static int omapl1xtimer_statintr(void *frame);
|
|
static void omapl1x_microtime_init(void);
|
|
static inline uint32_t omapl1x_get_timecount(struct timecounter *tc);
|
|
static inline void omapl1xtimer_stop(struct omapl1xtmr_softc *sc);
|
|
static inline uint32_t omapl1xtimer_read(struct omapl1xtmr_softc *sc);
|
|
static void omapl1xtimer_prd_intr_dis(struct omapl1xtmr_softc *sc);
|
|
static void omapl1xtimer_prd_intr_enb(struct omapl1xtmr_softc *sc);
|
|
static void omapl1xtimer_prd_intr_clr(struct omapl1xtmr_softc *sc);
|
|
static void omapl1xtimer_start(struct omapl1xtmr_softc *sc);
|
|
static void timer_factors(struct omapl1xtmr_softc *sc, int ints_per_sec,
|
|
uint8_t enamode);
|
|
static void timer_init(struct omapl1xtmr_softc *sc, int schz, uint8_t enamode,
|
|
boolean_t intr);
|
|
|
|
static struct timecounter omapl1x_timecounter = {
|
|
.tc_get_timecount = omapl1x_get_timecount,
|
|
.tc_counter_mask = 0xffffffff,
|
|
.tc_name = "gpt",
|
|
.tc_quality = 100,
|
|
.tc_priv = NULL
|
|
};
|
|
|
|
#ifdef OMAPL1X_TIMER_DEBUG
|
|
static void tfprint(uint, timer_factors_t *);
|
|
#endif
|
|
|
|
static uint32_t counts_per_usec;
|
|
static uint32_t counts_per_hz = ~0;
|
|
static struct omapl1xtmr_softc *clock_sc;
|
|
static struct omapl1xtmr_softc *stat_sc;
|
|
static struct omapl1xtmr_softc *ref_sc;
|
|
|
|
/* Timer modes */
|
|
#define TGCR_TIMMODE_64BIT 0x0
|
|
#define TGCR_TIMMODE_32BIT_UNCHANINED 0x1
|
|
#define TGCR_TIMMODE_64BIT_WDOG 0x2
|
|
#define TGCR_TIMMODE_32BIT_CHANINED 0x3
|
|
#define TGCR_TIMMODE_SHIFT 2
|
|
|
|
#define TGCR_RS_STOP 0x0
|
|
#define TGCR_RS_RUN 0x1
|
|
#define TGCR_RS_MASK 0x3
|
|
#define TGCR_RS_12_SHIFT 0
|
|
#define TGCR_RS_34_SHIFT 1
|
|
|
|
#define TCR_ENAMODE_DISABLE 0x0
|
|
#define TCR_ENAMODE_ONESHOT 0x1
|
|
#define TCR_ENAMODE_CONTINUOUS 0x2
|
|
#define TCR_ENAMODE_RELOAD 0x3
|
|
#define TCR_ENAMODE_MASK 0x3
|
|
#define TCR_ENAMODE_12_SHIFT 6
|
|
#define TCR_ENAMODE_34_SHIFT 22
|
|
|
|
#define INTR_PRD_12_EN_SHIFT 0
|
|
#define INTR_PRD_34_EN_SHIFT 16
|
|
#define INTR_PRD_12_STAT_SHIFT 1
|
|
#define INTR_PRD_34_STAT_SHIFT 17
|
|
|
|
/* Watchdog related macros */
|
|
#define WDTCR_WDTKEY1 0xA5C6
|
|
#define WDTCR_WDTKEY2 0xDA7E
|
|
|
|
#define WDTCR_WDKEY_SHIFT 16
|
|
#define WDTCR_WDEN_SHIFT 14
|
|
#define WDTCR_WDKEY_MASK 0xffff0000
|
|
|
|
CFATTACH_DECL_NEW(omapl1xtimer, sizeof(struct omapl1xtmr_softc),
|
|
omapl1xtimer_match, omapl1xtimer_attach, NULL, NULL);
|
|
|
|
static void
|
|
omapl1xtimer_prd_intr_dis (struct omapl1xtmr_softc *sc)
|
|
{
|
|
uint32_t val;
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT);
|
|
val &= ~(1 << tfp->tf_intr_prd_en_shift);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT, val);
|
|
}
|
|
|
|
static void
|
|
omapl1xtimer_prd_intr_enb (struct omapl1xtmr_softc *sc)
|
|
{
|
|
uint32_t val;
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT);
|
|
val |= 1 << tfp->tf_intr_prd_en_shift;
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT, val);
|
|
}
|
|
|
|
static void
|
|
omapl1xtimer_prd_intr_clr (struct omapl1xtmr_softc *sc)
|
|
{
|
|
uint32_t val;
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT);
|
|
val |= 1 << tfp->tf_intr_prd_stat_shift;
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, INTCTLSTAT, val);
|
|
}
|
|
|
|
static inline uint32_t
|
|
omapl1xtimer_read (struct omapl1xtmr_softc *sc)
|
|
{
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
return bus_space_read_4(sc->sc_iot, sc->sc_ioh, tfp->tf_ctr_reg);
|
|
}
|
|
|
|
static inline void
|
|
omapl1xtimer_stop (struct omapl1xtmr_softc *sc)
|
|
{
|
|
uint32_t val;
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCR);
|
|
val &= ~(TCR_ENAMODE_MASK << tfp->tf_enamode_shift);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCR, val);
|
|
}
|
|
|
|
static void
|
|
omapl1xtimer_start (struct omapl1xtmr_softc *sc)
|
|
{
|
|
uint32_t val, shift;
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
|
|
/* get the timer to be used out of reset */
|
|
shift = sc->sc_bot ? TGCR_RS_12_SHIFT : TGCR_RS_34_SHIFT;
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TGCR);
|
|
|
|
val |= TGCR_RS_RUN << shift;
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TGCR, val);
|
|
|
|
/* set the desired timer period */
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, tfp->tf_prd_reg,
|
|
tfp->tf_period);
|
|
|
|
/* set the selected enamode to get the timer running */
|
|
val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TCR);
|
|
|
|
val |= tfp->tf_enamode << tfp->tf_enamode_shift;
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCR, val);
|
|
}
|
|
|
|
static inline uint32_t
|
|
omapl1x_get_timecount (struct timecounter *tc)
|
|
{
|
|
return omapl1xtimer_read(ref_sc);
|
|
}
|
|
|
|
int
|
|
omapl1xtimer_clockintr (void *frame)
|
|
{
|
|
struct omapl1xtmr_softc *sc = clock_sc;
|
|
|
|
omapl1xtimer_prd_intr_clr(sc);
|
|
hardclock(frame);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
omapl1xtimer_statintr (void *frame)
|
|
{
|
|
struct omapl1xtmr_softc *sc = stat_sc;
|
|
|
|
omapl1xtimer_prd_intr_clr(sc);
|
|
statclock(frame);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
timer_init (struct omapl1xtmr_softc *sc, int schz, uint8_t enamode,
|
|
boolean_t intr)
|
|
{
|
|
int val = 0;
|
|
|
|
timer_factors(sc, schz, enamode);
|
|
|
|
omapl1xtimer_stop(sc);
|
|
omapl1xtimer_prd_intr_dis(sc);
|
|
omapl1xtimer_prd_intr_clr(sc);
|
|
|
|
/* Clear tcr, tgcr, timer counters and period registers */
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TCR, 0);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TGCR, 0);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIM12, 0);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIM34, 0);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, PRD12, 0);
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, PRD34, 0);
|
|
|
|
if (intr)
|
|
omapl1xtimer_prd_intr_enb(sc);
|
|
|
|
/* Set timers to 32 bot unchained mode */
|
|
val = TGCR_TIMMODE_32BIT_UNCHANINED << TGCR_TIMMODE_SHIFT;
|
|
bus_space_write_4(sc->sc_iot, sc->sc_ioh, TGCR, val);
|
|
|
|
omapl1xtimer_start(sc);
|
|
}
|
|
|
|
static void
|
|
omapl1x_microtime_init (void)
|
|
{
|
|
if (ref_sc == NULL)
|
|
panic("microtime reference timer was not configured.");
|
|
timer_init(ref_sc, 0, TCR_ENAMODE_CONTINUOUS, FALSE);
|
|
}
|
|
|
|
void
|
|
setstatclockrate (int schz)
|
|
{
|
|
if (stat_sc == NULL)
|
|
panic("Statistics timer was not configured.");
|
|
timer_init(stat_sc, schz, TCR_ENAMODE_CONTINUOUS, TRUE);
|
|
}
|
|
|
|
/*
|
|
* clock_sc and stat_sc starts here
|
|
* ref_sc is initialized already by tipbtimer_attach
|
|
*/
|
|
void
|
|
cpu_initclocks(void)
|
|
{
|
|
if (clock_sc == NULL)
|
|
panic("Clock timer was not configured.");
|
|
if (stat_sc == NULL)
|
|
panic("Statistics timer was not configured.");
|
|
if (ref_sc == NULL)
|
|
panic("Microtime reference timer was not configured.");
|
|
|
|
/*
|
|
* We already have the timers running, but not generating interrupts.
|
|
* In addition, we've set stathz and profhz.
|
|
*/
|
|
printf("clock: hz=%d stathz=%d\n", hz, stathz);
|
|
|
|
/*
|
|
* The "cookie" parameter must be zero to pass the interrupt frame
|
|
* through to hardclock() and statclock().
|
|
*/
|
|
intr_establish(clock_sc->sc_intr, IPL_CLOCK, IST_LEVEL_HIGH,
|
|
omapl1xtimer_clockintr, 0);
|
|
|
|
intr_establish(stat_sc->sc_intr, IPL_HIGH, IST_LEVEL_HIGH,
|
|
omapl1xtimer_statintr, 0);
|
|
|
|
timer_init(clock_sc, hz, TCR_ENAMODE_CONTINUOUS, TRUE);
|
|
timer_init(stat_sc, stathz, TCR_ENAMODE_CONTINUOUS, TRUE);
|
|
|
|
omapl1x_timecounter.tc_frequency = omapl1x_get_tc_freq();
|
|
|
|
tc_init(&omapl1x_timecounter);
|
|
}
|
|
|
|
void
|
|
delay (u_int n)
|
|
{
|
|
struct omapl1xtmr_softc *sc = ref_sc;
|
|
uint32_t cur, last, delta, usecs;
|
|
|
|
if (sc == NULL)
|
|
panic("The timer must be initialized sooner.");
|
|
|
|
/*
|
|
* This works by polling the timer and counting the
|
|
* number of microseconds that go by.
|
|
*/
|
|
last = omapl1xtimer_read(sc);
|
|
|
|
delta = usecs = 0;
|
|
|
|
while (n > usecs) {
|
|
cur = omapl1xtimer_read(sc);
|
|
|
|
/* Check to see if the timer has wrapped around. */
|
|
if (last > cur)
|
|
delta += (cur + (counts_per_hz - last));
|
|
else
|
|
delta += (cur - last);
|
|
|
|
last = cur;
|
|
|
|
if (delta >= counts_per_usec) {
|
|
usecs += delta / counts_per_usec;
|
|
delta %= counts_per_usec;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
timer_factors (struct omapl1xtmr_softc *sc, int ints_per_sec, uint8_t enamode)
|
|
{
|
|
timer_factors_t *tfp = &sc->sc_tf;
|
|
const uint32_t us_per_sec = 1000000;
|
|
|
|
if (ints_per_sec == 0) {
|
|
tfp->tf_period = ~0U;
|
|
counts_per_usec = sc->sc_timer_freq / us_per_sec;
|
|
} else {
|
|
uint32_t count_freq;
|
|
count_freq = sc->sc_timer_freq;
|
|
count_freq /= ints_per_sec;
|
|
tfp->tf_period = count_freq;
|
|
}
|
|
|
|
tfp->tf_counts_per_usec = sc->sc_timer_freq / us_per_sec;
|
|
tfp->tf_enamode = enamode;
|
|
|
|
if (sc->sc_bot) {
|
|
tfp->tf_ctr_reg = TIM12;
|
|
tfp->tf_prd_reg = PRD12;
|
|
tfp->tf_enamode_shift = TCR_ENAMODE_12_SHIFT;
|
|
tfp->tf_intr_prd_en_shift = INTR_PRD_12_EN_SHIFT;
|
|
tfp->tf_intr_prd_stat_shift = INTR_PRD_12_STAT_SHIFT;
|
|
} else {
|
|
tfp->tf_ctr_reg = TIM34;
|
|
tfp->tf_prd_reg = PRD34;
|
|
tfp->tf_enamode_shift = TCR_ENAMODE_34_SHIFT;
|
|
tfp->tf_intr_prd_en_shift = INTR_PRD_34_EN_SHIFT;
|
|
tfp->tf_intr_prd_stat_shift = INTR_PRD_34_STAT_SHIFT;
|
|
}
|
|
|
|
#ifdef OMAPL1X_TIMER_DEBUG
|
|
tfprint(sc->sc_timerno, tfp);
|
|
Debugger();
|
|
#endif
|
|
}
|
|
|
|
#ifdef OMAPL1X_TIMER_DEBUG
|
|
void
|
|
tfprint (uint n, timer_factors_t *tfp)
|
|
{
|
|
printf("%s: timer# %d\n", __func__, n);
|
|
printf("\ttf_counts_per_usec: %#x\n", tfp->tf_counts_per_usec);
|
|
printf("\ttf_counter: %#x\n", tfp->period);
|
|
printf("\ttf_enamode: %#x\n", tfp->tf_enamode);
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
omapl1xtimer_match (device_t parent, struct cfdata *match, void *aux)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
omapl1xtimer_attach (device_t parent, device_t self, void *aux)
|
|
{
|
|
struct omapl1xtmr_softc *sc = device_private(self);
|
|
struct tipb_attach_args *tipb = aux;
|
|
|
|
sc->sc_timerno = self->dv_unit;
|
|
sc->sc_iot = tipb->tipb_iot;
|
|
sc->sc_intr = tipb->tipb_intr;
|
|
sc->sc_addr = tipb->tipb_addr;
|
|
sc->sc_bot = 1; /* use the bottom timer in all cases */
|
|
sc->sc_size = OMAPL1X_TIMER_SIZE;
|
|
|
|
if (bus_space_map(sc->sc_iot, sc->sc_addr, sc->sc_size, 0, &sc->sc_ioh))
|
|
panic("%s: Cannot map registers", device_xname(self));
|
|
|
|
aprint_normal("\n");
|
|
aprint_naive("\n");
|
|
|
|
switch (sc->sc_timerno) {
|
|
case 0:
|
|
/*
|
|
* timer #0 is the system clock
|
|
* it gets started later
|
|
*/
|
|
clock_sc = sc;
|
|
sc->sc_timer_freq = OMAPL1X_TIMER0_FREQ;
|
|
break;
|
|
case 1:
|
|
/*
|
|
* timer #2 is the stat clock
|
|
* it gets started later
|
|
*/
|
|
profhz = stathz = STATHZ;
|
|
stat_sc = sc;
|
|
sc->sc_timer_freq = OMAPL1X_TIMER2_FREQ;
|
|
break;
|
|
case 2:
|
|
/*
|
|
* Timer #3 is used for microtime reference clock and for delay()
|
|
* autoloading, non-interrupting, just wraps around as an unsigned int.
|
|
* we start it now to make delay() available
|
|
*/
|
|
ref_sc = sc;
|
|
sc->sc_timer_freq = OMAPL1X_TIMER3_FREQ;
|
|
omapl1x_microtime_init();
|
|
break;
|
|
default:
|
|
panic("bad omapl1x timer number %d\n", sc->sc_timerno);
|
|
break;
|
|
}
|
|
|
|
wdt.wdt_iot = tipb->tipb_iot;
|
|
wdt.wdt_addr = OMAPL1X_WDT_ADDR;
|
|
wdt.wdt_size = OMAPL1X_WDT_SIZE;
|
|
|
|
/* Map WDT registers. We want to use it for reseting the chip */
|
|
if (bus_space_map(wdt.wdt_iot, wdt.wdt_addr,
|
|
wdt.wdt_size, 0, &wdt.wdt_ioh)) {
|
|
aprint_error_dev(self, "can't map wdt mem space\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void
|
|
omapl1x_reset (void)
|
|
{
|
|
uint32_t val;
|
|
|
|
printf("\n");
|
|
delay(50000);
|
|
|
|
val = bus_space_read_4(wdt.wdt_iot, wdt.wdt_ioh, TGCR);
|
|
|
|
/*
|
|
* Get the timer out of reset and put it in
|
|
* watchdog timer mode.
|
|
*/
|
|
val |= ((TGCR_RS_RUN << TGCR_RS_12_SHIFT) |
|
|
(TGCR_RS_RUN << TGCR_RS_34_SHIFT));
|
|
val |= (TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT);
|
|
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, TGCR, val);
|
|
|
|
/* Init the counter and period registers */
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, TIM12, 0x0);
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, TIM34, 0x0);
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, PRD12, ~0);
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, PRD34, ~0);
|
|
|
|
val = bus_space_read_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR);
|
|
|
|
/*
|
|
* Now enable the wdt and write the WDKEY1 to get the
|
|
* wd in the Pre-active state.
|
|
*/
|
|
val |= (1 << WDTCR_WDEN_SHIFT);
|
|
val |= (WDTCR_WDTKEY1 << WDTCR_WDKEY_SHIFT);
|
|
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR, val);
|
|
|
|
/*
|
|
* Now write the WDKEY2 to get the wd in the Active
|
|
* state.
|
|
*/
|
|
val = bus_space_read_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR);
|
|
val &= ~WDTCR_WDKEY_MASK;
|
|
val |= (WDTCR_WDTKEY2 << WDTCR_WDKEY_SHIFT);
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR, val);
|
|
|
|
/*
|
|
* Write an invalid value to the WDKEY to trigger
|
|
* the wd timeout right away.
|
|
*/
|
|
val = bus_space_read_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR);
|
|
val &= ~WDTCR_WDKEY_MASK;
|
|
bus_space_write_4(wdt.wdt_iot, wdt.wdt_ioh, WDTCR, val);
|
|
|
|
while(1);
|
|
}
|