Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-cns3xxx/core.c
10817 views
1
/*
2
* Copyright 1999 - 2003 ARM Limited
3
* Copyright 2000 Deep Blue Solutions Ltd
4
* Copyright 2008 Cavium Networks
5
*
6
* This file is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License, Version 2, as
8
* published by the Free Software Foundation.
9
*/
10
11
#include <linux/init.h>
12
#include <linux/interrupt.h>
13
#include <linux/clockchips.h>
14
#include <linux/io.h>
15
#include <asm/mach/map.h>
16
#include <asm/mach/time.h>
17
#include <asm/mach/irq.h>
18
#include <asm/hardware/gic.h>
19
#include <mach/cns3xxx.h>
20
#include "core.h"
21
22
static struct map_desc cns3xxx_io_desc[] __initdata = {
23
{
24
.virtual = CNS3XXX_TC11MP_TWD_BASE_VIRT,
25
.pfn = __phys_to_pfn(CNS3XXX_TC11MP_TWD_BASE),
26
.length = SZ_4K,
27
.type = MT_DEVICE,
28
}, {
29
.virtual = CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT,
30
.pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_CPU_BASE),
31
.length = SZ_4K,
32
.type = MT_DEVICE,
33
}, {
34
.virtual = CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT,
35
.pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_DIST_BASE),
36
.length = SZ_4K,
37
.type = MT_DEVICE,
38
}, {
39
.virtual = CNS3XXX_TIMER1_2_3_BASE_VIRT,
40
.pfn = __phys_to_pfn(CNS3XXX_TIMER1_2_3_BASE),
41
.length = SZ_4K,
42
.type = MT_DEVICE,
43
}, {
44
.virtual = CNS3XXX_GPIOA_BASE_VIRT,
45
.pfn = __phys_to_pfn(CNS3XXX_GPIOA_BASE),
46
.length = SZ_4K,
47
.type = MT_DEVICE,
48
}, {
49
.virtual = CNS3XXX_GPIOB_BASE_VIRT,
50
.pfn = __phys_to_pfn(CNS3XXX_GPIOB_BASE),
51
.length = SZ_4K,
52
.type = MT_DEVICE,
53
}, {
54
.virtual = CNS3XXX_MISC_BASE_VIRT,
55
.pfn = __phys_to_pfn(CNS3XXX_MISC_BASE),
56
.length = SZ_4K,
57
.type = MT_DEVICE,
58
}, {
59
.virtual = CNS3XXX_PM_BASE_VIRT,
60
.pfn = __phys_to_pfn(CNS3XXX_PM_BASE),
61
.length = SZ_4K,
62
.type = MT_DEVICE,
63
},
64
};
65
66
void __init cns3xxx_map_io(void)
67
{
68
iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
69
}
70
71
/* used by entry-macro.S */
72
void __init cns3xxx_init_irq(void)
73
{
74
gic_init(0, 29, __io(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
75
__io(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
76
}
77
78
void cns3xxx_power_off(void)
79
{
80
u32 __iomem *pm_base = __io(CNS3XXX_PM_BASE_VIRT);
81
u32 clkctrl;
82
83
printk(KERN_INFO "powering system down...\n");
84
85
clkctrl = readl(pm_base + PM_SYS_CLK_CTRL_OFFSET);
86
clkctrl &= 0xfffff1ff;
87
clkctrl |= (0x5 << 9); /* Hibernate */
88
writel(clkctrl, pm_base + PM_SYS_CLK_CTRL_OFFSET);
89
90
}
91
92
/*
93
* Timer
94
*/
95
static void __iomem *cns3xxx_tmr1;
96
97
static void cns3xxx_timer_set_mode(enum clock_event_mode mode,
98
struct clock_event_device *clk)
99
{
100
unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
101
int pclk = cns3xxx_cpu_clock() / 8;
102
int reload;
103
104
switch (mode) {
105
case CLOCK_EVT_MODE_PERIODIC:
106
reload = pclk * 20 / (3 * HZ) * 0x25000;
107
writel(reload, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
108
ctrl |= (1 << 0) | (1 << 2) | (1 << 9);
109
break;
110
case CLOCK_EVT_MODE_ONESHOT:
111
/* period set, and timer enabled in 'next_event' hook */
112
ctrl |= (1 << 2) | (1 << 9);
113
break;
114
case CLOCK_EVT_MODE_UNUSED:
115
case CLOCK_EVT_MODE_SHUTDOWN:
116
default:
117
ctrl = 0;
118
}
119
120
writel(ctrl, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
121
}
122
123
static int cns3xxx_timer_set_next_event(unsigned long evt,
124
struct clock_event_device *unused)
125
{
126
unsigned long ctrl = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
127
128
writel(evt, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
129
writel(ctrl | (1 << 0), cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
130
131
return 0;
132
}
133
134
static struct clock_event_device cns3xxx_tmr1_clockevent = {
135
.name = "cns3xxx timer1",
136
.shift = 8,
137
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
138
.set_mode = cns3xxx_timer_set_mode,
139
.set_next_event = cns3xxx_timer_set_next_event,
140
.rating = 350,
141
.cpumask = cpu_all_mask,
142
};
143
144
static void __init cns3xxx_clockevents_init(unsigned int timer_irq)
145
{
146
cns3xxx_tmr1_clockevent.irq = timer_irq;
147
cns3xxx_tmr1_clockevent.mult =
148
div_sc((cns3xxx_cpu_clock() >> 3) * 1000000, NSEC_PER_SEC,
149
cns3xxx_tmr1_clockevent.shift);
150
cns3xxx_tmr1_clockevent.max_delta_ns =
151
clockevent_delta2ns(0xffffffff, &cns3xxx_tmr1_clockevent);
152
cns3xxx_tmr1_clockevent.min_delta_ns =
153
clockevent_delta2ns(0xf, &cns3xxx_tmr1_clockevent);
154
155
clockevents_register_device(&cns3xxx_tmr1_clockevent);
156
}
157
158
/*
159
* IRQ handler for the timer
160
*/
161
static irqreturn_t cns3xxx_timer_interrupt(int irq, void *dev_id)
162
{
163
struct clock_event_device *evt = &cns3xxx_tmr1_clockevent;
164
u32 __iomem *stat = cns3xxx_tmr1 + TIMER1_2_INTERRUPT_STATUS_OFFSET;
165
u32 val;
166
167
/* Clear the interrupt */
168
val = readl(stat);
169
writel(val & ~(1 << 2), stat);
170
171
evt->event_handler(evt);
172
173
return IRQ_HANDLED;
174
}
175
176
static struct irqaction cns3xxx_timer_irq = {
177
.name = "timer",
178
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
179
.handler = cns3xxx_timer_interrupt,
180
};
181
182
/*
183
* Set up the clock source and clock events devices
184
*/
185
static void __init __cns3xxx_timer_init(unsigned int timer_irq)
186
{
187
u32 val;
188
u32 irq_mask;
189
190
/*
191
* Initialise to a known state (all timers off)
192
*/
193
194
/* disable timer1 and timer2 */
195
writel(0, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
196
/* stop free running timer3 */
197
writel(0, cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
198
199
/* timer1 */
200
writel(0x5C800, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
201
writel(0x5C800, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
202
203
writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V1_OFFSET);
204
writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V2_OFFSET);
205
206
/* mask irq, non-mask timer1 overflow */
207
irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
208
irq_mask &= ~(1 << 2);
209
irq_mask |= 0x03;
210
writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
211
212
/* down counter */
213
val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
214
val |= (1 << 9);
215
writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
216
217
/* timer2 */
218
writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V1_OFFSET);
219
writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V2_OFFSET);
220
221
/* mask irq */
222
irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
223
irq_mask |= ((1 << 3) | (1 << 4) | (1 << 5));
224
writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
225
226
/* down counter */
227
val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
228
val |= (1 << 10);
229
writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
230
231
/* Make irqs happen for the system timer */
232
setup_irq(timer_irq, &cns3xxx_timer_irq);
233
234
cns3xxx_clockevents_init(timer_irq);
235
}
236
237
static void __init cns3xxx_timer_init(void)
238
{
239
cns3xxx_tmr1 = __io(CNS3XXX_TIMER1_2_3_BASE_VIRT);
240
241
__cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
242
}
243
244
struct sys_timer cns3xxx_timer = {
245
.init = cns3xxx_timer_init,
246
};
247
248