All of lore.kernel.org
 help / color / mirror / Atom feed
From: Graeme Russ <graeme.russ@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 6/7] Implement SC520 timers
Date: Tue, 24 Feb 2009 21:14:45 +1100	[thread overview]
Message-ID: <49A3C895.9070504@gmail.com> (raw)

Implement SC520 timers

Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
 cpu/i386/Makefile              |    2 
 cpu/i386/sc520/sc520_timer.c   |   71 ++++++++-----
 cpu/i386/timer.c               |  211 ----------------------------------------
 include/asm-i386/u-boot-i386.h |    7 +
 lib_i386/Makefile              |    2 
 lib_i386/pcat_timer.c          |  102 +++++++++++++++++++
 lib_i386/timer.c               |  107 ++++++++++++++++++++
 7 files changed, 259 insertions(+), 243 deletions(-)
 delete mode 100644 cpu/i386/timer.c
 create mode 100644 lib_i386/pcat_timer.c
 create mode 100644 lib_i386/timer.c

diff --git a/cpu/i386/Makefile b/cpu/i386/Makefile
index f72cd6e..e98bd3d 100644
--- a/cpu/i386/Makefile
+++ b/cpu/i386/Makefile
@@ -29,7 +29,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).a
 
 START	= start.o start16.o resetvec.o
-COBJS	= serial.o interrupts.o exceptions.o cpu.o timer.o
+COBJS	= serial.o interrupts.o exceptions.o cpu.o
 
 SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/i386/sc520/sc520_timer.c b/cpu/i386/sc520/sc520_timer.c
index 7578511..2cb8656 100644
--- a/cpu/i386/sc520/sc520_timer.c
+++ b/cpu/i386/sc520/sc520_timer.c
@@ -27,47 +27,56 @@
 #include <asm/interrupt.h>
 #include <asm/ic/sc520.h>
 
-void reset_timer(void)
+void sc520_timer_isr(void)
 {
-	write_mmcr_word(SC520_GPTMR0CNT, 0);
-	write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-
+	/* Ack the GP Timer Interrupt */
+	write_mmcr_byte (SC520_GPTMRSTA, 0x02);
 }
 
-ulong get_timer(ulong base)
+int timer_init(void)
 {
-	/* fixme: 30 or 33 */
-	return	read_mmcr_word(SC520_GPTMR0CNT) / 33;
-}
+	/* Map GP Timer 1 to Master PIC IR0  */
+	write_mmcr_byte (SC520_GPTMR1MAP, 0x01);
 
-void set_timer(ulong t)
-{
-	/* FixMe: use two cascade coupled timers */
-	write_mmcr_word(SC520_GPTMR0CTL, 0x4001);
-	write_mmcr_word(SC520_GPTMR0CNT, t*33);
-	write_mmcr_word(SC520_GPTMR0CTL, 0x6001);
-}
+	/* Disable GP Timers 1 & 2 - Allow configuration writes */
+	write_mmcr_word (SC520_GPTMR1CTL, 0x4000);
+	write_mmcr_word (SC520_GPTMR2CTL, 0x4000);
+
+	/* Reset GP Timers 1 & 2 */
+	write_mmcr_word (SC520_GPTMR1CNT, 0x0000);
+	write_mmcr_word (SC520_GPTMR2CNT, 0x0000);
+
+	/* Setup GP Timer 2 as a 100kHz (10us) prescaler */
+	write_mmcr_word (SC520_GPTMR2MAXCMPA, 83);
+	write_mmcr_word (SC520_GPTMR2CTL, 0xc001);
+
+	/* Setup GP Timer 1 as a 1000 Hz (1ms) interrupt generator */
+	write_mmcr_word (SC520_GPTMR1MAXCMPA, 100);
+	write_mmcr_word (SC520_GPTMR1CTL, 0xe009);
 
