summaryrefslogtreecommitdiff
path: root/cpu/arm920t/wmt/interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/arm920t/wmt/interrupts.c')
-rwxr-xr-xcpu/arm920t/wmt/interrupts.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/cpu/arm920t/wmt/interrupts.c b/cpu/arm920t/wmt/interrupts.c
new file mode 100755
index 0000000..8663208
--- /dev/null
+++ b/cpu/arm920t/wmt/interrupts.c
@@ -0,0 +1,231 @@
+/*
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * Copyright (c) 2008 WonderMedia Technologies, Inc.
+ *
+ * This program 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 Software Foundation,
+ * either version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_WMT)
+
+#include <asm/arch/common_def.h>
+#include <asm/arch/hardware.h>
+
+#include "pmc.h"
+
+#define TIMER_LOAD_VAL 0xffffffff
+
+static PMC_REG *pmc_regs = (PMC_REG *) BA_PMC;
+
+/* macro to read the 32 bit timer */
+static inline ulong READ_TIMER(void)
+{
+ if ((pmc_regs->OS_Timer_Ctrl & OSTC_RDREQ) == 0)
+ pmc_regs->OS_Timer_Ctrl |= OSTC_RDREQ;
+
+ while (pmc_regs->OS_Timer_Access_Sts & OSTA_RCA)
+ ;
+
+ return pmc_regs->OS_Timer_Count;
+}
+
+static ulong timestamp;
+static ulong lastdec;
+
+/* nothing really to do with interrupts, just starts up a counter. */
+int interrupt_init(void)
+{
+ /*
+ * Disable all OS Timer Control functions.
+ */
+ pmc_regs->OS_Timer_Ctrl = 0;
+
+ /*
+ * Disable OS Timer Watchdog.
+ */
+ pmc_regs->OS_Timer_WatchDog_Enable = 0;
+
+ /*
+ * Disable all OS Timer Interrupts.
+ */
+ pmc_regs->OS_Timer_Int_Enable = 0;
+
+
+ /*
+ * Clean all active OS Timer Match Status.
+ */
+ pmc_regs->OS_Timer_Sts = (OSTS_M0 | OSTS_M1 | OSTS_M2 | OSTS_M3);
+
+ /*
+ * Enable OS Timer update.
+ */
+ if ((pmc_regs->OS_Timer_Ctrl & OSTC_ENABLE) == 0)
+ pmc_regs->OS_Timer_Ctrl |= OSTC_ENABLE;
+
+ /* init the timestamp and lastdec value */
+ reset_timer_masked();
+
+ return 0;
+}
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+/* delay x useconds AND perserve advance timstamp value */
+void udelay(unsigned long usec)
+{
+ ulong tmo, tmp;
+
+ if (usec >= 1000) { /* if "big" number, spread normalization to seconds */
+ tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
+ tmo *= CFG_HZ; /* find number of "ticks" to wait to achieve target */
+ tmo /= 1000; /* finish normalize. */
+ } else { /* else small number, don't kill it prior to HZ multiply */
+ tmo = usec * CFG_HZ;
+ tmo /= (1000*1000);
+ }
+
+ tmp = get_timer(0); /* get current timestamp */
+ if ((tmo + tmp + 1) < tmp) /* if setting this fordward will roll time stamp */
+ reset_timer_masked(); /* reset "advancing" timestamp to 0, set lastdec value */
+ else
+ tmo += tmp; /* else, set advancing stamp wake up time */
+
+ while (get_timer_masked() < tmo) /* loop till event */
+ /* NOP */;
+}
+
+void reset_timer_masked(void)
+{
+ /* reset time */
+ lastdec = READ_TIMER(); /* capure current incrementer value time */
+ timestamp = 0; /* start "advancing" time stamp from 0 */
+}
+
+ulong get_timer_masked(void)
+{
+ ulong now = READ_TIMER(); /* current tick value */
+
+ if (lastdec <= now) { /* normal mode (non roll) */
+ /* normal mode */
+ timestamp += now - lastdec; /* move stamp fordward with absoulte diff ticks */
+ } else {
+ /* we have an overflow ... */
+ timestamp += now + TIMER_LOAD_VAL - lastdec;
+ }
+ lastdec = now;
+
+ return timestamp;
+}
+
+void udelay_masked(unsigned long usec)
+{
+ ulong tmo;
+ ulong endtime;
+ signed long diff;
+
+ if (usec >= 1000) { /* if "big" number, spread normalization to seconds */
+ tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
+ tmo *= CFG_HZ; /* find number of "ticks" to wait to achieve target */
+ tmo /= 1000; /* finish normalize. */
+ } else { /* else small number, don't kill it prior to HZ multiply */
+ tmo = usec * CFG_HZ;
+ tmo /= (1000*1000);
+ }
+
+ endtime = get_timer_masked() + tmo;
+
+ do {
+ ulong now = get_timer_masked();
+ diff = endtime - now;
+ } while (diff >= 0);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+ return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+ ulong tbclk;
+
+ tbclk = CFG_HZ;
+
+ return tbclk;
+}
+
+/*
+ * reset the cpu by setting up the watchdog timer and let him time out
+ */
+void reset_cpu(ulong ignored)
+{
+ /* Clean prevoius reset status */
+ pmc_regs->Reset_Sts = (PMRS_PGR | PMRS_SHR | PMRS_SWR | PMRS_WDR | PMRS_HBR | PMRS_IOR | PMRS_PMR);
+
+ /* set PLLC to default value */
+ while (pmc_regs->PM_Sts2&0x3F0038)
+ ;
+ pmc_regs->PLLC = 0x02270001;
+ while (pmc_regs->PM_Sts2&0x3F0038)
+ ;
+
+ /* Request software reset */
+ pmc_regs->SW_Reset_Req = PMSR_SWR;
+
+ while (1) /* loop forever and wait for reset to happen */
+ ;
+
+ /*NOTREACHED*/
+}
+
+#endif /* defined(CONFIG_WMT) */