aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-prima2
diff options
context:
space:
mode:
authorBinghua Duan <binghua.duan@csr.com>2011-07-08 05:40:12 -0400
committerBarry Song <21cnbao@gmail.com>2011-07-08 19:19:28 -0400
commit02c981c07bc95ac1e42ec6c817f0c28cf3fe993a (patch)
tree3b0f9a368d7d3b4cef3eab9128a0c3d95e8188d4 /arch/arm/mach-prima2
parentf1bb20a8365f6753e0f7b6e94981ca2b662bae13 (diff)
ARM: CSR: Adding CSR SiRFprimaII board support
SiRFprimaII is the latest generation application processor from CSR’s Multifunction SoC product family. Designed around an ARM cortex A9 core, high-speed memory bus, advanced 3D accelerator and full-HD multi-format video decoder, SiRFprimaII is able to meet the needs of complicated applications for modern multifunction devices that require heavy concurrent applications and fluid user experience. Integrated with GPS baseband, analog and PMU, this new platform is designed to provide a cost effective solution for Automotive and Consumer markets. This patch adds the basic support for this SoC and EVB board based on device tree. It is following the ZYNQ of Xilinx in some degree. Signed-off-by: Binghua Duan <Binghua.Duan@csr.com> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com> Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> Signed-off-by: Yuping Luo <Yuping.Luo@csr.com> Signed-off-by: Bin Shi <Bin.Shi@csr.com> Signed-off-by: Huayi Li <Huayi.Li@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm/mach-prima2')
-rw-r--r--arch/arm/mach-prima2/Makefile5
-rw-r--r--arch/arm/mach-prima2/Makefile.boot3
-rw-r--r--arch/arm/mach-prima2/clock.c509
-rw-r--r--arch/arm/mach-prima2/common.h20
-rw-r--r--arch/arm/mach-prima2/include/mach/clkdev.h15
-rw-r--r--arch/arm/mach-prima2/include/mach/debug-macro.S29
-rw-r--r--arch/arm/mach-prima2/include/mach/entry-macro.S29
-rw-r--r--arch/arm/mach-prima2/include/mach/hardware.h15
-rw-r--r--arch/arm/mach-prima2/include/mach/io.h16
-rw-r--r--arch/arm/mach-prima2/include/mach/irqs.h17
-rw-r--r--arch/arm/mach-prima2/include/mach/map.h16
-rw-r--r--arch/arm/mach-prima2/include/mach/memory.h21
-rw-r--r--arch/arm/mach-prima2/include/mach/system.h29
-rw-r--r--arch/arm/mach-prima2/include/mach/timex.h14
-rw-r--r--arch/arm/mach-prima2/include/mach/uart.h23
-rw-r--r--arch/arm/mach-prima2/include/mach/uncompress.h40
-rw-r--r--arch/arm/mach-prima2/include/mach/vmalloc.h16
-rw-r--r--arch/arm/mach-prima2/irq.c71
-rw-r--r--arch/arm/mach-prima2/prima2.c40
-rw-r--r--arch/arm/mach-prima2/rstc.c69
-rw-r--r--arch/arm/mach-prima2/timer.c217
21 files changed, 1214 insertions, 0 deletions
diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
new file mode 100644
index 000000000000..d44f7aedda87
--- /dev/null
+++ b/arch/arm/mach-prima2/Makefile
@@ -0,0 +1,5 @@
1obj-y := timer.o
2obj-y += irq.o
3obj-y += clock.o
4obj-y += rstc.o
5obj-y += prima2.o
diff --git a/arch/arm/mach-prima2/Makefile.boot b/arch/arm/mach-prima2/Makefile.boot
new file mode 100644
index 000000000000..d023db3ae4ff
--- /dev/null
+++ b/arch/arm/mach-prima2/Makefile.boot
@@ -0,0 +1,3 @@
1zreladdr-y := 0x00008000
2params_phys-y := 0x00000100
3initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c
new file mode 100644
index 000000000000..f9a2aaf63f71
--- /dev/null
+++ b/arch/arm/mach-prima2/clock.c
@@ -0,0 +1,509 @@
1/*
2 * Clock tree for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/module.h>
10#include <linux/bitops.h>
11#include <linux/err.h>
12#include <linux/errno.h>
13#include <linux/io.h>
14#include <linux/clkdev.h>
15#include <linux/clk.h>
16#include <linux/spinlock.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19#include <asm/mach/map.h>
20#include <mach/map.h>
21
22#define SIRFSOC_CLKC_CLK_EN0 0x0000
23#define SIRFSOC_CLKC_CLK_EN1 0x0004
24#define SIRFSOC_CLKC_REF_CFG 0x0014
25#define SIRFSOC_CLKC_CPU_CFG 0x0018
26#define SIRFSOC_CLKC_MEM_CFG 0x001c
27#define SIRFSOC_CLKC_SYS_CFG 0x0020
28#define SIRFSOC_CLKC_IO_CFG 0x0024
29#define SIRFSOC_CLKC_DSP_CFG 0x0028
30#define SIRFSOC_CLKC_GFX_CFG 0x002c
31#define SIRFSOC_CLKC_MM_CFG 0x0030
32#define SIRFSOC_LKC_LCD_CFG 0x0034
33#define SIRFSOC_CLKC_MMC_CFG 0x0038
34#define SIRFSOC_CLKC_PLL1_CFG0 0x0040
35#define SIRFSOC_CLKC_PLL2_CFG0 0x0044
36#define SIRFSOC_CLKC_PLL3_CFG0 0x0048
37#define SIRFSOC_CLKC_PLL1_CFG1 0x004c
38#define SIRFSOC_CLKC_PLL2_CFG1 0x0050
39#define SIRFSOC_CLKC_PLL3_CFG1 0x0054
40#define SIRFSOC_CLKC_PLL1_CFG2 0x0058
41#define SIRFSOC_CLKC_PLL2_CFG2 0x005c
42#define SIRFSOC_CLKC_PLL3_CFG2 0x0060
43
44#define SIRFSOC_CLOCK_VA_BASE SIRFSOC_VA(0x005000)
45
46#define KHZ 1000
47#define MHZ (KHZ * KHZ)
48
49struct clk_ops {
50 unsigned long (*get_rate)(struct clk *clk);
51 long (*round_rate)(struct clk *clk, unsigned long rate);
52 int (*set_rate)(struct clk *clk, unsigned long rate);
53 int (*enable)(struct clk *clk);
54 int (*disable)(struct clk *clk);
55 struct clk *(*get_parent)(struct clk *clk);
56 int (*set_parent)(struct clk *clk, struct clk *parent);
57};
58
59struct clk {
60 struct clk *parent; /* parent clk */
61 unsigned long rate; /* clock rate in Hz */
62 signed char usage; /* clock enable count */
63 signed char enable_bit; /* enable bit: 0 ~ 63 */
64 unsigned short regofs; /* register offset */
65 struct clk_ops *ops; /* clock operation */
66};
67
68static DEFINE_SPINLOCK(clocks_lock);
69
70static inline unsigned long clkc_readl(unsigned reg)
71{
72 return readl(SIRFSOC_CLOCK_VA_BASE + reg);
73}
74
75static inline void clkc_writel(u32 val, unsigned reg)
76{
77 writel(val, SIRFSOC_CLOCK_VA_BASE + reg);
78}
79
80/*
81 * osc_rtc - real time oscillator - 32.768KHz
82 * osc_sys - high speed oscillator - 26MHz
83 */
84
85static struct clk clk_rtc = {
86 .rate = 32768,
87};
88
89static struct clk clk_osc = {
90 .rate = 26 * MHZ,
91};
92
93/*
94 * std pll
95 */
96static unsigned long std_pll_get_rate(struct clk *clk)
97{
98 unsigned long fin = clk_get_rate(clk->parent);
99 u32 regcfg2 = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 -
100 SIRFSOC_CLKC_PLL1_CFG0;
101
102 if (clkc_readl(regcfg2) & BIT(2)) {
103 /* pll bypass mode */
104 clk->rate = fin;
105 } else {
106 /* fout = fin * nf / nr / od */
107 u32 cfg0 = clkc_readl(clk->regofs);
108 u32 nf = (cfg0 & (BIT(13) - 1)) + 1;
109 u32 nr = ((cfg0 >> 13) & (BIT(6) - 1)) + 1;
110 u32 od = ((cfg0 >> 19) & (BIT(4) - 1)) + 1;
111 WARN_ON(fin % MHZ);
112 clk->rate = fin / MHZ * nf / nr / od * MHZ;
113 }
114
115 return clk->rate;
116}
117
118static int std_pll_set_rate(struct clk *clk, unsigned long rate)
119{
120 unsigned long fin, nf, nr, od, reg;
121
122 /*
123 * fout = fin * nf / (nr * od);
124 * set od = 1, nr = fin/MHz, so fout = nf * MHz
125 */
126
127 nf = rate / MHZ;
128 if (unlikely((rate % MHZ) || nf > BIT(13) || nf < 1))
129 return -EINVAL;
130
131 fin = clk_get_rate(clk->parent);
132 BUG_ON(fin < MHZ);
133
134 nr = fin / MHZ;
135 BUG_ON((fin % MHZ) || nr > BIT(6));
136
137 od = 1;
138
139 reg = (nf - 1) | ((nr - 1) << 13) | ((od - 1) << 19);
140 clkc_writel(reg, clk->regofs);
141
142 reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG1 - SIRFSOC_CLKC_PLL1_CFG0;
143 clkc_writel((nf >> 1) - 1, reg);
144
145 reg = clk->regofs + SIRFSOC_CLKC_PLL1_CFG2 - SIRFSOC_CLKC_PLL1_CFG0;
146 while (!(clkc_readl(reg) & BIT(6)))
147 cpu_relax();
148
149 clk->rate = 0; /* set to zero will force recalculation */
150 return 0;
151}
152
153static struct clk_ops std_pll_ops = {
154 .get_rate = std_pll_get_rate,
155 .set_rate = std_pll_set_rate,
156};
157
158static struct clk clk_pll1 = {
159 .parent = &clk_osc,
160 .regofs = SIRFSOC_CLKC_PLL1_CFG0,
161 .ops = &std_pll_ops,
162};
163
164static struct clk clk_pll2 = {
165 .parent = &clk_osc,
166 .regofs = SIRFSOC_CLKC_PLL2_CFG0,
167 .ops = &std_pll_ops,
168};
169
170static struct clk clk_pll3 = {
171 .parent = &clk_osc,
172 .regofs = SIRFSOC_CLKC_PLL3_CFG0,
173 .ops = &std_pll_ops,
174};
175
176/*
177 * clock domains - cpu, mem, sys/io
178 */
179
180static struct clk clk_mem;
181
182static struct clk *dmn_get_parent(struct clk *clk)
183{
184 struct clk *clks[] = {
185 &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
186 };
187 u32 cfg = clkc_readl(clk->regofs);
188 WARN_ON((cfg & (BIT(3) - 1)) > 4);
189 return clks[cfg & (BIT(3) - 1)];
190}
191
192static int dmn_set_parent(struct clk *clk, struct clk *parent)
193{
194 const struct clk *clks[] = {
195 &clk_osc, &clk_rtc, &clk_pll1, &clk_pll2, &clk_pll3
196 };
197 u32 cfg = clkc_readl(clk->regofs);
198 int i;
199 for (i = 0; i < ARRAY_SIZE(clks); i++) {
200 if (clks[i] == parent) {
201 cfg &= ~(BIT(3) - 1);
202 clkc_writel(cfg | i, clk->regofs);
203 /* BIT(3) - switching status: 1 - busy, 0 - done */
204 while (clkc_readl(clk->regofs) & BIT(3))
205 cpu_relax();
206 return 0;
207 }
208 }
209 return -EINVAL;
210}
211
212static unsigned long dmn_get_rate(struct clk *clk)
213{
214 unsigned long fin = clk_get_rate(clk->parent);
215 u32 cfg = clkc_readl(clk->regofs);
216 if (cfg & BIT(24)) {
217 /* fcd bypass mode */
218 clk->rate = fin;
219 } else {
220 /*
221 * wait count: bit[19:16], hold count: bit[23:20]
222 */
223 u32 wait = (cfg >> 16) & (BIT(4) - 1);
224 u32 hold = (cfg >> 20) & (BIT(4) - 1);
225
226 clk->rate = fin / (wait + hold + 2);
227 }
228
229 return clk->rate;
230}
231
232static int dmn_set_rate(struct clk *clk, unsigned long rate)
233{
234 unsigned long fin;
235 unsigned ratio, wait, hold, reg;
236 unsigned bits = (clk == &clk_mem) ? 3 : 4;
237
238 fin = clk_get_rate(clk->parent);
239 ratio = fin / rate;
240
241 if (unlikely(ratio < 2 || ratio > BIT(bits + 1)))
242 return -EINVAL;
243
244 WARN_ON(fin % rate);
245
246 wait = (ratio >> 1) - 1;
247 hold = ratio - wait - 2;
248
249 reg = clkc_readl(clk->regofs);
250 reg &= ~(((BIT(bits) - 1) << 16) | ((BIT(bits) - 1) << 20));
251 reg |= (wait << 16) | (hold << 20) | BIT(25);
252 clkc_writel(reg, clk->regofs);
253
254 /* waiting FCD been effective */
255 while (clkc_readl(clk->regofs) & BIT(25))
256 cpu_relax();
257
258 clk->rate = 0; /* set to zero will force recalculation */
259
260 return 0;
261}
262
263/*
264 * cpu clock has no FCD register in Prima2, can only change pll
265 */
266static int cpu_set_rate(struct clk *clk, unsigned long rate)
267{
268 int ret1, ret2;
269 struct clk *cur_parent, *tmp_parent;
270
271 cur_parent = dmn_get_parent(clk);
272 BUG_ON(cur_parent == NULL || cur_parent->usage > 1);
273
274 /* switch to tmp pll before setting parent clock's rate */
275 tmp_parent = cur_parent == &clk_pll1 ? &clk_pll2 : &clk_pll1;
276 ret1 = dmn_set_parent(clk, tmp_parent);
277 BUG_ON(ret1);
278
279 ret2 = clk_set_rate(cur_parent, rate);
280
281 ret1 = dmn_set_parent(clk, cur_parent);
282
283 clk->rate = 0; /* set to zero will force recalculation */
284
285 return ret2 ? ret2 : ret1;
286}
287
288static struct clk_ops cpu_ops = {
289 .get_parent = dmn_get_parent,
290 .set_parent = dmn_set_parent,
291 .set_rate = cpu_set_rate,
292};
293
294static struct clk clk_cpu = {
295 .parent = &clk_pll1,
296 .regofs = SIRFSOC_CLKC_CPU_CFG,
297 .ops = &cpu_ops,
298};
299
300
301static struct clk_ops msi_ops = {
302 .set_rate = dmn_set_rate,
303 .get_rate = dmn_get_rate,
304 .set_parent = dmn_set_parent,
305 .get_parent = dmn_get_parent,
306};
307
308static struct clk clk_mem = {
309 .parent = &clk_pll2,
310 .regofs = SIRFSOC_CLKC_MEM_CFG,
311 .ops = &msi_ops,
312};
313
314static struct clk clk_sys = {
315 .parent = &clk_pll3,
316 .regofs = SIRFSOC_CLKC_SYS_CFG,
317 .ops = &msi_ops,
318};
319
320static struct clk clk_io = {
321 .parent = &clk_pll3,
322 .regofs = SIRFSOC_CLKC_IO_CFG,
323 .ops = &msi_ops,
324};
325
326/*
327 * on-chip clock sets
328 */
329static struct clk_lookup onchip_clks[] = {
330 {
331 .dev_id = "rtc",
332 .clk = &clk_rtc,
333 }, {
334 .dev_id = "osc",
335 .clk = &clk_osc,
336 }, {
337 .dev_id = "pll1",
338 .clk = &clk_pll1,
339 }, {
340 .dev_id = "pll2",
341 .clk = &clk_pll2,
342 }, {
343 .dev_id = "pll3",
344 .clk = &clk_pll3,
345 }, {
346 .dev_id = "cpu",
347 .clk = &clk_cpu,
348 }, {
349 .dev_id = "mem",
350 .clk = &clk_mem,
351 }, {
352 .dev_id = "sys",
353 .clk = &clk_sys,
354 }, {
355 .dev_id = "io",
356 .clk = &clk_io,
357 },
358};
359
360int clk_enable(struct clk *clk)
361{
362 unsigned long flags;
363
364 if (unlikely(IS_ERR_OR_NULL(clk)))
365 return -EINVAL;
366
367 if (clk->parent)
368 clk_enable(clk->parent);
369
370 spin_lock_irqsave(&clocks_lock, flags);
371 if (!clk->usage++ && clk->ops && clk->ops->enable)
372 clk->ops->enable(clk);
373 spin_unlock_irqrestore(&clocks_lock, flags);
374 return 0;
375}
376EXPORT_SYMBOL(clk_enable);
377
378void clk_disable(struct clk *clk)
379{
380 unsigned long flags;
381
382 if (unlikely(IS_ERR_OR_NULL(clk)))
383 return;
384
385 WARN_ON(!clk->usage);
386
387 spin_lock_irqsave(&clocks_lock, flags);
388 if (--clk->usage == 0 && clk->ops && clk->ops->disable)
389 clk->ops->disable(clk);
390 spin_unlock_irqrestore(&clocks_lock, flags);
391
392 if (clk->parent)
393 clk_disable(clk->parent);
394}
395EXPORT_SYMBOL(clk_disable);
396
397unsigned long clk_get_rate(struct clk *clk)
398{
399 if (unlikely(IS_ERR_OR_NULL(clk)))
400 return 0;
401
402 if (clk->rate)
403 return clk->rate;
404
405 if (clk->ops && clk->ops->get_rate)
406 return clk->ops->get_rate(clk);
407
408 return clk_get_rate(clk->parent);
409}
410EXPORT_SYMBOL(clk_get_rate);
411
412long clk_round_rate(struct clk *clk, unsigned long rate)
413{
414 if (unlikely(IS_ERR_OR_NULL(clk)))
415 return 0;
416
417 if (clk->ops && clk->ops->round_rate)
418 return clk->ops->round_rate(clk, rate);
419
420 return 0;
421}
422EXPORT_SYMBOL(clk_round_rate);
423
424int clk_set_rate(struct clk *clk, unsigned long rate)
425{
426 if (unlikely(IS_ERR_OR_NULL(clk)))
427 return -EINVAL;
428
429 if (!clk->ops || !clk->ops->set_rate)
430 return -EINVAL;
431
432 return clk->ops->set_rate(clk, rate);
433}
434EXPORT_SYMBOL(clk_set_rate);
435
436int clk_set_parent(struct clk *clk, struct clk *parent)
437{
438 int ret;
439 unsigned long flags;
440
441 if (unlikely(IS_ERR_OR_NULL(clk)))
442 return -EINVAL;
443
444 if (!clk->ops || !clk->ops->set_parent)
445 return -EINVAL;
446
447 spin_lock_irqsave(&clocks_lock, flags);
448 ret = clk->ops->set_parent(clk, parent);
449 if (!ret) {
450 parent->usage += clk->usage;
451 clk->parent->usage -= clk->usage;
452 BUG_ON(clk->parent->usage < 0);
453 clk->parent = parent;
454 }
455 spin_unlock_irqrestore(&clocks_lock, flags);
456 return ret;
457}
458EXPORT_SYMBOL(clk_set_parent);
459
460struct clk *clk_get_parent(struct clk *clk)
461{
462 unsigned long flags;
463
464 if (unlikely(IS_ERR_OR_NULL(clk)))
465 return NULL;
466
467 if (!clk->ops || !clk->ops->get_parent)
468 return clk->parent;
469
470 spin_lock_irqsave(&clocks_lock, flags);
471 clk->parent = clk->ops->get_parent(clk);
472 spin_unlock_irqrestore(&clocks_lock, flags);
473 return clk->parent;
474}
475EXPORT_SYMBOL(clk_get_parent);
476
477static void __init sirfsoc_clk_init(void)
478{
479 clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
480}
481
482static struct of_device_id clkc_ids[] = {
483 { .compatible = "sirf,prima2-clkc" },
484};
485
486void __init sirfsoc_of_clk_init(void)
487{
488 struct device_node *np;
489 struct resource res;
490 struct map_desc sirfsoc_clkc_iodesc = {
491 .virtual = SIRFSOC_CLOCK_VA_BASE,
492 .type = MT_DEVICE,
493 };
494
495 np = of_find_matching_node(NULL, clkc_ids);
496 if (!np)
497 panic("unable to find compatible clkc node in dtb\n");
498
499 if (of_address_to_resource(np, 0, &res))
500 panic("unable to find clkc range in dtb");
501 of_node_put(np);
502
503 sirfsoc_clkc_iodesc.pfn = __phys_to_pfn(res.start);
504 sirfsoc_clkc_iodesc.length = 1 + res.end - res.start;
505
506 iotable_init(&sirfsoc_clkc_iodesc, 1);
507
508 sirfsoc_clk_init();
509}
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
new file mode 100644
index 000000000000..fa4a3b5c674a
--- /dev/null
+++ b/arch/arm/mach-prima2/common.h
@@ -0,0 +1,20 @@
1/*
2 * This file contains common function prototypes to avoid externs in the c files.
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_PRIMA2_COMMON_H__
10#define __MACH_PRIMA2_COMMON_H__
11
12#include <linux/init.h>
13#include <asm/mach/time.h>
14
15extern struct sys_timer sirfsoc_timer;
16
17extern void __init sirfsoc_of_irq_init(void);
18extern void __init sirfsoc_of_clk_init(void);
19
20#endif
diff --git a/arch/arm/mach-prima2/include/mach/clkdev.h b/arch/arm/mach-prima2/include/mach/clkdev.h
new file mode 100644
index 000000000000..66932518b1b7
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/clkdev.h
@@ -0,0 +1,15 @@
1/*
2 * arch/arm/mach-prima2/include/mach/clkdev.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_CLKDEV_H
10#define __MACH_CLKDEV_H
11
12#define __clk_get(clk) ({ 1; })
13#define __clk_put(clk) do { } while (0)
14
15#endif
diff --git a/arch/arm/mach-prima2/include/mach/debug-macro.S b/arch/arm/mach-prima2/include/mach/debug-macro.S
new file mode 100644
index 000000000000..bf75106333ff
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/debug-macro.S
@@ -0,0 +1,29 @@
1/*
2 * arch/arm/mach-prima2/include/mach/debug-macro.S
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <mach/hardware.h>
10#include <mach/uart.h>
11
12 .macro addruart, rp, rv
13 ldr \rp, =SIRFSOC_UART1_PA_BASE @ physical
14 ldr \rv, =SIRFSOC_UART1_VA_BASE @ virtual
15 .endm
16
17 .macro senduart,rd,rx
18 str \rd, [\rx, #SIRFSOC_UART_TXFIFO_DATA]
19 .endm
20
21 .macro busyuart,rd,rx
22 .endm
23
24 .macro waituart,rd,rx
251001: ldr \rd, [\rx, #SIRFSOC_UART_TXFIFO_STATUS]
26 tst \rd, #SIRFSOC_UART1_TXFIFO_EMPTY
27 beq 1001b
28 .endm
29
diff --git a/arch/arm/mach-prima2/include/mach/entry-macro.S b/arch/arm/mach-prima2/include/mach/entry-macro.S
new file mode 100644
index 000000000000..1c8a50f102a7
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/entry-macro.S
@@ -0,0 +1,29 @@
1/*
2 * arch/arm/mach-prima2/include/mach/entry-macro.S
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <mach/hardware.h>
10
11#define SIRFSOC_INT_ID 0x38
12
13 .macro get_irqnr_preamble, base, tmp
14 ldr \base, =sirfsoc_intc_base
15 ldr \base, [\base]
16 .endm
17
18 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
19 ldr \irqnr, [\base, #SIRFSOC_INT_ID] @ Get the highest priority irq
20 cmp \irqnr, #0x40 @ the irq num can't be larger than 0x3f
21 movges \irqnr, #0
22 .endm
23
24 .macro disable_fiq
25 .endm
26
27 .macro arch_ret_to_user, tmp1, tmp2
28 .endm
29
diff --git a/arch/arm/mach-prima2/include/mach/hardware.h b/arch/arm/mach-prima2/include/mach/hardware.h
new file mode 100644
index 000000000000..105b96964f25
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/hardware.h
@@ -0,0 +1,15 @@
1/*
2 * arch/arm/mach-prima2/include/mach/hardware.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_HARDWARE_H__
10#define __MACH_HARDWARE_H__
11
12#include <asm/sizes.h>
13#include <mach/map.h>
14
15#endif
diff --git a/arch/arm/mach-prima2/include/mach/io.h b/arch/arm/mach-prima2/include/mach/io.h
new file mode 100644
index 000000000000..6c31e9ec279e
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/io.h
@@ -0,0 +1,16 @@
1/*
2 * arch/arm/mach-prima2/include/mach/io.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_PRIMA2_IO_H
10#define __MACH_PRIMA2_IO_H
11
12#define IO_SPACE_LIMIT ((resource_size_t)0)
13
14#define __mem_pci(a) (a)
15
16#endif
diff --git a/arch/arm/mach-prima2/include/mach/irqs.h b/arch/arm/mach-prima2/include/mach/irqs.h
new file mode 100644
index 000000000000..bb354f952fd6
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/irqs.h
@@ -0,0 +1,17 @@
1/*
2 * arch/arm/mach-prima2/include/mach/irqs.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __ASM_ARCH_IRQS_H
10#define __ASM_ARCH_IRQS_H
11
12#define SIRFSOC_INTENAL_IRQ_START 0
13#define SIRFSOC_INTENAL_IRQ_END 59
14
15#define NR_IRQS 220
16
17#endif
diff --git a/arch/arm/mach-prima2/include/mach/map.h b/arch/arm/mach-prima2/include/mach/map.h
new file mode 100644
index 000000000000..66b1ae2e553f
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/map.h
@@ -0,0 +1,16 @@
1/*
2 * memory & I/O static mapping definitions for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_PRIMA2_MAP_H__
10#define __MACH_PRIMA2_MAP_H__
11
12#include <mach/vmalloc.h>
13
14#define SIRFSOC_VA(x) (VMALLOC_END + ((x) & 0x00FFF000))
15
16#endif
diff --git a/arch/arm/mach-prima2/include/mach/memory.h b/arch/arm/mach-prima2/include/mach/memory.h
new file mode 100644
index 000000000000..368cd5a0601a
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/memory.h
@@ -0,0 +1,21 @@
1/*
2 * arch/arm/mach-prima2/include/mach/memory.h
3 *
4 * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __ASM_ARCH_MEMORY_H
10#define __ASM_ARCH_MEMORY_H
11
12#define PLAT_PHYS_OFFSET UL(0x00000000)
13
14/*
15 * Restrict DMA-able region to workaround silicon limitation.
16 * The limitation restricts buffers available for DMA to SD/MMC
17 * hardware to be below 256MB
18 */
19#define ARM_DMA_ZONE_SIZE (SZ_256M)
20
21#endif
diff --git a/arch/arm/mach-prima2/include/mach/system.h b/arch/arm/mach-prima2/include/mach/system.h
new file mode 100644
index 000000000000..0dbd257ad16d
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/system.h
@@ -0,0 +1,29 @@
1/*
2 * arch/arm/mach-prima2/include/mach/system.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_SYSTEM_H__
10#define __MACH_SYSTEM_H__
11
12#include <linux/bitops.h>
13#include <mach/hardware.h>
14
15#define SIRFSOC_SYS_RST_BIT BIT(31)
16
17extern void __iomem *sirfsoc_rstc_base;
18
19static inline void arch_idle(void)
20{
21 cpu_do_idle();
22}
23
24static inline void arch_reset(char mode, const char *cmd)
25{
26 writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base);
27}
28
29#endif
diff --git a/arch/arm/mach-prima2/include/mach/timex.h b/arch/arm/mach-prima2/include/mach/timex.h
new file mode 100644
index 000000000000..d6f98a75e562
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/timex.h
@@ -0,0 +1,14 @@
1/*
2 * arch/arm/mach-prima2/include/mach/timex.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_TIMEX_H__
10#define __MACH_TIMEX_H__
11
12#define CLOCK_TICK_RATE 1000000
13
14#endif
diff --git a/arch/arm/mach-prima2/include/mach/uart.h b/arch/arm/mach-prima2/include/mach/uart.h
new file mode 100644
index 000000000000..c98b4d5ac24a
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/uart.h
@@ -0,0 +1,23 @@
1/*
2 * arch/arm/mach-prima2/include/mach/uart.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_PRIMA2_SIRFSOC_UART_H
10#define __MACH_PRIMA2_SIRFSOC_UART_H
11
12/* UART-1: used as serial debug port */
13#define SIRFSOC_UART1_PA_BASE 0xb0060000
14#define SIRFSOC_UART1_VA_BASE SIRFSOC_VA(0x060000)
15#define SIRFSOC_UART1_SIZE SZ_4K
16
17#define SIRFSOC_UART_TXFIFO_STATUS 0x0114
18#define SIRFSOC_UART_TXFIFO_DATA 0x0118
19
20#define SIRFSOC_UART1_TXFIFO_FULL (1 << 5)
21#define SIRFSOC_UART1_TXFIFO_EMPTY (1 << 6)
22
23#endif
diff --git a/arch/arm/mach-prima2/include/mach/uncompress.h b/arch/arm/mach-prima2/include/mach/uncompress.h
new file mode 100644
index 000000000000..83125c6a30b3
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/uncompress.h
@@ -0,0 +1,40 @@
1/*
2 * arch/arm/mach-prima2/include/mach/uncompress.h
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __ASM_ARCH_UNCOMPRESS_H
10#define __ASM_ARCH_UNCOMPRESS_H
11
12#include <linux/io.h>
13#include <mach/hardware.h>
14#include <mach/uart.h>
15
16void arch_decomp_setup(void)
17{
18}
19
20#define arch_decomp_wdog()
21
22static __inline__ void putc(char c)
23{
24 /*
25 * during kernel decompression, all mappings are flat:
26 * virt_addr == phys_addr
27 */
28 while (__raw_readl(SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_STATUS)
29 & SIRFSOC_UART1_TXFIFO_FULL)
30 barrier();
31
32 __raw_writel(c, SIRFSOC_UART1_PA_BASE + SIRFSOC_UART_TXFIFO_DATA);
33}
34
35static inline void flush(void)
36{
37}
38
39#endif
40
diff --git a/arch/arm/mach-prima2/include/mach/vmalloc.h b/arch/arm/mach-prima2/include/mach/vmalloc.h
new file mode 100644
index 000000000000..c9f90fec78e3
--- /dev/null
+++ b/arch/arm/mach-prima2/include/mach/vmalloc.h
@@ -0,0 +1,16 @@
1/*
2 * arch/arm/ach-prima2/include/mach/vmalloc.h
3 *
4 * Copyright (c) 2010 – 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#ifndef __MACH_VMALLOC_H
10#define __MACH_VMALLOC_H
11
12#include <linux/const.h>
13
14#define VMALLOC_END _AC(0xFEC00000, UL)
15
16#endif
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
new file mode 100644
index 000000000000..c3404cbb6ff7
--- /dev/null
+++ b/arch/arm/mach-prima2/irq.c
@@ -0,0 +1,71 @@
1/*
2 * interrupt controller support for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/init.h>
10#include <linux/io.h>
11#include <linux/irq.h>
12#include <mach/hardware.h>
13#include <asm/mach/irq.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16
17#define SIRFSOC_INT_RISC_MASK0 0x0018
18#define SIRFSOC_INT_RISC_MASK1 0x001C
19#define SIRFSOC_INT_RISC_LEVEL0 0x0020
20#define SIRFSOC_INT_RISC_LEVEL1 0x0024
21
22void __iomem *sirfsoc_intc_base;
23
24static __init void
25sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
26{
27 struct irq_chip_generic *gc;
28 struct irq_chip_type *ct;
29
30 gc = irq_alloc_generic_chip("SIRFINTC", 1, irq_start, base, handle_level_irq);
31 ct = gc->chip_types;
32
33 ct->chip.irq_mask = irq_gc_mask_clr_bit;
34 ct->chip.irq_unmask = irq_gc_mask_set_bit;
35 ct->regs.mask = SIRFSOC_INT_RISC_MASK0;
36
37 irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, 0);
38}
39
40static __init void sirfsoc_irq_init(void)
41{
42 sirfsoc_alloc_gc(sirfsoc_intc_base, 0, 32);
43 sirfsoc_alloc_gc(sirfsoc_intc_base + 4, 32, SIRFSOC_INTENAL_IRQ_END - 32);
44
45 writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL0);
46 writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_LEVEL1);
47
48 writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK0);
49 writel_relaxed(0, sirfsoc_intc_base + SIRFSOC_INT_RISC_MASK1);
50}
51
52static struct of_device_id intc_ids[] = {
53 { .compatible = "sirf,prima2-intc" },
54};
55
56void __init sirfsoc_of_irq_init(void)
57{
58 struct device_node *np;
59
60 np = of_find_matching_node(NULL, intc_ids);
61 if (!np)
62 panic("unable to find compatible intc node in dtb\n");
63
64 sirfsoc_intc_base = of_iomap(np, 0);
65 if (!sirfsoc_intc_base)
66 panic("unable to map intc cpu registers\n");
67
68 of_node_put(np);
69
70 sirfsoc_irq_init();
71}
diff --git a/arch/arm/mach-prima2/prima2.c b/arch/arm/mach-prima2/prima2.c
new file mode 100644
index 000000000000..c26947d76e12
--- /dev/null
+++ b/arch/arm/mach-prima2/prima2.c
@@ -0,0 +1,40 @@
1/*
2 * Defines machines for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <asm/mach-types.h>
12#include <asm/mach/arch.h>
13#include <linux/of.h>
14#include <linux/of_platform.h>
15#include "common.h"
16
17static struct of_device_id sirfsoc_of_bus_ids[] __initdata = {
18 { .compatible = "simple-bus", },
19 {},
20};
21
22void __init sirfsoc_mach_init(void)
23{
24 of_platform_bus_probe(NULL, sirfsoc_of_bus_ids, NULL);
25}
26
27static const char *prima2cb_dt_match[] __initdata = {
28 "sirf,prima2-cb",
29 NULL
30};
31
32MACHINE_START(PRIMA2_EVB, "prima2cb")
33 /* Maintainer: Barry Song <baohua.song@csr.com> */
34 .boot_params = 0x00000100,
35 .init_early = sirfsoc_of_clk_init,
36 .init_irq = sirfsoc_of_irq_init,
37 .timer = &sirfsoc_timer,
38 .init_machine = sirfsoc_mach_init,
39 .dt_compat = prima2cb_dt_match,
40MACHINE_END
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
new file mode 100644
index 000000000000..d074786e83d4
--- /dev/null
+++ b/arch/arm/mach-prima2/rstc.c
@@ -0,0 +1,69 @@
1/*
2 * reset controller for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/kernel.h>
10#include <linux/mutex.h>
11#include <linux/io.h>
12#include <linux/delay.h>
13#include <linux/device.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16
17void __iomem *sirfsoc_rstc_base;
18static DEFINE_MUTEX(rstc_lock);
19
20static struct of_device_id rstc_ids[] = {
21 { .compatible = "sirf,prima2-rstc" },
22};
23
24static int __init sirfsoc_of_rstc_init(void)
25{
26 struct device_node *np;
27
28 np = of_find_matching_node(NULL, rstc_ids);
29 if (!np)
30 panic("unable to find compatible rstc node in dtb\n");
31
32 sirfsoc_rstc_base = of_iomap(np, 0);
33 if (!sirfsoc_rstc_base)
34 panic("unable to map rstc cpu registers\n");
35
36 of_node_put(np);
37
38 return 0;
39}
40early_initcall(sirfsoc_of_rstc_init);
41
42int sirfsoc_reset_device(struct device *dev)
43{
44 const unsigned int *prop = of_get_property(dev->of_node, "reset-bit", NULL);
45 unsigned int reset_bit;
46
47 if (!prop)
48 return -ENODEV;
49
50 reset_bit = be32_to_cpup(prop);
51
52 mutex_lock(&rstc_lock);
53
54 /*
55 * Writing 1 to this bit resets corresponding block. Writing 0 to this
56 * bit de-asserts reset signal of the corresponding block.
57 * datasheet doesn't require explicit delay between the set and clear
58 * of reset bit. it could be shorter if tests pass.
59 */
60 writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) | reset_bit,
61 sirfsoc_rstc_base + (reset_bit / 32) * 4);
62 msleep(10);
63 writel(readl(sirfsoc_rstc_base + (reset_bit / 32) * 4) & ~reset_bit,
64 sirfsoc_rstc_base + (reset_bit / 32) * 4);
65
66 mutex_unlock(&rstc_lock);
67
68 return 0;
69}
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
new file mode 100644
index 000000000000..44027f34a88a
--- /dev/null
+++ b/arch/arm/mach-prima2/timer.c
@@ -0,0 +1,217 @@
1/*
2 * System timer for CSR SiRFprimaII
3 *
4 * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
5 *
6 * Licensed under GPLv2 or later.
7 */
8
9#include <linux/kernel.h>
10#include <linux/interrupt.h>
11#include <linux/clockchips.h>
12#include <linux/clocksource.h>
13#include <linux/bitops.h>
14#include <linux/irq.h>
15#include <linux/clk.h>
16#include <linux/err.h>
17#include <linux/slab.h>
18#include <linux/of.h>
19#include <linux/of_address.h>
20#include <mach/map.h>
21#include <asm/mach/time.h>
22
23#define SIRFSOC_TIMER_COUNTER_LO 0x0000
24#define SIRFSOC_TIMER_COUNTER_HI 0x0004
25#define SIRFSOC_TIMER_MATCH_0 0x0008
26#define SIRFSOC_TIMER_MATCH_1 0x000C
27#define SIRFSOC_TIMER_MATCH_2 0x0010
28#define SIRFSOC_TIMER_MATCH_3 0x0014
29#define SIRFSOC_TIMER_MATCH_4 0x0018
30#define SIRFSOC_TIMER_MATCH_5 0x001C
31#define SIRFSOC_TIMER_STATUS 0x0020
32#define SIRFSOC_TIMER_INT_EN 0x0024
33#define SIRFSOC_TIMER_WATCHDOG_EN 0x0028
34#define SIRFSOC_TIMER_DIV 0x002C
35#define SIRFSOC_TIMER_LATCH 0x0030
36#define SIRFSOC_TIMER_LATCHED_LO 0x0034
37#define SIRFSOC_TIMER_LATCHED_HI 0x0038
38
39#define SIRFSOC_TIMER_WDT_INDEX 5
40
41#define SIRFSOC_TIMER_LATCH_BIT BIT(0)
42
43static void __iomem *sirfsoc_timer_base;
44static void __init sirfsoc_of_timer_map(void);
45
46/* timer0 interrupt handler */
47static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
48{
49 struct clock_event_device *ce = dev_id;
50
51 WARN_ON(!(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_STATUS) & BIT(0)));
52
53 /* clear timer0 interrupt */
54 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
55
56 ce->event_handler(ce);
57
58 return IRQ_HANDLED;
59}
60
61/* read 64-bit timer counter */
62static cycle_t sirfsoc_timer_read(struct clocksource *cs)
63{
64 u64 cycles;
65
66 /* latch the 64-bit timer counter */
67 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
68 cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_HI);
69 cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
70
71 return cycles;
72}
73
74static int sirfsoc_timer_set_next_event(unsigned long delta,
75 struct clock_event_device *ce)
76{
77 unsigned long now, next;
78
79 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
80 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
81 next = now + delta;
82 writel_relaxed(next, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0);
83 writel_relaxed(SIRFSOC_TIMER_LATCH_BIT, sirfsoc_timer_base + SIRFSOC_TIMER_LATCH);
84 now = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_LATCHED_LO);
85
86 return next - now > delta ? -ETIME : 0;
87}
88
89static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
90 struct clock_event_device *ce)
91{
92 u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
93 switch (mode) {
94 case CLOCK_EVT_MODE_PERIODIC:
95 WARN_ON(1);
96 break;
97 case CLOCK_EVT_MODE_ONESHOT:
98 writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
99 break;
100 case CLOCK_EVT_MODE_SHUTDOWN:
101 writel_relaxed(val & ~BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN);
102 break;
103 case CLOCK_EVT_MODE_UNUSED:
104 case CLOCK_EVT_MODE_RESUME:
105 break;
106 }
107}
108
109static struct clock_event_device sirfsoc_clockevent = {
110 .name = "sirfsoc_clockevent",
111 .rating = 200,
112 .features = CLOCK_EVT_FEAT_ONESHOT,
113 .set_mode = sirfsoc_timer_set_mode,
114 .set_next_event = sirfsoc_timer_set_next_event,
115};
116
117static struct clocksource sirfsoc_clocksource = {
118 .name = "sirfsoc_clocksource",
119 .rating = 200,
120 .mask = CLOCKSOURCE_MASK(64),
121 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
122 .read = sirfsoc_timer_read,
123};
124
125static struct irqaction sirfsoc_timer_irq = {
126 .name = "sirfsoc_timer0",
127 .flags = IRQF_TIMER,
128 .irq = 0,
129 .handler = sirfsoc_timer_interrupt,
130 .dev_id = &sirfsoc_clockevent,
131};
132
133/* Overwrite weak default sched_clock with more precise one */
134unsigned long long notrace sched_clock(void)
135{
136 static int is_mapped = 0;
137
138 /*
139 * sched_clock is called earlier than .init of sys_timer
140 * if we map timer memory in .init of sys_timer, system
141 * will panic due to illegal memory access
142 */
143 if(!is_mapped) {
144 sirfsoc_of_timer_map();
145 is_mapped = 1;
146 }
147
148 return sirfsoc_timer_read(NULL) * (NSEC_PER_SEC / CLOCK_TICK_RATE);
149}
150
151static void __init sirfsoc_clockevent_init(void)
152{
153 clockevents_calc_mult_shift(&sirfsoc_clockevent, CLOCK_TICK_RATE, 60);
154
155 sirfsoc_clockevent.max_delta_ns =
156 clockevent_delta2ns(-2, &sirfsoc_clockevent);
157 sirfsoc_clockevent.min_delta_ns =
158 clockevent_delta2ns(2, &sirfsoc_clockevent);
159
160 sirfsoc_clockevent.cpumask = cpumask_of(0);
161 clockevents_register_device(&sirfsoc_clockevent);
162}
163
164/* initialize the kernel jiffy timer source */
165static void __init sirfsoc_timer_init(void)
166{
167 unsigned long rate;
168
169 /* timer's input clock is io clock */
170 struct clk *clk = clk_get_sys("io", NULL);
171
172 BUG_ON(IS_ERR(clk));
173
174 rate = clk_get_rate(clk);
175
176 BUG_ON(rate < CLOCK_TICK_RATE);
177 BUG_ON(rate % CLOCK_TICK_RATE);
178
179 writel_relaxed(rate / CLOCK_TICK_RATE / 2 - 1, sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
180 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_LO);
181 writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_HI);
182 writel_relaxed(BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_STATUS);
183
184 BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, CLOCK_TICK_RATE));
185
186 BUG_ON(setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq));
187
188 sirfsoc_clockevent_init();
189}
190
191static struct of_device_id timer_ids[] = {
192 { .compatible = "sirf,prima2-tick" },
193};
194
195static void __init sirfsoc_of_timer_map(void)
196{
197 struct device_node *np;
198 const unsigned int *intspec;
199
200 np = of_find_matching_node(NULL, timer_ids);
201 if (!np)
202 panic("unable to find compatible timer node in dtb\n");
203 sirfsoc_timer_base = of_iomap(np, 0);
204 if (!sirfsoc_timer_base)
205 panic("unable to map timer cpu registers\n");
206
207 /* Get the interrupts property */
208 intspec = of_get_property(np, "interrupts", NULL);
209 BUG_ON(!intspec);
210 sirfsoc_timer_irq.irq = be32_to_cpup(intspec);
211
212 of_node_put(np);
213}
214
215struct sys_timer sirfsoc_timer = {
216 .init = sirfsoc_timer_init,
217};