~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/hexagon/kernel/time.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Time related functions for Hexagon architecture
 
3
 *
 
4
 * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License version 2 and
 
8
 * only version 2 as published by the Free Software Foundation.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 
18
 * 02110-1301, USA.
 
19
 */
 
20
 
 
21
#include <linux/init.h>
 
22
#include <linux/clockchips.h>
 
23
#include <linux/clocksource.h>
 
24
#include <linux/interrupt.h>
 
25
#include <linux/err.h>
 
26
#include <linux/platform_device.h>
 
27
#include <linux/ioport.h>
 
28
#include <linux/of.h>
 
29
#include <linux/of_address.h>
 
30
#include <linux/of_irq.h>
 
31
 
 
32
#include <asm/timer-regs.h>
 
33
#include <asm/hexagon_vm.h>
 
34
 
 
35
/*
 
36
 * For the clocksource we need:
 
37
 *      pcycle frequency (600MHz)
 
38
 * For the loops_per_jiffy we need:
 
39
 *      thread/cpu frequency (100MHz)
 
40
 * And for the timer, we need:
 
41
 *      sleep clock rate
 
42
 */
 
43
 
 
44
cycles_t        pcycle_freq_mhz;
 
45
cycles_t        thread_freq_mhz;
 
46
cycles_t        sleep_clk_freq;
 
47
 
 
48
static struct resource rtos_timer_resources[] = {
 
49
        {
 
50
                .start  = RTOS_TIMER_REGS_ADDR,
 
51
                .end    = RTOS_TIMER_REGS_ADDR+PAGE_SIZE-1,
 
52
                .flags  = IORESOURCE_MEM,
 
53
        },
 
54
};
 
55
 
 
56
static struct platform_device rtos_timer_device = {
 
57
        .name           = "rtos_timer",
 
58
        .id             = -1,
 
59
        .num_resources  = ARRAY_SIZE(rtos_timer_resources),
 
60
        .resource       = rtos_timer_resources,
 
61
};
 
62
 
 
63
/*  A lot of this stuff should move into a platform specific section.  */
 
64
struct adsp_hw_timer_struct {
 
65
        u32 match;   /*  Match value  */
 
66
        u32 count;
 
67
        u32 enable;  /*  [1] - CLR_ON_MATCH_EN, [0] - EN  */
 
68
        u32 clear;   /*  one-shot register that clears the count  */
 
69
};
 
70
 
 
71
/*  Look for "TCX0" for related constants.  */
 
72
static __iomem struct adsp_hw_timer_struct *rtos_timer;
 
73
 
 
74
static cycle_t timer_get_cycles(struct clocksource *cs)
 
75
{
 
76
        return (cycle_t) __vmgettime();
 
77
}
 
78
 
 
79
static struct clocksource hexagon_clocksource = {
 
80
        .name           = "pcycles",
 
81
        .rating         = 250,
 
82
        .read           = timer_get_cycles,
 
83
        .mask           = CLOCKSOURCE_MASK(64),
 
84
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 
85
};
 
86
 
 
87
static int set_next_event(unsigned long delta, struct clock_event_device *evt)
 
88
{
 
89
        /*  Assuming the timer will be disabled when we enter here.  */
 
90
 
 
91
        iowrite32(1, &rtos_timer->clear);
 
92
        iowrite32(0, &rtos_timer->clear);
 
93
 
 
94
        iowrite32(delta, &rtos_timer->match);
 
95
        iowrite32(1 << TIMER_ENABLE, &rtos_timer->enable);
 
96
        return 0;
 
97
}
 
98
 
 
99
/*
 
100
 * Sets the mode (periodic, shutdown, oneshot, etc) of a timer.
 
101
 */
 
102
static void set_mode(enum clock_event_mode mode,
 
103
        struct clock_event_device *evt)
 
104
{
 
105
        switch (mode) {
 
106
        case CLOCK_EVT_MODE_SHUTDOWN:
 
107
                /* XXX implement me */
 
108
        default:
 
109
                break;
 
110
        }
 
111
}
 
112
 
 
113
#ifdef CONFIG_SMP
 
114
/*  Broadcast mechanism  */
 
115
static void broadcast(const struct cpumask *mask)
 
116
{
 
117
        send_ipi(mask, IPI_TIMER);
 
118
}
 
119
#endif
 
120
 
 
121
static struct clock_event_device hexagon_clockevent_dev = {
 
122
        .name           = "clockevent",
 
123
        .features       = CLOCK_EVT_FEAT_ONESHOT,
 
124
        .rating         = 400,
 
125
        .irq            = RTOS_TIMER_INT,
 
126
        .set_next_event = set_next_event,
 
127
        .set_mode       = set_mode,
 
128
#ifdef CONFIG_SMP
 
129
        .broadcast      = broadcast,
 
130
#endif
 
131
};
 
132
 
 
133
#ifdef CONFIG_SMP
 
