2f2c267989
Reduce the function pointer mess of the m68knommu timer code by calling directly to the local hardware's timer setup, and expose the local common timer interrupt handler to the lower level hardware timer. Ultimately this will save definitions of all these functions across all the platform code to setup the function pointers (which for any given m68knommu CPU family member can be only one set of hardware timer functions). Signed-off-by: Greg Ungerer <gerg@uclinux.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
98 lines
2.7 KiB
C
98 lines
2.7 KiB
C
/***************************************************************************/
|
|
|
|
/*
|
|
* pit.c -- Freescale ColdFire PIT timer. Currently this type of
|
|
* hardware timer only exists in the Freescale ColdFire
|
|
* 5270/5271, 5282 and other CPUs.
|
|
*
|
|
* Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
|
|
* Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
|
|
*/
|
|
|
|
/***************************************************************************/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/param.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/irq.h>
|
|
#include <asm/machdep.h>
|
|
#include <asm/io.h>
|
|
#include <asm/coldfire.h>
|
|
#include <asm/mcfpit.h>
|
|
#include <asm/mcfsim.h>
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
* By default use timer1 as the system clock timer.
|
|
*/
|
|
#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a))
|
|
|
|
/***************************************************************************/
|
|
|
|
static irqreturn_t hw_tick(int irq, void *dummy)
|
|
{
|
|
unsigned short pcsr;
|
|
|
|
/* Reset the ColdFire timer */
|
|
pcsr = __raw_readw(TA(MCFPIT_PCSR));
|
|
__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
|
|
|
|
return arch_timer_interrupt(irq, dummy);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
static struct irqaction coldfire_pit_irq = {
|
|
.name = "timer",
|
|
.flags = IRQF_DISABLED | IRQF_TIMER,
|
|
.handler = hw_tick,
|
|
};
|
|
|
|
void hw_timer_init(void)
|
|
{
|
|
volatile unsigned char *icrp;
|
|
volatile unsigned long *imrp;
|
|
|
|
setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
|
|
|
|
icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
|
|
MCFINTC_ICR0 + MCFINT_PIT1);
|
|
*icrp = ICR_INTRCONF;
|
|
|
|
imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
|
|
*imrp &= ~MCFPIT_IMR_IBIT;
|
|
|
|
/* Set up PIT timer 1 as poll clock */
|
|
__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
|
|
__raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
|
|
__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
|
|
MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
unsigned long hw_timer_offset(void)
|
|
{
|
|
volatile unsigned long *ipr;
|
|
unsigned long pmr, pcntr, offset;
|
|
|
|
ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
|
|
|
|
pmr = __raw_readw(TA(MCFPIT_PMR));
|
|
pcntr = __raw_readw(TA(MCFPIT_PCNTR));
|
|
|
|
/*
|
|
* If we are still in the first half of the upcount and a
|
|
* timer interrupt is pending, then add on a ticks worth of time.
|
|
*/
|
|
offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
|
|
if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT))
|
|
offset += 1000000 / HZ;
|
|
return offset;
|
|
}
|
|
|
|
/***************************************************************************/
|