summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-07-06 21:36:32 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-07-06 21:36:32 +0000
commit4ae87c8b8ab7ddbd286f5288adaddcaf0a187e31 (patch)
treed3880b9f53a5c38d2211a1b8812724bf96913c4c /firmware/target/arm/s3c2440
parentcbed7a2cd21bb2715b39ebcd3015147a9d7ff3c2 (diff)
Gigabeat: Add timer functionality. Rework tick timer setup to be exactly 100Hz. Metronome should work now but some pcm changes are needed to have faster tocks work correctly (in the works).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13806 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/s3c2440')
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c51
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c127
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h39
3 files changed, 209 insertions, 8 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
index 9df90a2344..39e4efab49 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c
@@ -1,13 +1,49 @@
+#include "config.h"
+#include "system.h"
#include "kernel.h"
+#include "timer.h"
#include "thread.h"
-#include <stdio.h>
-#include "lcd.h"
-
extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void);
-void timer4(void) {
- int i;
+void tick_start(unsigned int interval_in_ms)
+{
+ /*
+ * Based on default PCLK of 49.1568MHz - scaling chosen to give
+ * remainder-free result for tick interval of 10ms (100Hz)
+ * Timer input clock frequency =
+ * fPCLK / {prescaler value+1} / {divider value}
+ * TIMER_FREQ = 49156800 / 2
+ * 13300 = TIMER_FREQ / 231 / 8
+ * 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2
+ * 231 = 11*7*3
+ */
+
+ /* stop timer 4 */
+ TCON &= ~(1 << 20);
+ /* Set the count for timer 4 */
+ TCNTB4 = (TIMER_FREQ / 231 / 8) * interval_in_ms / 1000;
+ /* Set the the prescaler value for timers 2,3, and 4 */
+ TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8);
+ /* MUX4 = 1/16 */
+ TCFG1 = (TCFG1 & ~0xff0000) | 0x030000;
+ /* set manual bit */
+ TCON |= 1 << 21;
+ /* reset manual bit */
+ TCON &= ~(1 << 21);
+ /* interval mode */
+ TCON |= 1 << 22;
+ /* start timer 4 */
+ TCON |= (1 << 20);
+
+ /* timer 4 unmask interrupts */
+ INTMSK &= ~TIMER4_MASK;
+}
+
+void TIMER4(void)
+{
+ int i;
+
/* Run through the list of tick tasks */
for(i = 0; i < MAX_NUM_TICK_TASKS; i++)
{
@@ -19,7 +55,6 @@ void timer4(void) {
current_tick++;
- /* following needs to be fixed. */
- /*wake_up_thread();*/
+ SRCPND = TIMER4_MASK;
+ INTPND = TIMER4_MASK;
}
-
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
new file mode 100644
index 0000000000..4654c7c845
--- /dev/null
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+* $Id$
+*
+* Copyright (C) 2007 by Michael Sevakis
+*
+* All files in this archive are subject to the GNU General Public License.
+* See the file COPYING in the source tree root for full license agreement.
+*
+* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+* KIND, either express or implied.
+*
+****************************************************************************/
+#include "config.h"
+#include "cpu.h"
+#include "system.h"
+#include "timer.h"
+#include "logf.h"
+
+/* GPB0/TOUT0 should already have been configured as output so that pin
+ should not be a functional pin and TIMER0 output unseen there */
+void TIMER0(void)
+{
+ if (pfn_timer != NULL)
+ pfn_timer();
+
+ SRCPND = TIMER0_MASK;
+ INTPND = TIMER0_MASK;
+}
+
+static void stop_timer(void)
+{
+ /* mask interrupt */
+ INTMSK |= TIMER0_MASK;
+
+ /* stop any running TIMER0 */
+ TCON &= ~(1 << 0);
+
+ /* clear pending */
+ SRCPND = TIMER0_MASK;
+ INTPND = TIMER0_MASK;
+}
+
+bool __timer_set(long cycles, bool start)
+{
+ bool retval = false;
+
+ /* Find the minimum factor that puts the counter in range 1-65535 */
+ unsigned int prescaler = (cycles + 65534) / 65535;
+
+ /* Maximum divider setting is x / 256 / 16 = x / 4096 */
+ if (prescaler <= 4096)
+ {
+ int oldlevel;
+ unsigned int divider;
+
+ if (start && pfn_unregister != NULL)
+ {
+ pfn_unregister();
+ pfn_unregister = NULL;
+ }
+
+ oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
+
+ TCMPB0 = 0;
+ TCNTB0 = (unsigned int)cycles / prescaler;
+
+ /* Max prescale is 255+1 */
+ for (divider = 0; prescaler > 256; prescaler >>= 1, divider++);
+
+ TCFG0 = (TCFG0 & ~0xff) | (prescaler - 1);
+ TCFG1 = (TCFG1 & ~0xf) | divider;
+
+ set_irq_level(oldlevel);
+
+ retval = true;
+ }
+
+ return retval;
+}
+
+bool __timer_register(void)
+{
+ bool retval = true;
+
+ int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS);
+
+ stop_timer();
+
+ /* neurosis - make sure something didn't set GPB0 to TOUT0 */
+ if ((GPBCON & 0x3) != 0x2)
+ {
+ /* manual update: on (to reset count) */
+ TCON |= (1 << 1);
+ /* dead zone: off, inverter: off, manual off */
+ TCON &= ~((1 << 4) | (1 << 2) | (1 << 1));
+ /* interval mode (auto reload): on */
+ TCON |= (1 << 3);
+ /* start timer */
+ TCON |= (1 << 0);
+ /* unmask interrupt */
+ INTMSK &= ~TIMER0_MASK;
+ }
+
+ if (!(TCON & (1 << 0)))
+ {
+ /* timer could not be started due to config error */
+ logf("Timer error: GPB0 set to TOUT0");
+ retval = false;
+ }
+
+ set_interrupt_status(oldstatus, IRQ_FIQ_STATUS);
+
+ return retval;
+}
+
+void __timer_unregister(void)
+{
+ int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS);
+ stop_timer();
+ set_interrupt_status(oldstatus, IRQ_FIQ_STATUS);
+}
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h
new file mode 100644
index 0000000000..e9f330cf8e
--- /dev/null
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+* $Id$
+*
+* Copyright (C) 2007 by Michael Sevakis
+*
+* All files in this archive are subject to the GNU General Public License.
+* See the file COPYING in the source tree root for full license agreement.
+*
+* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+* KIND, either express or implied.
+*
+****************************************************************************/
+#ifndef TIMER_TARGET_H
+#define TIMER_TARGET_H
+
+/* timer is based on PCLK and minimum division is 2 */
+#define TIMER_FREQ (49156800/2)
+
+bool __timer_set(long cycles, bool set);
+bool __timer_register(void);
+void __timer_unregister(void);
+
+#define __TIMER_SET(cycles, set) \
+ __timer_set(cycles, set)
+
+#define __TIMER_REGISTER(reg_prio, unregister_callback, cycles, \
+ int_prio, timer_callback) \
+ __timer_register()
+
+#define __TIMER_UNREGISTER(...) \
+ __timer_unregister()
+
+#endif /* TIMER_TARGET_H */