+	/* Clear the GP Timers status register */
+	write_mmcr_byte (SC520_GPTMRSTA, 0x07);
+
+	/* Register the SC520 specific timer interrupt handler */
+	register_timer_isr (sc520_timer_isr);
+
+	/* Install interrupt handler for GP Timer 1 */
+	irq_install_handler (0, timer_isr, NULL);
+	unmask_irq (0);
+
+	return 0;
+}
 
 void udelay(unsigned long usec)
 {
-	int m=0;
+	int m = 0;
 	long u;
 
-	read_mmcr_word(SC520_SWTMRMILLI);
-	read_mmcr_word(SC520_SWTMRMICRO);
-
-#if 0
-	/* do not enable this line, udelay is used in the serial driver -> recursion */
-	printf("udelay: %ld m.u %d.%d  tm.tu %d.%d\n", usec, m, u, tm, tu);
-#endif
-	while (1) {
-
-		m += read_mmcr_word(SC520_SWTMRMILLI);
-		u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000);
+	read_mmcr_word (SC520_SWTMRMILLI);
+	read_mmcr_word (SC520_SWTMRMICRO);
 
-		if (usec <= u) {
-			break;
-		}
-	}
+	do {
+		m += read_mmcr_word (SC520_SWTMRMILLI);
+		u = read_mmcr_word (SC520_SWTMRMICRO) + (m * 1000);
+	} while (u < usec);
 }
diff --git a/cpu/i386/timer.c b/cpu/i386/timer.c
deleted file mode 100644
index 79039c2..0000000
--- a/cpu/i386/timer.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * (C) Copyright 2002
- * Daniel Engstr?m, Omicron Ceti AB, daniel@omicron.se.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <asm/i8254.h>
-#include <asm/ibmpc.h>
-
-
-static volatile unsigned long system_ticks;
-static int timer_init_done =0;
-
-static void timer_isr(void *unused)
-{
-	system_ticks++;
-}
-
-unsigned long get_system_ticks(void)
-{
-	return system_ticks;
-}
-
-#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
-#define TIMER2_VALUE 0x0a8e /* 440Hz */
-
-int timer_init(void)
-{
-	system_ticks = 0;
-
-	irq_install_handler(0, timer_isr, NULL);
-
-	/* initialize timer 0 and 2
-	 *
-	 * Timer 0 is used to increment system_tick 1000 times/sec
-	 * Timer 1 was used for DRAM refresh in early PC's
-	 * Timer 2 is used to drive the speaker
-	 * (to stasrt a beep: write 3 to port 0x61,
-	 * to stop it again: write 0)
-	 */
-
-	outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
-	outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
-	outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
-
-	outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
-	outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
-	outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
-
-	timer_init_done = 1;
-
-	return 0;
-}
-
-
-#ifdef CONFIG_SYS_GENERIC_TIMER
-
-/* the unit for these is CONFIG_SYS_HZ */
-
-/* FixMe: implement these */
-void reset_timer (void)
-{
-	system_ticks = 0;
-}
-
-ulong get_timer (ulong base)
-{
-	return (system_ticks - base);
-}
-
-void set_timer (ulong t)
-{
-	system_ticks = t;
-}
-
-static u16 read_pit(void)
-{
-	u8 low;
-	outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
-	low = inb(PIT_BASE + PIT_T0);
-	return ((inb(PIT_BASE + PIT_T0) << 8) | low);
-}
-
-/* this is not very exact */
-void udelay (unsigned long usec)
-{
-	int counter;
-	int wraps;
-
-	if (!timer_init_done) {
-		return;
-	}
-	counter = read_pit();
-	wraps = usec/1000;
-	usec = usec%1000;
-
-	usec*=1194;
-	usec/=1000;
-	usec+=counter;
-	if (usec > 1194) {
-		usec-=1194;
-		wraps++;
-	}
-
-	while (1) {
-		int new_count = read_pit();
-
-		if (((new_count < usec) && !wraps) || wraps < 0) {
-			break;
-		}
-
-		if (new_count > counter) {
-			wraps--;
-		}
-		counter = new_count;
-	}
-
-}
-
-#if 0
-/* this is a version with debug output */
-void _udelay (unsigned long usec)
-{
-	int counter;
-	int wraps;
-
-	int usec1, usec2, usec3;
-	int wraps1, wraps2, wraps3, wraps4;
-	int ctr1, ctr2, ctr3, nct1, nct2;
-	int i;
-	usec1=usec;
-	if (!timer_init_done) {
-		return;
-	}
-	counter = read_pit();
-	ctr1 = counter;
-	wraps = usec/1000;
-	usec = usec%1000;
-
-	usec2 = usec;
-	wraps1 = wraps;
-
-	usec*=1194;
-	usec/=1000;
-	usec+=counter;
-	if (usec > 1194) {
-		usec-=1194;
-		wraps++;
-	}
-
-	usec3 = usec;
-	wraps2 = wraps;
-
-	ctr2 = wraps3 = nct1 = 4711;
-	ctr3 = wraps4 = nct2 = 4711;
-	i=0;
-	while (1) {
-		int new_count = read_pit();
-		i++;
-		if ((new_count < usec && !wraps) || wraps < 0) {
-			break;
-		}
-
-		if (new_count > counter) {
-			wraps--;
-		}
-		if (ctr2==4711) {
-			ctr2 = counter;
-			wraps3 = wraps;
-			nct1 = new_count;
-		} else {
-			ctr3 = counter;
-			wraps4 = wraps;
-			nct2 = new_count;
-		}
-
-		counter = new_count;
-	}
-
-	printf("udelay(%d)\n", usec1);
-	printf("counter %d\n", ctr1);
-	printf("1: wraps %d, usec %d\n", wraps1, usec2);
-	printf("2: wraps %d, usec %d\n", wraps2, usec3);
-	printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
-	printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
-
-	printf("%d %d %d %d %d\n",
-	       read_pit(), read_pit(), read_pit(),
-	       read_pit(), read_pit());
-}
-#endif
-#endif
diff --git a/include/asm-i386/u-boot-i386.h b/include/asm-i386/u-boot-i386.h
index 9a60cac..3921e01 100644
--- a/include/asm-i386/u-boot-i386.h
+++ b/include/asm-i386/u-boot-i386.h
@@ -43,6 +43,13 @@ extern ulong i386boot_bios_size;    /* size of BIOS emulation code */
 
 /* cpu/.../cpu.c */
 int cpu_init(void);