134
static DEFINE_PER_CPU(struct clock_event_device, clock_events);
 
135
 
 
136
void setup_percpu_clockdev(void)
 
137
{
 
138
        int cpu = smp_processor_id();
 
139
        struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
 
140
        struct clock_event_device *dummy_clock_dev =
 
141
                &per_cpu(clock_events, cpu);
 
142
 
 
143
        memcpy(dummy_clock_dev, ce_dev, sizeof(*dummy_clock_dev));
 
144
        INIT_LIST_HEAD(&dummy_clock_dev->list);
 
145
 
 
146
        dummy_clock_dev->features = CLOCK_EVT_FEAT_DUMMY;
 
147
        dummy_clock_dev->cpumask = cpumask_of(cpu);
 
148
        dummy_clock_dev->mode = CLOCK_EVT_MODE_UNUSED;
 
149
 
 
150
        clockevents_register_device(dummy_clock_dev);
 
151
}
 
152
 
 
153
/*  Called from smp.c for each CPU's timer ipi call  */
 
154
void ipi_timer(void)
 
155
{
 
156
        int cpu = smp_processor_id();
 
157
        struct clock_event_device *ce_dev = &per_cpu(clock_events, cpu);
 
158
 
 
159
        ce_dev->event_handler(ce_dev);
 
160
}
 
161
#endif /* CONFIG_SMP */
 
162
 
 
163
static irqreturn_t timer_interrupt(int irq, void *devid)
 
164
{
 
165
        struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
 
166
 
 
167
        iowrite32(0, &rtos_timer->enable);
 
168
        ce_dev->event_handler(ce_dev);
 
169
 
 
170
        return IRQ_HANDLED;
 
171
}
 
172
 
 
173
/*  This should also be pulled from devtree  */
 
174
static struct irqaction rtos_timer_intdesc = {
 
175
        .handler = timer_interrupt,
 
176
        .flags = IRQF_TIMER | IRQF_TRIGGER_RISING,
 
177
        .name = "rtos_timer"
 
178
};
 
179
 
 
180
/*
 
181
 * time_init_deferred - called by start_kernel to set up timer/clock source
 
182
 *
 
183
 * Install the IRQ handler for the clock, setup timers.
 
184
 * This is done late, as that way, we can use ioremap().
 
185
 *
 
186
 * This runs just before the delay loop is calibrated, and
 
187
 * is used for delay calibration.
 
188
 */
 
189
void __init time_init_deferred(void)
 
190
{
 
191
        struct resource *resource = NULL;
 
192
        struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
 
193
        struct device_node *dn;
 
194
        struct resource r;
 
195
        int err;
 
196
 
 
197
        ce_dev->cpumask = cpu_all_mask;
 
198
 
 
199
        if (!resource)
 
200
                resource = rtos_timer_device.resource;
 
201
 
 
202
        /*  ioremap here means this has to run later, after paging init  */
 
203
        rtos_timer = ioremap(resource->start, resource->end
 
204
                - resource->start + 1);
 
205
 
 
206
        if (!rtos_timer) {
 
207
                release_mem_region(resource->start, resource->end
 
208
                        - resource->start + 1);
 
209
        }
 
210
        clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
 
211
 
 
212
        /*  Note: the sim generic RTOS clock is apparently really 18750Hz  */
 
213
 
 
214
        /*
 
215
         * Last arg is some guaranteed seconds for which the conversion will
 
216
         * work without overflow.
 
217
         */
 
218
        clockevents_calc_mult_shift(ce_dev, sleep_clk_freq, 4);
 
219
 
 
220
        ce_dev->max_delta_ns = clockevent_delta2ns(0x7fffffff, ce_dev);
 
221
        ce_dev->min_delta_ns = clockevent_delta2ns(0xf, ce_dev);
 
222
 
 
223
#ifdef CONFIG_SMP
 
224
        setup_percpu_clockdev();
 
225
#endif
 
226
 
 
227
        clockevents_register_device(ce_dev);
 
228
        setup_irq(ce_dev->irq, &rtos_timer_intdesc);
 
229
}
 
230
 
 
231
void __init time_init(void)
 
232
{
 
233
        late_time_init = time_init_deferred;
 
234
}
 
235
 
 
236
/*
 
237
 * This could become parametric or perhaps even computed at run-time,
 
238
 * but for now we take the observed simulator jitter.
 
239
 */
 
240
static long long fudgefactor = 350;  /* Maybe lower if kernel optimized. */
 
241
 
 
242
void __udelay(unsigned long usecs)
 
243
{
 
244
        unsigned long long start = __vmgettime();
 
245
        unsigned long long finish = (pcycle_freq_mhz * usecs) - fudgefactor;
 
246
 
 
247
        while ((__vmgettime() - start) < finish)
 
248
                cpu_relax(); /*  not sure how this improves readability  */
 
249
}
 
250
EXPORT_SYMBOL(__udelay);