Blame view
arch/arm/plat-orion/time.c
5.21 KB
2bac1de20 plat-orion: share... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * arch/arm/plat-orion/time.c * * Marvell Orion SoC timer handling. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. * * Timer 0 is used as free-running clocksource, while timer 1 is * used as clock_event_device. */ #include <linux/kernel.h> |
a399e3fa7 [ARM] orion: make... |
15 |
#include <linux/timer.h> |
2bac1de20 plat-orion: share... |
16 17 18 |
#include <linux/clockchips.h> #include <linux/interrupt.h> #include <linux/irq.h> |
f06a16246 ARM: orion: conve... |
19 |
#include <asm/sched_clock.h> |
2bac1de20 plat-orion: share... |
20 21 |
/* |
4ee1f6b57 ARM: Remove depen... |
22 |
* MBus bridge block registers. |
2bac1de20 plat-orion: share... |
23 |
*/ |
4ee1f6b57 ARM: Remove depen... |
24 25 26 27 |
#define BRIDGE_CAUSE_OFF 0x0110 #define BRIDGE_MASK_OFF 0x0114 #define BRIDGE_INT_TIMER0 0x0002 #define BRIDGE_INT_TIMER1 0x0004 |
2bac1de20 plat-orion: share... |
28 29 30 31 32 |
/* * Timer block registers. */ |
4ee1f6b57 ARM: Remove depen... |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#define TIMER_CTRL_OFF 0x0000 #define TIMER0_EN 0x0001 #define TIMER0_RELOAD_EN 0x0002 #define TIMER1_EN 0x0004 #define TIMER1_RELOAD_EN 0x0008 #define TIMER0_RELOAD_OFF 0x0010 #define TIMER0_VAL_OFF 0x0014 #define TIMER1_RELOAD_OFF 0x0018 #define TIMER1_VAL_OFF 0x001c /* * SoC-specific data. */ static void __iomem *bridge_base; static u32 bridge_timer1_clr_mask; static void __iomem *timer_base; /* * Number of timer ticks per jiffy. */ static u32 ticks_per_jiffy; |
2bac1de20 plat-orion: share... |
56 57 58 |
/* |
8a3269fc2 [ARM] orion: sche... |
59 |
* Orion's sched_clock implementation. It has a resolution of |
f06a16246 ARM: orion: conve... |
60 |
* at least 7.5ns (133MHz TCLK). |
8a3269fc2 [ARM] orion: sche... |
61 |
*/ |
8a3269fc2 [ARM] orion: sche... |
62 |
|
2f0778afa ARM: 7205/2: sche... |
63 |
static u32 notrace orion_read_sched_clock(void) |
a399e3fa7 [ARM] orion: make... |
64 |
{ |
2f0778afa ARM: 7205/2: sche... |
65 |
return ~readl(timer_base + TIMER0_VAL_OFF); |
8a3269fc2 [ARM] orion: sche... |
66 67 68 |
} /* |
2bac1de20 plat-orion: share... |
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
* Clockevent handling. */ static int orion_clkevt_next_event(unsigned long delta, struct clock_event_device *dev) { unsigned long flags; u32 u; if (delta == 0) return -ETIME; local_irq_save(flags); /* * Clear and enable clockevent timer interrupt. */ |
4ee1f6b57 ARM: Remove depen... |
85 |
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); |
2bac1de20 plat-orion: share... |
86 |
|
4ee1f6b57 ARM: Remove depen... |
87 |
u = readl(bridge_base + BRIDGE_MASK_OFF); |
2bac1de20 plat-orion: share... |
88 |
u |= BRIDGE_INT_TIMER1; |
4ee1f6b57 ARM: Remove depen... |
89 |
writel(u, bridge_base + BRIDGE_MASK_OFF); |
2bac1de20 plat-orion: share... |
90 91 92 93 |
/* * Setup new clockevent timer value. */ |
4ee1f6b57 ARM: Remove depen... |
94 |
writel(delta, timer_base + TIMER1_VAL_OFF); |
2bac1de20 plat-orion: share... |
95 96 97 98 |
/* * Enable the timer. */ |
4ee1f6b57 ARM: Remove depen... |
99 |
u = readl(timer_base + TIMER_CTRL_OFF); |
2bac1de20 plat-orion: share... |
100 |
u = (u & ~TIMER1_RELOAD_EN) | TIMER1_EN; |
4ee1f6b57 ARM: Remove depen... |
101 |
writel(u, timer_base + TIMER_CTRL_OFF); |
2bac1de20 plat-orion: share... |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
local_irq_restore(flags); return 0; } static void orion_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) { unsigned long flags; u32 u; local_irq_save(flags); if (mode == CLOCK_EVT_MODE_PERIODIC) { /* * Setup timer to fire at 1/HZ intervals. */ |
4ee1f6b57 ARM: Remove depen... |
119 120 |
writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); |
2bac1de20 plat-orion: share... |
121 122 123 124 |
/* * Enable timer interrupt. */ |
4ee1f6b57 ARM: Remove depen... |
125 126 |
u = readl(bridge_base + BRIDGE_MASK_OFF); writel(u | BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); |
2bac1de20 plat-orion: share... |
127 128 129 130 |
/* * Enable timer. */ |
4ee1f6b57 ARM: Remove depen... |
131 132 133 |
u = readl(timer_base + TIMER_CTRL_OFF); writel(u | TIMER1_EN | TIMER1_RELOAD_EN, timer_base + TIMER_CTRL_OFF); |
2bac1de20 plat-orion: share... |
134 135 136 137 |
} else { /* * Disable timer. */ |
4ee1f6b57 ARM: Remove depen... |
138 139 |
u = readl(timer_base + TIMER_CTRL_OFF); writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); |
2bac1de20 plat-orion: share... |
140 141 142 143 |
/* * Disable timer interrupt. */ |
4ee1f6b57 ARM: Remove depen... |
144 145 |
u = readl(bridge_base + BRIDGE_MASK_OFF); writel(u & ~BRIDGE_INT_TIMER1, bridge_base + BRIDGE_MASK_OFF); |
2bac1de20 plat-orion: share... |
146 147 148 149 |
/* * ACK pending timer interrupt. */ |
4ee1f6b57 ARM: Remove depen... |
150 |
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); |
2bac1de20 plat-orion: share... |
151 152 153 154 155 156 157 158 159 160 |
} local_irq_restore(flags); } static struct clock_event_device orion_clkevt = { .name = "orion_tick", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .shift = 32, .rating = 300, |
2bac1de20 plat-orion: share... |
161 162 163 164 165 166 167 168 169 |
.set_next_event = orion_clkevt_next_event, .set_mode = orion_clkevt_mode, }; static irqreturn_t orion_timer_interrupt(int irq, void *dev_id) { /* * ACK timer interrupt and call event handler. */ |
4ee1f6b57 ARM: Remove depen... |
170 |
writel(bridge_timer1_clr_mask, bridge_base + BRIDGE_CAUSE_OFF); |
2bac1de20 plat-orion: share... |
171 172 173 174 175 176 177 178 179 180 |
orion_clkevt.event_handler(&orion_clkevt); return IRQ_HANDLED; } static struct irqaction orion_timer_irq = { .name = "orion_tick", .flags = IRQF_DISABLED | IRQF_TIMER, .handler = orion_timer_interrupt }; |
4ee1f6b57 ARM: Remove depen... |
181 182 183 184 185 186 187 188 189 |
void __init orion_time_set_base(u32 _timer_base) { timer_base = (void __iomem *)_timer_base; } void __init orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask, unsigned int irq, unsigned int tclk) |
2bac1de20 plat-orion: share... |
190 191 |
{ u32 u; |
4ee1f6b57 ARM: Remove depen... |
192 193 194 195 196 |
/* * Set SoC-specific data. */ bridge_base = (void __iomem *)_bridge_base; bridge_timer1_clr_mask = _bridge_timer1_clr_mask; |
2bac1de20 plat-orion: share... |
197 |
ticks_per_jiffy = (tclk + HZ/2) / HZ; |
8a3269fc2 [ARM] orion: sche... |
198 |
/* |
4ee1f6b57 ARM: Remove depen... |
199 |
* Set scale and timer for sched_clock. |
8a3269fc2 [ARM] orion: sche... |
200 |
*/ |
2f0778afa ARM: 7205/2: sche... |
201 |
setup_sched_clock(orion_read_sched_clock, 32, tclk); |
2bac1de20 plat-orion: share... |
202 203 204 |
/* * Setup free-running clocksource timer (interrupts |
4ee1f6b57 ARM: Remove depen... |
205 |
* disabled). |
2bac1de20 plat-orion: share... |
206 |
*/ |
4ee1f6b57 ARM: Remove depen... |
207 208 209 210 211 212 |
writel(0xffffffff, timer_base + TIMER0_VAL_OFF); writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); u = readl(bridge_base + BRIDGE_MASK_OFF); writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF); u = readl(timer_base + TIMER_CTRL_OFF); writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF); |
bfe45e0be clocksource: conv... |
213 214 |
clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource", tclk, 300, 32, clocksource_mmio_readl_down); |
2bac1de20 plat-orion: share... |
215 |
|
2bac1de20 plat-orion: share... |
216 |
/* |
4ee1f6b57 ARM: Remove depen... |
217 |
* Setup clockevent timer (interrupt-driven). |
2bac1de20 plat-orion: share... |
218 219 220 221 222 |
*/ setup_irq(irq, &orion_timer_irq); orion_clkevt.mult = div_sc(tclk, NSEC_PER_SEC, orion_clkevt.shift); orion_clkevt.max_delta_ns = clockevent_delta2ns(0xfffffffe, &orion_clkevt); orion_clkevt.min_delta_ns = clockevent_delta2ns(1, &orion_clkevt); |
320ab2b0b cpumask: convert ... |
223 |
orion_clkevt.cpumask = cpumask_of(0); |
2bac1de20 plat-orion: share... |
224 225 |
clockevents_register_device(&orion_clkevt); } |