+
+/* cpu/.../timer.c */
+void timer_isr(void *);
+typedef void (timer_fnc_t) (void);
+int register_timer_isr (timer_fnc_t *isr_func);
+
+/* Architecture specific - can be in cpu/i386/, lib_i386/, or $(BOARD)/ */
 int timer_init(void);
 
 /* cpu/.../interrupts.c */
diff --git a/lib_i386/Makefile b/lib_i386/Makefile
index fb4184b..ec6f236 100644
--- a/lib_i386/Makefile
+++ b/lib_i386/Makefile
@@ -39,7 +39,9 @@ COBJS-y	+= video_bios.o
 COBJS-y	+= video.o
 COBJS-y	+= zimage.o
 COBJS-y	+= interrupts.o
+COBJS-y	+= timer.o
 COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o
+COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o
 
 SRCS	:= $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
 OBJS	:= $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
diff --git a/lib_i386/pcat_timer.c b/lib_i386/pcat_timer.c
new file mode 100644
index 0000000..e282f64
--- /dev/null
+++ b/lib_i386/pcat_timer.c
@@ -0,0 +1,102 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engstr?m, Omicron Ceti AB, daniel at omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+#define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
+#define TIMER2_VALUE 0x0a8e /* 440Hz */
+
+int timer_init(void)
+{
+	/* initialize timer 0 and 2
+	 *
+	 * Timer 0 is used to increment system_tick 1000 times/sec
+	 * Timer 1 was used for DRAM refresh in early PC's
+	 * Timer 2 is used to drive the speaker
+	 * (to stasrt a beep: write 3 to port 0x61,
+	 * to stop it again: write 0)
+	 */
+	outb (PIT_CMD_CTR0 | PIT_CMD_BOTH | PIT_CMD_MODE2,
+	      PIT_BASE + PIT_COMMAND);
+	outb (TIMER0_VALUE & 0xff, PIT_BASE + PIT_T0);
+	outb (TIMER0_VALUE >> 8, PIT_BASE + PIT_T0);
+
+	outb (PIT_CMD_CTR2 | PIT_CMD_BOTH | PIT_CMD_MODE3,
+	      PIT_BASE + PIT_COMMAND);
+	outb (TIMER2_VALUE & 0xff, PIT_BASE + PIT_T2);
+	outb (TIMER2_VALUE >> 8, PIT_BASE + PIT_T2);
+
+	irq_install_handler (0, timer_isr, NULL);
+	unmask_irq (0);
+
+	return 0;
+}
+
+static u16 read_pit(void)
+{
+	u8 low;
+
+	outb (PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
+	low = inb (PIT_BASE + PIT_T0);
+
+	return ((inb (PIT_BASE + PIT_T0) << 8) | low);
+}
+
+/* this is not very exact */
+void udelay (unsigned long usec)
+{
+	int counter;
+	int wraps;
+
+	if (timer_init_done)
+	{
+		counter = read_pit ();
+		wraps = usec / 1000;
+		usec = usec % 1000;
+
+		usec *= 1194;
+		usec /= 1000;
+		usec += counter;
+
+		while (usec > 1194) {
+			usec -= 1194;
+			wraps++;
+		}
+
+		while (1) {
+			int new_count = read_pit ();
+
+			if (((new_count < usec) && !wraps) || wraps < 0)
+				break;
+
+			if (new_count > counter)
+				wraps--;
+
+			counter = new_count;
+		}
+	}
+
+}
diff --git a/lib_i386/timer.c b/lib_i386/timer.c
new file mode 100644
index 0000000..5cb1f54
--- /dev/null
+++ b/lib_i386/timer.c
@@ -0,0 +1,107 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engstr?m, Omicron Ceti AB, daniel at omicron.se.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/i8254.h>
+#include <asm/ibmpc.h>
+
+struct timer_isr_function {
+	struct timer_isr_function *next;
+	timer_fnc_t *isr_func;
+};
+
+static struct timer_isr_function *first_timer_isr = NULL;
+static volatile unsigned long system_ticks = 0;
+
+/*
+ * register_timer_isr() allows multiple architecture and board specific
+ * functions to be called every millisecond. Keep the execution time of
+ * each function as low as possible
+ */
+int register_timer_isr (timer_fnc_t *isr_func)
+{
+	struct timer_isr_function *new_func;
+	struct timer_isr_function *temp;
+	int flag;
+
+	new_func = malloc(sizeof(struct timer_isr_function));
+
+	if (new_func == NULL)
+		return 1;
+
+	new_func->isr_func = isr_func;
+	new_func->next = NULL;
+
+	/*
+	 *  Don't allow timer interrupts while the
+	 *  linked list is being modified
+	 */
+	flag = disable_interrupts ();
+
+	if (first_timer_isr == NULL) {
+		first_timer_isr = new_func;
+	} else {
+		temp = first_timer_isr;
+		while (temp->next != NULL)
+			temp = temp->next;
+		temp->next = new_func;
+	}
+
+	if (flag)
+		enable_interrupts ();
+
+	return 0;
+}
+
+/*
+ * timer_isr() MUST be the registered interrupt handler for
+ */
+void timer_isr(void *unused)
+{
+	struct timer_isr_function *temp = first_timer_isr;
+
+	system_ticks++;
+
+	/* Execute each registered function */
+	while (temp != NULL) {
+		temp->isr_func ();
+		temp = temp->next;
+	}
+}
+
+void reset_timer (void)
+{
+	system_ticks = 0;
+}
+
+ulong get_timer (ulong base)
+{
+	return (system_ticks - base);
+}
+
+void set_timer (ulong t)
+{
+	system_ticks = t;
+}

             reply	other threads:[~2009-02-24 10:14 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-24 10:14 Graeme Russ [this message]
2009-02-24 22:35 ` [U-Boot] [PATCH 6/7] Implement SC520 timers Wolfgang Denk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=49A3C895.9070504@gmail.com \
    --to=graeme.russ@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.