Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/platform/coldfire/pit.c
10819 views
1
/***************************************************************************/
2
3
/*
4
* pit.c -- Freescale ColdFire PIT timer. Currently this type of
5
* hardware timer only exists in the Freescale ColdFire
6
* 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
7
* family members will probably use it too.
8
*
9
* Copyright (C) 1999-2008, Greg Ungerer ([email protected])
10
* Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
11
*/
12
13
/***************************************************************************/
14
15
#include <linux/kernel.h>
16
#include <linux/sched.h>
17
#include <linux/param.h>
18
#include <linux/init.h>
19
#include <linux/interrupt.h>
20
#include <linux/irq.h>
21
#include <linux/clockchips.h>
22
#include <asm/machdep.h>
23
#include <asm/io.h>
24
#include <asm/coldfire.h>
25
#include <asm/mcfpit.h>
26
#include <asm/mcfsim.h>
27
28
/***************************************************************************/
29
30
/*
31
* By default use timer1 as the system clock timer.
32
*/
33
#define FREQ ((MCF_CLK / 2) / 64)
34
#define TA(a) (MCFPIT_BASE1 + (a))
35
#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
36
37
static u32 pit_cnt;
38
39
/*
40
* Initialize the PIT timer.
41
*
42
* This is also called after resume to bring the PIT into operation again.
43
*/
44
45
static void init_cf_pit_timer(enum clock_event_mode mode,
46
struct clock_event_device *evt)
47
{
48
switch (mode) {
49
case CLOCK_EVT_MODE_PERIODIC:
50
51
__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
52
__raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
53
__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
54
MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
55
MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
56
break;
57
58
case CLOCK_EVT_MODE_SHUTDOWN:
59
case CLOCK_EVT_MODE_UNUSED:
60
61
__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
62
break;
63
64
case CLOCK_EVT_MODE_ONESHOT:
65
66
__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
67
__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
68
MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
69
TA(MCFPIT_PCSR));
70
break;
71
72
case CLOCK_EVT_MODE_RESUME:
73
/* Nothing to do here */
74
break;
75
}
76
}
77
78
/*
79
* Program the next event in oneshot mode
80
*
81
* Delta is given in PIT ticks
82
*/
83
static int cf_pit_next_event(unsigned long delta,
84
struct clock_event_device *evt)
85
{
86
__raw_writew(delta, TA(MCFPIT_PMR));
87
return 0;
88
}
89
90
struct clock_event_device cf_pit_clockevent = {
91
.name = "pit",
92
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
93
.set_mode = init_cf_pit_timer,
94
.set_next_event = cf_pit_next_event,
95
.shift = 32,
96
.irq = MCFINT_VECBASE + MCFINT_PIT1,
97
};
98
99
100
101
/***************************************************************************/
102
103
static irqreturn_t pit_tick(int irq, void *dummy)
104
{
105
struct clock_event_device *evt = &cf_pit_clockevent;
106
u16 pcsr;
107
108
/* Reset the ColdFire timer */
109
pcsr = __raw_readw(TA(MCFPIT_PCSR));
110
__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
111
112
pit_cnt += PIT_CYCLES_PER_JIFFY;
113
evt->event_handler(evt);
114
return IRQ_HANDLED;
115
}
116
117
/***************************************************************************/
118
119
static struct irqaction pit_irq = {
120
.name = "timer",
121
.flags = IRQF_DISABLED | IRQF_TIMER,
122
.handler = pit_tick,
123
};
124
125
/***************************************************************************/
126
127
static cycle_t pit_read_clk(struct clocksource *cs)
128
{
129
unsigned long flags;
130
u32 cycles;
131
u16 pcntr;
132
133
local_irq_save(flags);
134
pcntr = __raw_readw(TA(MCFPIT_PCNTR));
135
cycles = pit_cnt;
136
local_irq_restore(flags);
137
138
return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
139
}
140
141
/***************************************************************************/
142
143
static struct clocksource pit_clk = {
144
.name = "pit",
145
.rating = 100,
146
.read = pit_read_clk,
147
.shift = 20,
148
.mask = CLOCKSOURCE_MASK(32),
149
};
150
151
/***************************************************************************/
152
153
void hw_timer_init(void)
154
{
155
cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
156
cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
157
cf_pit_clockevent.max_delta_ns =
158
clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
159
cf_pit_clockevent.min_delta_ns =
160
clockevent_delta2ns(0x3f, &cf_pit_clockevent);
161
clockevents_register_device(&cf_pit_clockevent);
162
163
setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
164
165
pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
166
clocksource_register(&pit_clk);
167
}
168
169
/***************************************************************************/
170
171