diff options
Diffstat (limited to 'arch/arm/mach-tcc8k')
-rw-r--r-- | arch/arm/mach-tcc8k/Kconfig | 11 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/Makefile | 9 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/Makefile.boot | 3 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/board-tcc8000-sdk.c | 64 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/clock.c | 567 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/common.h | 15 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/devices.c | 239 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/io.c | 62 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/irq.c | 111 | ||||
-rw-r--r-- | arch/arm/mach-tcc8k/time.c | 149 |
10 files changed, 1230 insertions, 0 deletions
diff --git a/arch/arm/mach-tcc8k/Kconfig b/arch/arm/mach-tcc8k/Kconfig new file mode 100644 index 000000000000..ad86415d1577 --- /dev/null +++ b/arch/arm/mach-tcc8k/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | if ARCH_TCC8K | ||
2 | |||
3 | comment "TCC8000 systems:" | ||
4 | |||
5 | config MACH_TCC8000_SDK | ||
6 | bool "Telechips TCC8000-SDK development kit" | ||
7 | default y | ||
8 | help | ||
9 | Support for the Telechips TCC8000-SDK board. | ||
10 | |||
11 | endif | ||
diff --git a/arch/arm/mach-tcc8k/Makefile b/arch/arm/mach-tcc8k/Makefile new file mode 100644 index 000000000000..9bacf31e49ba --- /dev/null +++ b/arch/arm/mach-tcc8k/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for TCC8K boards and common files. | ||
3 | # | ||
4 | |||
5 | # Common support | ||
6 | obj-y += clock.o irq.o time.o io.o devices.o | ||
7 | |||
8 | # Board specific support | ||
9 | obj-$(CONFIG_MACH_TCC8000_SDK) += board-tcc8000-sdk.o | ||
diff --git a/arch/arm/mach-tcc8k/Makefile.boot b/arch/arm/mach-tcc8k/Makefile.boot new file mode 100644 index 000000000000..f135c9deae10 --- /dev/null +++ b/arch/arm/mach-tcc8k/Makefile.boot | |||
@@ -0,0 +1,3 @@ | |||
1 | zreladdr-y := 0x20008000 | ||
2 | params_phys-y := 0x20000100 | ||
3 | initrd_phys-y := 0x20800000 | ||
diff --git a/arch/arm/mach-tcc8k/board-tcc8000-sdk.c b/arch/arm/mach-tcc8k/board-tcc8000-sdk.c new file mode 100644 index 000000000000..4e42555b2009 --- /dev/null +++ b/arch/arm/mach-tcc8k/board-tcc8000-sdk.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/platform_device.h> | ||
12 | |||
13 | #include <asm/mach-types.h> | ||
14 | |||
15 | #include <asm/mach/arch.h> | ||
16 | #include <asm/mach/map.h> | ||
17 | #include <asm/mach/time.h> | ||
18 | |||
19 | #include <mach/clock.h> | ||
20 | |||
21 | #include "common.h" | ||
22 | |||
23 | #define XI_FREQUENCY 12000000 | ||
24 | #define XTI_FREQUENCY 32768 | ||
25 | |||
26 | #ifdef CONFIG_MTD_NAND_TCC | ||
27 | /* NAND */ | ||
28 | static struct tcc_nand_platform_data tcc8k_sdk_nand_data = { | ||
29 | .width = 1, | ||
30 | .hw_ecc = 0, | ||
31 | }; | ||
32 | #endif | ||
33 | |||
34 | static void __init tcc8k_init(void) | ||
35 | { | ||
36 | #ifdef CONFIG_MTD_NAND_TCC | ||
37 | tcc_nand_device.dev.platform_data = &tcc8k_sdk_nand_data; | ||
38 | platform_device_register(&tcc_nand_device); | ||
39 | #endif | ||
40 | } | ||
41 | |||
42 | static void __init tcc8k_init_timer(void) | ||
43 | { | ||
44 | tcc_clocks_init(XI_FREQUENCY, XTI_FREQUENCY); | ||
45 | } | ||
46 | |||
47 | static struct sys_timer tcc8k_timer = { | ||
48 | .init = tcc8k_init_timer, | ||
49 | }; | ||
50 | |||
51 | static void __init tcc8k_map_io(void) | ||
52 | { | ||
53 | tcc8k_map_common_io(); | ||
54 | } | ||
55 | |||
56 | MACHINE_START(TCC8000_SDK, "Telechips TCC8000-SDK Demo Board") | ||
57 | .phys_io = 0x90000000, | ||
58 | .io_pg_offst = ((0xf1000000) >> 18) & 0xfffc, | ||
59 | .boot_params = PHYS_OFFSET + 0x00000100, | ||
60 | .map_io = tcc8k_map_io, | ||
61 | .init_irq = tcc8k_init_irq, | ||
62 | .init_machine = tcc8k_init, | ||
63 | .timer = &tcc8k_timer, | ||
64 | MACHINE_END | ||
diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c new file mode 100644 index 000000000000..ba32a15127ab --- /dev/null +++ b/arch/arm/mach-tcc8k/clock.c | |||
@@ -0,0 +1,567 @@ | |||
1 | /* | ||
2 | * Lowlevel clock handling for Telechips TCC8xxx SoCs | ||
3 | * | ||
4 | * Copyright (C) 2010 by Hans J. Koch <hjk@linutronix.de> | ||
5 | * | ||
6 | * Licensed under the terms of the GPL v2 | ||
7 | */ | ||
8 | |||
9 | #include <linux/clk.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | |||
16 | #include <asm/clkdev.h> | ||
17 | |||
18 | #include <mach/clock.h> | ||
19 | #include <mach/irqs.h> | ||
20 | #include <mach/tcc8k-regs.h> | ||
21 | |||
22 | #include "common.h" | ||
23 | |||
24 | #define BCLKCTR0 (CKC_BASE + BCLKCTR0_OFFS) | ||
25 | #define BCLKCTR1 (CKC_BASE + BCLKCTR1_OFFS) | ||
26 | |||
27 | #define ACLKREF (CKC_BASE + ACLKREF_OFFS) | ||
28 | #define ACLKUART0 (CKC_BASE + ACLKUART0_OFFS) | ||
29 | #define ACLKUART1 (CKC_BASE + ACLKUART1_OFFS) | ||
30 | #define ACLKUART2 (CKC_BASE + ACLKUART2_OFFS) | ||
31 | #define ACLKUART3 (CKC_BASE + ACLKUART3_OFFS) | ||
32 | #define ACLKUART4 (CKC_BASE + ACLKUART4_OFFS) | ||
33 | #define ACLKI2C (CKC_BASE + ACLKI2C_OFFS) | ||
34 | #define ACLKADC (CKC_BASE + ACLKADC_OFFS) | ||
35 | #define ACLKUSBH (CKC_BASE + ACLKUSBH_OFFS) | ||
36 | #define ACLKLCD (CKC_BASE + ACLKLCD_OFFS) | ||
37 | #define ACLKSDH0 (CKC_BASE + ACLKSDH0_OFFS) | ||
38 | #define ACLKSDH1 (CKC_BASE + ACLKSDH1_OFFS) | ||
39 | #define ACLKSPI0 (CKC_BASE + ACLKSPI0_OFFS) | ||
40 | #define ACLKSPI1 (CKC_BASE + ACLKSPI1_OFFS) | ||
41 | #define ACLKSPDIF (CKC_BASE + ACLKSPDIF_OFFS) | ||
42 | #define ACLKC3DEC (CKC_BASE + ACLKC3DEC_OFFS) | ||
43 | #define ACLKCAN0 (CKC_BASE + ACLKCAN0_OFFS) | ||
44 | #define ACLKCAN1 (CKC_BASE + ACLKCAN1_OFFS) | ||
45 | #define ACLKGSB0 (CKC_BASE + ACLKGSB0_OFFS) | ||
46 | #define ACLKGSB1 (CKC_BASE + ACLKGSB1_OFFS) | ||
47 | #define ACLKGSB2 (CKC_BASE + ACLKGSB2_OFFS) | ||
48 | #define ACLKGSB3 (CKC_BASE + ACLKGSB3_OFFS) | ||
49 | #define ACLKUSBH (CKC_BASE + ACLKUSBH_OFFS) | ||
50 | #define ACLKTCT (CKC_BASE + ACLKTCT_OFFS) | ||
51 | #define ACLKTCX (CKC_BASE + ACLKTCX_OFFS) | ||
52 | #define ACLKTCZ (CKC_BASE + ACLKTCZ_OFFS) | ||
53 | |||
54 | /* Crystal frequencies */ | ||
55 | static unsigned long xi_rate, xti_rate; | ||
56 | |||
57 | static void __iomem *pll_cfg_addr(int pll) | ||
58 | { | ||
59 | switch (pll) { | ||
60 | case 0: return (CKC_BASE + PLL0CFG_OFFS); | ||
61 | case 1: return (CKC_BASE + PLL1CFG_OFFS); | ||
62 | case 2: return (CKC_BASE + PLL2CFG_OFFS); | ||
63 | default: | ||
64 | BUG(); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | static int pll_enable(int pll, int enable) | ||
69 | { | ||
70 | u32 reg; | ||
71 | void __iomem *addr = pll_cfg_addr(pll); | ||
72 | |||
73 | reg = __raw_readl(addr); | ||
74 | if (enable) | ||
75 | reg &= ~PLLxCFG_PD; | ||
76 | else | ||
77 | reg |= PLLxCFG_PD; | ||
78 | |||
79 | __raw_writel(reg, addr); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int xi_enable(int enable) | ||
84 | { | ||
85 | u32 reg; | ||
86 | |||
87 | reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS); | ||
88 | if (enable) | ||
89 | reg |= CLKCTRL_XE; | ||
90 | else | ||
91 | reg &= ~CLKCTRL_XE; | ||
92 | |||
93 | __raw_writel(reg, CKC_BASE + CLKCTRL_OFFS); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int root_clk_enable(enum root_clks src) | ||
98 | { | ||
99 | switch (src) { | ||
100 | case CLK_SRC_PLL0: return pll_enable(0, 1); | ||
101 | case CLK_SRC_PLL1: return pll_enable(1, 1); | ||
102 | case CLK_SRC_PLL2: return pll_enable(2, 1); | ||
103 | case CLK_SRC_XI: return xi_enable(1); | ||
104 | default: | ||
105 | BUG(); | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int root_clk_disable(enum root_clks root_src) | ||
111 | { | ||
112 | switch (root_src) { | ||
113 | case CLK_SRC_PLL0: return pll_enable(0, 0); | ||
114 | case CLK_SRC_PLL1: return pll_enable(1, 0); | ||
115 | case CLK_SRC_PLL2: return pll_enable(2, 0); | ||
116 | case CLK_SRC_XI: return xi_enable(0); | ||
117 | default: | ||
118 | BUG(); | ||
119 | } | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int enable_clk(struct clk *clk) | ||
124 | { | ||
125 | u32 reg; | ||
126 | |||
127 | if (clk->root_id != CLK_SRC_NOROOT) | ||
128 | return root_clk_enable(clk->root_id); | ||
129 | |||
130 | if (clk->aclkreg) { | ||
131 | reg = __raw_readl(clk->aclkreg); | ||
132 | reg |= ACLK_EN; | ||
133 | __raw_writel(reg, clk->aclkreg); | ||
134 | } | ||
135 | if (clk->bclkctr) { | ||
136 | reg = __raw_readl(clk->bclkctr); | ||
137 | reg |= 1 << clk->bclk_shift; | ||
138 | __raw_writel(reg, clk->bclkctr); | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void disable_clk(struct clk *clk) | ||
144 | { | ||
145 | u32 reg; | ||
146 | |||
147 | if (clk->root_id != CLK_SRC_NOROOT) { | ||
148 | root_clk_disable(clk->root_id); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | if (clk->bclkctr) { | ||
153 | reg = __raw_readl(clk->bclkctr); | ||
154 | reg &= ~(1 << clk->bclk_shift); | ||
155 | __raw_writel(reg, clk->bclkctr); | ||
156 | } | ||
157 | if (clk->aclkreg) { | ||
158 | reg = __raw_readl(clk->aclkreg); | ||
159 | reg &= ~ACLK_EN; | ||
160 | __raw_writel(reg, clk->aclkreg); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static unsigned long get_rate_pll(int pll) | ||
165 | { | ||
166 | u32 reg; | ||
167 | unsigned long s, m, p; | ||
168 | void __iomem *addr = pll_cfg_addr(pll); | ||
169 | |||
170 | reg = __raw_readl(addr); | ||
171 | s = (reg >> 16) & 0x07; | ||
172 | m = (reg >> 8) & 0xff; | ||
173 | p = reg & 0x3f; | ||
174 | |||
175 | return (m * xi_rate) / (p * (1 << s)); | ||
176 | } | ||
177 | |||
178 | static unsigned long get_rate_pll_div(int pll) | ||
179 | { | ||
180 | u32 reg; | ||
181 | unsigned long div = 0; | ||
182 | void __iomem *addr; | ||
183 | |||
184 | switch (pll) { | ||
185 | case 0: | ||
186 | addr = CKC_BASE + CLKDIVC0_OFFS; | ||
187 | reg = __raw_readl(addr); | ||
188 | if (reg & CLKDIVC0_P0E) | ||
189 | div = (reg >> 24) & 0x3f; | ||
190 | break; | ||
191 | case 1: | ||
192 | addr = CKC_BASE + CLKDIVC0_OFFS; | ||
193 | reg = __raw_readl(addr); | ||
194 | if (reg & CLKDIVC0_P1E) | ||
195 | div = (reg >> 16) & 0x3f; | ||
196 | break; | ||
197 | case 2: | ||
198 | addr = CKC_BASE + CLKDIVC1_OFFS; | ||
199 | reg = __raw_readl(addr); | ||
200 | if (reg & CLKDIVC1_P2E) | ||
201 | div = __raw_readl(addr) & 0x3f; | ||
202 | break; | ||
203 | } | ||
204 | return get_rate_pll(pll) / (div + 1); | ||
205 | } | ||
206 | |||
207 | static unsigned long get_rate_xi_div(void) | ||
208 | { | ||
209 | unsigned long div = 0; | ||
210 | u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS); | ||
211 | |||
212 | if (reg & CLKDIVC0_XE) | ||
213 | div = (reg >> 8) & 0x3f; | ||
214 | |||
215 | return xi_rate / (div + 1); | ||
216 | } | ||
217 | |||
218 | static unsigned long get_rate_xti_div(void) | ||
219 | { | ||
220 | unsigned long div = 0; | ||
221 | u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS); | ||
222 | |||
223 | if (reg & CLKDIVC0_XTE) | ||
224 | div = reg & 0x3f; | ||
225 | |||
226 | return xti_rate / (div + 1); | ||
227 | } | ||
228 | |||
229 | static unsigned long root_clk_get_rate(enum root_clks src) | ||
230 | { | ||
231 | switch (src) { | ||
232 | case CLK_SRC_PLL0: return get_rate_pll(0); | ||
233 | case CLK_SRC_PLL1: return get_rate_pll(1); | ||
234 | case CLK_SRC_PLL2: return get_rate_pll(2); | ||
235 | case CLK_SRC_PLL0DIV: return get_rate_pll_div(0); | ||
236 | case CLK_SRC_PLL1DIV: return get_rate_pll_div(1); | ||
237 | case CLK_SRC_PLL2DIV: return get_rate_pll_div(2); | ||
238 | case CLK_SRC_XI: return xi_rate; | ||
239 | case CLK_SRC_XTI: return xti_rate; | ||
240 | case CLK_SRC_XIDIV: return get_rate_xi_div(); | ||
241 | case CLK_SRC_XTIDIV: return get_rate_xti_div(); | ||
242 | default: return 0; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static unsigned long aclk_get_rate(struct clk *clk) | ||
247 | { | ||
248 | u32 reg; | ||
249 | unsigned long div; | ||
250 | unsigned int src; | ||
251 | |||
252 | reg = __raw_readl(clk->aclkreg); | ||
253 | div = reg & 0x0fff; | ||
254 | src = (reg >> ACLK_SEL_SHIFT) & CLK_SRC_MASK; | ||
255 | return root_clk_get_rate(src) / (div + 1); | ||
256 | } | ||
257 | |||
258 | static unsigned long aclk_best_div(struct clk *clk, unsigned long rate) | ||
259 | { | ||
260 | unsigned long div, src, freq, r1, r2; | ||
261 | |||
262 | src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; | ||
263 | src &= CLK_SRC_MASK; | ||
264 | freq = root_clk_get_rate(src); | ||
265 | div = freq / rate + 1; | ||
266 | r1 = freq / div; | ||
267 | r2 = freq / (div + 1); | ||
268 | if (r2 >= rate) | ||
269 | return div + 1; | ||
270 | if ((rate - r2) < (r1 - rate)) | ||
271 | return div + 1; | ||
272 | |||
273 | return div; | ||
274 | } | ||
275 | |||
276 | static unsigned long aclk_round_rate(struct clk *clk, unsigned long rate) | ||
277 | { | ||
278 | unsigned int src; | ||
279 | |||
280 | src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; | ||
281 | src &= CLK_SRC_MASK; | ||
282 | |||
283 | return root_clk_get_rate(src) / aclk_best_div(clk, rate); | ||
284 | } | ||
285 | |||
286 | static int aclk_set_rate(struct clk *clk, unsigned long rate) | ||
287 | { | ||
288 | u32 reg; | ||
289 | |||
290 | reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK; | ||
291 | reg |= aclk_best_div(clk, rate); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static unsigned long get_rate_sys(struct clk *clk) | ||
296 | { | ||
297 | unsigned int src; | ||
298 | |||
299 | src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK; | ||
300 | return root_clk_get_rate(src); | ||
301 | } | ||
302 | |||
303 | static unsigned long get_rate_bus(struct clk *clk) | ||
304 | { | ||
305 | unsigned int div; | ||
306 | |||
307 | div = (__raw_readl(CKC_BASE + CLKCTRL_OFFS) >> 4) & 0xff; | ||
308 | return get_rate_sys(clk) / (div + 1); | ||
309 | } | ||
310 | |||
311 | static unsigned long get_rate_cpu(struct clk *clk) | ||
312 | { | ||
313 | unsigned int reg, div, fsys, fbus; | ||
314 | |||
315 | fbus = get_rate_bus(clk); | ||
316 | reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS); | ||
317 | if (reg & (1 << 29)) | ||
318 | return fbus; | ||
319 | fsys = get_rate_sys(clk); | ||
320 | div = (reg >> 16) & 0x0f; | ||
321 | return fbus + ((fsys - fbus) * (div + 1)) / 16; | ||
322 | } | ||
323 | |||
324 | static unsigned long get_rate_root(struct clk *clk) | ||
325 | { | ||
326 | return root_clk_get_rate(clk->root_id); | ||
327 | } | ||
328 | |||
329 | static int aclk_set_parent(struct clk *clock, struct clk *parent) | ||
330 | { | ||
331 | u32 reg; | ||
332 | |||
333 | if (clock->parent == parent) | ||
334 | return 0; | ||
335 | |||
336 | clock->parent = parent; | ||
337 | |||
338 | if (!parent) | ||
339 | return 0; | ||
340 | |||
341 | if (parent->root_id == CLK_SRC_NOROOT) | ||
342 | return 0; | ||
343 | reg = __raw_readl(clock->aclkreg); | ||
344 | reg &= ~ACLK_SEL_MASK; | ||
345 | reg |= (parent->root_id << ACLK_SEL_SHIFT) & ACLK_SEL_MASK; | ||
346 | __raw_writel(reg, clock->aclkreg); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | #define DEFINE_ROOT_CLOCK(name, ri, p) \ | ||
352 | static struct clk name = { \ | ||
353 | .root_id = ri, \ | ||
354 | .get_rate = get_rate_root, \ | ||
355 | .enable = enable_clk, \ | ||
356 | .disable = disable_clk, \ | ||
357 | .parent = p, \ | ||
358 | }; | ||
359 | |||
360 | #define DEFINE_SPECIAL_CLOCK(name, gr, p) \ | ||
361 | static struct clk name = { \ | ||
362 | .root_id = CLK_SRC_NOROOT, \ | ||
363 | .get_rate = gr, \ | ||
364 | .parent = p, \ | ||
365 | }; | ||
366 | |||
367 | #define DEFINE_ACLOCK(name, bc, bs, ar) \ | ||
368 | static struct clk name = { \ | ||
369 | .root_id = CLK_SRC_NOROOT, \ | ||
370 | .bclkctr = bc, \ | ||
371 | .bclk_shift = bs, \ | ||
372 | .aclkreg = ar, \ | ||
373 | .get_rate = aclk_get_rate, \ | ||
374 | .set_rate = aclk_set_rate, \ | ||
375 | .round_rate = aclk_round_rate, \ | ||
376 | .enable = enable_clk, \ | ||
377 | .disable = disable_clk, \ | ||
378 | .set_parent = aclk_set_parent, \ | ||
379 | }; | ||
380 | |||
381 | #define DEFINE_BCLOCK(name, bc, bs, gr, p) \ | ||
382 | static struct clk name = { \ | ||
383 | .root_id = CLK_SRC_NOROOT, \ | ||
384 | .bclkctr = bc, \ | ||
385 | .bclk_shift = bs, \ | ||
386 | .get_rate = gr, \ | ||
387 | .enable = enable_clk, \ | ||
388 | .disable = disable_clk, \ | ||
389 | .parent = p, \ | ||
390 | }; | ||
391 | |||
392 | DEFINE_ROOT_CLOCK(xi, CLK_SRC_XI, NULL) | ||
393 | DEFINE_ROOT_CLOCK(xti, CLK_SRC_XTI, NULL) | ||
394 | DEFINE_ROOT_CLOCK(xidiv, CLK_SRC_XIDIV, &xi) | ||
395 | DEFINE_ROOT_CLOCK(xtidiv, CLK_SRC_XTIDIV, &xti) | ||
396 | DEFINE_ROOT_CLOCK(pll0, CLK_SRC_PLL0, &xi) | ||
397 | DEFINE_ROOT_CLOCK(pll1, CLK_SRC_PLL1, &xi) | ||
398 | DEFINE_ROOT_CLOCK(pll2, CLK_SRC_PLL2, &xi) | ||
399 | DEFINE_ROOT_CLOCK(pll0div, CLK_SRC_PLL0DIV, &pll0) | ||
400 | DEFINE_ROOT_CLOCK(pll1div, CLK_SRC_PLL1DIV, &pll1) | ||
401 | DEFINE_ROOT_CLOCK(pll2div, CLK_SRC_PLL2DIV, &pll2) | ||
402 | |||
403 | /* The following 3 clocks are special and are initialized explicitly later */ | ||
404 | DEFINE_SPECIAL_CLOCK(sys, get_rate_sys, NULL) | ||
405 | DEFINE_SPECIAL_CLOCK(bus, get_rate_bus, &sys) | ||
406 | DEFINE_SPECIAL_CLOCK(cpu, get_rate_cpu, &sys) | ||
407 | |||
408 | DEFINE_ACLOCK(tct, NULL, 0, ACLKTCT) | ||
409 | DEFINE_ACLOCK(tcx, NULL, 0, ACLKTCX) | ||
410 | DEFINE_ACLOCK(tcz, NULL, 0, ACLKTCZ) | ||
411 | DEFINE_ACLOCK(ref, NULL, 0, ACLKREF) | ||
412 | DEFINE_ACLOCK(uart0, BCLKCTR0, 5, ACLKUART0) | ||
413 | DEFINE_ACLOCK(uart1, BCLKCTR0, 23, ACLKUART1) | ||
414 | DEFINE_ACLOCK(uart2, BCLKCTR0, 6, ACLKUART2) | ||
415 | DEFINE_ACLOCK(uart3, BCLKCTR0, 8, ACLKUART3) | ||
416 | DEFINE_ACLOCK(uart4, BCLKCTR1, 6, ACLKUART4) | ||
417 | DEFINE_ACLOCK(i2c, BCLKCTR0, 7, ACLKI2C) | ||
418 | DEFINE_ACLOCK(adc, BCLKCTR0, 10, ACLKADC) | ||
419 | DEFINE_ACLOCK(usbh0, BCLKCTR0, 11, ACLKUSBH) | ||
420 | DEFINE_ACLOCK(lcd, BCLKCTR0, 13, ACLKLCD) | ||
421 | DEFINE_ACLOCK(sd0, BCLKCTR0, 17, ACLKSDH0) | ||
422 | DEFINE_ACLOCK(sd1, BCLKCTR1, 5, ACLKSDH1) | ||
423 | DEFINE_ACLOCK(spi0, BCLKCTR0, 24, ACLKSPI0) | ||
424 | DEFINE_ACLOCK(spi1, BCLKCTR0, 30, ACLKSPI1) | ||
425 | DEFINE_ACLOCK(spdif, BCLKCTR1, 2, ACLKSPDIF) | ||
426 | DEFINE_ACLOCK(c3dec, BCLKCTR1, 9, ACLKC3DEC) | ||
427 | DEFINE_ACLOCK(can0, BCLKCTR1, 10, ACLKCAN0) | ||
428 | DEFINE_ACLOCK(can1, BCLKCTR1, 11, ACLKCAN1) | ||
429 | DEFINE_ACLOCK(gsb0, BCLKCTR1, 13, ACLKGSB0) | ||
430 | DEFINE_ACLOCK(gsb1, BCLKCTR1, 14, ACLKGSB1) | ||
431 | DEFINE_ACLOCK(gsb2, BCLKCTR1, 15, ACLKGSB2) | ||
432 | DEFINE_ACLOCK(gsb3, BCLKCTR1, 16, ACLKGSB3) | ||
433 | DEFINE_ACLOCK(usbh1, BCLKCTR1, 20, ACLKUSBH) | ||
434 | |||
435 | DEFINE_BCLOCK(dai0, BCLKCTR0, 0, NULL, NULL) | ||
436 | DEFINE_BCLOCK(pic, BCLKCTR0, 1, NULL, NULL) | ||
437 | DEFINE_BCLOCK(tc, BCLKCTR0, 2, NULL, NULL) | ||
438 | DEFINE_BCLOCK(gpio, BCLKCTR0, 3, NULL, NULL) | ||
439 | DEFINE_BCLOCK(usbd, BCLKCTR0, 4, NULL, NULL) | ||
440 | DEFINE_BCLOCK(ecc, BCLKCTR0, 9, NULL, NULL) | ||
441 | DEFINE_BCLOCK(gdma0, BCLKCTR0, 12, NULL, NULL) | ||
442 | DEFINE_BCLOCK(rtc, BCLKCTR0, 15, NULL, NULL) | ||
443 | DEFINE_BCLOCK(nfc, BCLKCTR0, 16, NULL, NULL) | ||
444 | DEFINE_BCLOCK(g2d, BCLKCTR0, 18, NULL, NULL) | ||
445 | DEFINE_BCLOCK(gdma1, BCLKCTR0, 22, NULL, NULL) | ||
446 | DEFINE_BCLOCK(mscl, BCLKCTR0, 25, NULL, NULL) | ||
447 | DEFINE_BCLOCK(bdma, BCLKCTR1, 0, NULL, NULL) | ||
448 | DEFINE_BCLOCK(adma0, BCLKCTR1, 1, NULL, NULL) | ||
449 | DEFINE_BCLOCK(scfg, BCLKCTR1, 3, NULL, NULL) | ||
450 | DEFINE_BCLOCK(cid, BCLKCTR1, 4, NULL, NULL) | ||
451 | DEFINE_BCLOCK(dai1, BCLKCTR1, 7, NULL, NULL) | ||
452 | DEFINE_BCLOCK(adma1, BCLKCTR1, 8, NULL, NULL) | ||
453 | DEFINE_BCLOCK(gps, BCLKCTR1, 12, NULL, NULL) | ||
454 | DEFINE_BCLOCK(gdma2, BCLKCTR1, 17, NULL, NULL) | ||
455 | DEFINE_BCLOCK(gdma3, BCLKCTR1, 18, NULL, NULL) | ||
456 | DEFINE_BCLOCK(ddrc, BCLKCTR1, 19, NULL, NULL) | ||
457 | |||
458 | #define _REGISTER_CLOCK(d, n, c) \ | ||
459 | { \ | ||
460 | .dev_id = d, \ | ||
461 | .con_id = n, \ | ||
462 | .clk = &c, \ | ||
463 | }, | ||
464 | |||
465 | static struct clk_lookup lookups[] = { | ||
466 | _REGISTER_CLOCK(NULL, "bus", bus) | ||
467 | _REGISTER_CLOCK(NULL, "cpu", cpu) | ||
468 | _REGISTER_CLOCK(NULL, "tct", tct) | ||
469 | _REGISTER_CLOCK(NULL, "tcx", tcx) | ||
470 | _REGISTER_CLOCK(NULL, "tcz", tcz) | ||
471 | _REGISTER_CLOCK(NULL, "ref", ref) | ||
472 | _REGISTER_CLOCK(NULL, "dai0", dai0) | ||
473 | _REGISTER_CLOCK(NULL, "pic", pic) | ||
474 | _REGISTER_CLOCK(NULL, "tc", tc) | ||
475 | _REGISTER_CLOCK(NULL, "gpio", gpio) | ||
476 | _REGISTER_CLOCK(NULL, "usbd", usbd) | ||
477 | _REGISTER_CLOCK("tcc-uart.0", NULL, uart0) | ||
478 | _REGISTER_CLOCK("tcc-uart.2", NULL, uart2) | ||
479 | _REGISTER_CLOCK("tcc-i2c", NULL, i2c) | ||
480 | _REGISTER_CLOCK("tcc-uart.3", NULL, uart3) | ||
481 | _REGISTER_CLOCK(NULL, "ecc", ecc) | ||
482 | _REGISTER_CLOCK(NULL, "adc", adc) | ||
483 | _REGISTER_CLOCK("tcc-usbh.0", "usb", usbh0) | ||
484 | _REGISTER_CLOCK(NULL, "gdma0", gdma0) | ||
485 | _REGISTER_CLOCK(NULL, "lcd", lcd) | ||
486 | _REGISTER_CLOCK(NULL, "rtc", rtc) | ||
487 | _REGISTER_CLOCK(NULL, "nfc", nfc) | ||
488 | _REGISTER_CLOCK("tcc-mmc.0", NULL, sd0) | ||
489 | _REGISTER_CLOCK(NULL, "g2d", g2d) | ||
490 | _REGISTER_CLOCK(NULL, "gdma1", gdma1) | ||
491 | _REGISTER_CLOCK("tcc-uart.1", NULL, uart1) | ||
492 | _REGISTER_CLOCK("tcc-spi.0", NULL, spi0) | ||
493 | _REGISTER_CLOCK(NULL, "mscl", mscl) | ||
494 | _REGISTER_CLOCK("tcc-spi.1", NULL, spi1) | ||
495 | _REGISTER_CLOCK(NULL, "bdma", bdma) | ||
496 | _REGISTER_CLOCK(NULL, "adma0", adma0) | ||
497 | _REGISTER_CLOCK(NULL, "spdif", spdif) | ||
498 | _REGISTER_CLOCK(NULL, "scfg", scfg) | ||
499 | _REGISTER_CLOCK(NULL, "cid", cid) | ||
500 | _REGISTER_CLOCK("tcc-mmc.1", NULL, sd1) | ||
501 | _REGISTER_CLOCK("tcc-uart.4", NULL, uart4) | ||
502 | _REGISTER_CLOCK(NULL, "dai1", dai1) | ||
503 | _REGISTER_CLOCK(NULL, "adma1", adma1) | ||
504 | _REGISTER_CLOCK(NULL, "c3dec", c3dec) | ||
505 | _REGISTER_CLOCK("tcc-can.0", NULL, can0) | ||
506 | _REGISTER_CLOCK("tcc-can.1", NULL, can1) | ||
507 | _REGISTER_CLOCK(NULL, "gps", gps) | ||
508 | _REGISTER_CLOCK("tcc-gsb.0", NULL, gsb0) | ||
509 | _REGISTER_CLOCK("tcc-gsb.1", NULL, gsb1) | ||
510 | _REGISTER_CLOCK("tcc-gsb.2", NULL, gsb2) | ||
511 | _REGISTER_CLOCK("tcc-gsb.3", NULL, gsb3) | ||
512 | _REGISTER_CLOCK(NULL, "gdma2", gdma2) | ||
513 | _REGISTER_CLOCK(NULL, "gdma3", gdma3) | ||
514 | _REGISTER_CLOCK(NULL, "ddrc", ddrc) | ||
515 | _REGISTER_CLOCK("tcc-usbh.1", "usb", usbh1) | ||
516 | }; | ||
517 | |||
518 | static struct clk *root_clk_by_index(enum root_clks src) | ||
519 | { | ||
520 | switch (src) { | ||
521 | case CLK_SRC_PLL0: return &pll0; | ||
522 | case CLK_SRC_PLL1: return &pll1; | ||
523 | case CLK_SRC_PLL2: return &pll2; | ||
524 | case CLK_SRC_PLL0DIV: return &pll0div; | ||
525 | case CLK_SRC_PLL1DIV: return &pll1div; | ||
526 | case CLK_SRC_PLL2DIV: return &pll2div; | ||
527 | case CLK_SRC_XI: return ξ | ||
528 | case CLK_SRC_XTI: return &xti; | ||
529 | case CLK_SRC_XIDIV: return &xidiv; | ||
530 | case CLK_SRC_XTIDIV: return &xtidiv; | ||
531 | default: return NULL; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void find_aclk_parent(struct clk *clk) | ||
536 | { | ||
537 | unsigned int src; | ||
538 | struct clk *clock; | ||
539 | |||
540 | if (!clk->aclkreg) | ||
541 | return; | ||
542 | |||
543 | src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT; | ||
544 | src &= CLK_SRC_MASK; | ||
545 | |||
546 | clock = root_clk_by_index(src); | ||
547 | if (!clock) | ||
548 | return; | ||
549 | |||
550 | clk->parent = clock; | ||
551 | clk->set_parent = aclk_set_parent; | ||
552 | } | ||
553 | |||
554 | void __init tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq) | ||
555 | { | ||
556 | int i; | ||
557 | |||
558 | xi_rate = xi_freq; | ||
559 | xti_rate = xti_freq; | ||
560 | |||
561 | /* fixup parents and add the clock */ | ||
562 | for (i = 0; i < ARRAY_SIZE(lookups); i++) { | ||
563 | find_aclk_parent(lookups[i].clk); | ||
564 | clkdev_add(&lookups[i]); | ||
565 | } | ||
566 | tcc8k_timer_init(&tcz, (void __iomem *)TIMER_BASE, INT_TC32); | ||
567 | } | ||
diff --git a/arch/arm/mach-tcc8k/common.h b/arch/arm/mach-tcc8k/common.h new file mode 100644 index 000000000000..705690add395 --- /dev/null +++ b/arch/arm/mach-tcc8k/common.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef MACH_TCC8K_COMMON_H | ||
2 | #define MACH_TCC8K_COMMON_H | ||
3 | |||
4 | #include <linux/platform_device.h> | ||
5 | |||
6 | extern struct platform_device tcc_nand_device; | ||
7 | |||
8 | struct clk; | ||
9 | |||
10 | extern void tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq); | ||
11 | extern void tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq); | ||
12 | extern void tcc8k_init_irq(void); | ||
13 | extern void tcc8k_map_common_io(void); | ||
14 | |||
15 | #endif | ||
diff --git a/arch/arm/mach-tcc8k/devices.c b/arch/arm/mach-tcc8k/devices.c new file mode 100644 index 000000000000..6722ad7c2836 --- /dev/null +++ b/arch/arm/mach-tcc8k/devices.c | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-tcc8k/devices.c | ||
3 | * | ||
4 | * Copyright (C) Telechips, Inc. | ||
5 | * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de> | ||
6 | * | ||
7 | * Licensed under the terms of GPL v2. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/dma-mapping.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include <asm/mach/map.h> | ||
18 | |||
19 | #include <mach/tcc8k-regs.h> | ||
20 | #include <mach/irqs.h> | ||
21 | |||
22 | #include "common.h" | ||
23 | |||
24 | static u64 tcc8k_dmamask = DMA_BIT_MASK(32); | ||
25 | |||
26 | #ifdef CONFIG_MTD_NAND_TCC | ||
27 | /* NAND controller */ | ||
28 | static struct resource tcc_nand_resources[] = { | ||
29 | { | ||
30 | .start = (resource_size_t)NFC_BASE, | ||
31 | .end = (resource_size_t)NFC_BASE + 0x7f, | ||
32 | .flags = IORESOURCE_MEM, | ||
33 | }, { | ||
34 | .start = INT_NFC, | ||
35 | .end = INT_NFC, | ||
36 | .flags = IORESOURCE_IRQ, | ||
37 | }, | ||
38 | }; | ||
39 | |||
40 | struct platform_device tcc_nand_device = { | ||
41 | .name = "tcc_nand", | ||
42 | .id = 0, | ||
43 | .num_resources = ARRAY_SIZE(tcc_nand_resources), | ||
44 | .resource = tcc_nand_resources, | ||
45 | }; | ||
46 | #endif | ||
47 | |||
48 | #ifdef CONFIG_MMC_TCC8K | ||
49 | /* MMC controller */ | ||
50 | static struct resource tcc8k_mmc0_resource[] = { | ||
51 | { | ||
52 | .start = INT_SD0, | ||
53 | .end = INT_SD0, | ||
54 | .flags = IORESOURCE_IRQ, | ||
55 | }, | ||
56 | }; | ||
57 | |||
58 | static struct resource tcc8k_mmc1_resource[] = { | ||
59 | { | ||
60 | .start = INT_SD1, | ||
61 | .end = INT_SD1, | ||
62 | .flags = IORESOURCE_IRQ, | ||
63 | }, | ||
64 | }; | ||
65 | |||
66 | struct platform_device tcc8k_mmc0_device = { | ||
67 | .name = "tcc-mmc", | ||
68 | .id = 0, | ||
69 | .num_resources = ARRAY_SIZE(tcc8k_mmc0_resource), | ||
70 | .resource = tcc8k_mmc0_resource, | ||
71 | .dev = { | ||
72 | .dma_mask = &tcc8k_dmamask, | ||
73 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
74 | } | ||
75 | }; | ||
76 | |||
77 | struct platform_device tcc8k_mmc1_device = { | ||
78 | .name = "tcc-mmc", | ||
79 | .id = 1, | ||
80 | .num_resources = ARRAY_SIZE(tcc8k_mmc1_resource), | ||
81 | .resource = tcc8k_mmc1_resource, | ||
82 | .dev = { | ||
83 | .dma_mask = &tcc8k_dmamask, | ||
84 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | static inline void tcc8k_init_mmc(void) | ||
89 | { | ||
90 | u32 reg = __raw_readl(GPIOPS_BASE + GPIOPS_FS1_OFFS); | ||
91 | |||
92 | reg |= GPIOPS_FS1_SDH0_BITS | GPIOPS_FS1_SDH1_BITS; | ||
93 | __raw_writel(reg, GPIOPS_BASE + GPIOPS_FS1_OFFS); | ||
94 | |||
95 | platform_device_register(&tcc8k_mmc0_device); | ||
96 | platform_device_register(&tcc8k_mmc1_device); | ||
97 | } | ||
98 | #else | ||
99 | static inline void tcc8k_init_mmc(void) { } | ||
100 | #endif | ||
101 | |||
102 | #ifdef CONFIG_USB_OHCI_HCD | ||
103 | static int tcc8k_ohci_init(struct device *dev) | ||
104 | { | ||
105 | u32 reg; | ||
106 | |||
107 | /* Use GPIO PK19 as VBUS control output */ | ||
108 | reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS0_OFFS); | ||
109 | reg &= ~(1 << 19); | ||
110 | __raw_writel(reg, GPIOPK_BASE + GPIOPK_FS0_OFFS); | ||
111 | reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS1_OFFS); | ||
112 | reg &= ~(1 << 19); | ||
113 | __raw_writel(reg, GPIOPK_BASE + GPIOPK_FS1_OFFS); | ||
114 | |||
115 | reg = __raw_readl(GPIOPK_BASE + GPIOPK_DOE_OFFS); | ||
116 | reg |= (1 << 19); | ||
117 | __raw_writel(reg, GPIOPK_BASE + GPIOPK_DOE_OFFS); | ||
118 | /* Turn on VBUS */ | ||
119 | reg = __raw_readl(GPIOPK_BASE + GPIOPK_DAT_OFFS); | ||
120 | reg |= (1 << 19); | ||
121 | __raw_writel(reg, GPIOPK_BASE + GPIOPK_DAT_OFFS); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static struct resource tcc8k_ohci0_resources[] = { | ||
127 | [0] = { | ||
128 | .start = (resource_size_t)USBH0_BASE, | ||
129 | .end = (resource_size_t)USBH0_BASE + 0x5c, | ||
130 | .flags = IORESOURCE_MEM, | ||
131 | }, | ||
132 | [1] = { | ||
133 | .start = INT_USBH0, | ||
134 | .end = INT_USBH0, | ||
135 | .flags = IORESOURCE_IRQ, | ||
136 | } | ||
137 | }; | ||
138 | |||
139 | static struct resource tcc8k_ohci1_resources[] = { | ||
140 | [0] = { | ||
141 | .start = (resource_size_t)USBH1_BASE, | ||
142 | .end = (resource_size_t)USBH1_BASE + 0x5c, | ||
143 | .flags = IORESOURCE_MEM, | ||
144 | }, | ||
145 | [1] = { | ||
146 | .start = INT_USBH1, | ||
147 | .end = INT_USBH1, | ||
148 | .flags = IORESOURCE_IRQ, | ||
149 | } | ||
150 | }; | ||
151 | |||
152 | static struct tccohci_platform_data tcc8k_ohci0_platform_data = { | ||
153 | .controller = 0, | ||
154 | .port_mode = PMM_PERPORT_MODE, | ||
155 | .init = tcc8k_ohci_init, | ||
156 | }; | ||
157 | |||
158 | static struct tccohci_platform_data tcc8k_ohci1_platform_data = { | ||
159 | .controller = 1, | ||
160 | .port_mode = PMM_PERPORT_MODE, | ||
161 | .init = tcc8k_ohci_init, | ||
162 | }; | ||
163 | |||
164 | static struct platform_device ohci0_device = { | ||
165 | .name = "tcc-ohci", | ||
166 | .id = 0, | ||
167 | .dev = { | ||
168 | .dma_mask = &tcc8k_dmamask, | ||
169 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
170 | .platform_data = &tcc8k_ohci0_platform_data, | ||
171 | }, | ||
172 | .num_resources = ARRAY_SIZE(tcc8k_ohci0_resources), | ||
173 | .resource = tcc8k_ohci0_resources, | ||
174 | }; | ||
175 | |||
176 | static struct platform_device ohci1_device = { | ||
177 | .name = "tcc-ohci", | ||
178 | .id = 1, | ||
179 | .dev = { | ||
180 | .dma_mask = &tcc8k_dmamask, | ||
181 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
182 | .platform_data = &tcc8k_ohci1_platform_data, | ||
183 | }, | ||
184 | .num_resources = ARRAY_SIZE(tcc8k_ohci1_resources), | ||
185 | .resource = tcc8k_ohci1_resources, | ||
186 | }; | ||
187 | |||
188 | static void __init tcc8k_init_usbhost(void) | ||
189 | { | ||
190 | platform_device_register(&ohci0_device); | ||
191 | platform_device_register(&ohci1_device); | ||
192 | } | ||
193 | #else | ||
194 | static void __init tcc8k_init_usbhost(void) { } | ||
195 | #endif | ||
196 | |||
197 | /* USB device controller*/ | ||
198 | #ifdef CONFIG_USB_GADGET_TCC8K | ||
199 | static struct resource udc_resources[] = { | ||
200 | [0] = { | ||
201 | .start = INT_USBD, | ||
202 | .end = INT_USBD, | ||
203 | .flags = IORESOURCE_IRQ, | ||
204 | }, | ||
205 | [1] = { | ||
206 | .start = INT_UDMA, | ||
207 | .end = INT_UDMA, | ||
208 | .flags = IORESOURCE_IRQ, | ||
209 | }, | ||
210 | }; | ||
211 | |||
212 | static struct platform_device tcc8k_udc_device = { | ||
213 | .name = "tcc-udc", | ||
214 | .id = 0, | ||
215 | .resource = udc_resources, | ||
216 | .num_resources = ARRAY_SIZE(udc_resources), | ||
217 | .dev = { | ||
218 | .dma_mask = &tcc8k_dmamask, | ||
219 | .coherent_dma_mask = DMA_BIT_MASK(32), | ||
220 | }, | ||
221 | }; | ||
222 | |||
223 | static void __init tcc8k_init_usb_gadget(void) | ||
224 | { | ||
225 | platform_device_register(&tcc8k_udc_device); | ||
226 | } | ||
227 | #else | ||
228 | static void __init tcc8k_init_usb_gadget(void) { } | ||
229 | #endif /* CONFIG_USB_GADGET_TCC83X */ | ||
230 | |||
231 | static int __init tcc8k_init_devices(void) | ||
232 | { | ||
233 | tcc8k_init_mmc(); | ||
234 | tcc8k_init_usbhost(); | ||
235 | tcc8k_init_usb_gadget(); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | arch_initcall(tcc8k_init_devices); | ||
diff --git a/arch/arm/mach-tcc8k/io.c b/arch/arm/mach-tcc8k/io.c new file mode 100644 index 000000000000..9b39d7fa658f --- /dev/null +++ b/arch/arm/mach-tcc8k/io.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-tcc8k/io.c | ||
3 | * | ||
4 | * (C) 2009 Hans J. Koch <hjk@linutronix.de> | ||
5 | * | ||
6 | * derived from TCC83xx io.c | ||
7 | * Copyright (C) Telechips, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/kernel.h> | ||
17 | |||
18 | #include <asm/mach/map.h> | ||
19 | |||
20 | #include <mach/tcc8k-regs.h> | ||
21 | |||
22 | /* | ||
23 | * The machine specific code may provide the extra mapping besides the | ||
24 | * default mapping provided here. | ||
25 | */ | ||
26 | static struct map_desc tcc8k_io_desc[] __initdata = { | ||
27 | { | ||
28 | .virtual = (unsigned long)CS1_BASE_VIRT, | ||
29 | .pfn = __phys_to_pfn(CS1_BASE), | ||
30 | .length = CS1_SIZE, | ||
31 | .type = MT_DEVICE, | ||
32 | }, { | ||
33 | .virtual = (unsigned long)AHB_PERI_BASE_VIRT, | ||
34 | .pfn = __phys_to_pfn(AHB_PERI_BASE), | ||
35 | .length = AHB_PERI_SIZE, | ||
36 | .type = MT_DEVICE, | ||
37 | }, { | ||
38 | .virtual = (unsigned long)APB0_PERI_BASE_VIRT, | ||
39 | .pfn = __phys_to_pfn(APB0_PERI_BASE), | ||
40 | .length = APB0_PERI_SIZE, | ||
41 | .type = MT_DEVICE, | ||
42 | }, { | ||
43 | .virtual = (unsigned long)APB1_PERI_BASE_VIRT, | ||
44 | .pfn = __phys_to_pfn(APB1_PERI_BASE), | ||
45 | .length = APB1_PERI_SIZE, | ||
46 | .type = MT_DEVICE, | ||
47 | }, { | ||
48 | .virtual = (unsigned long)EXT_MEM_CTRL_BASE_VIRT, | ||
49 | .pfn = __phys_to_pfn(EXT_MEM_CTRL_BASE), | ||
50 | .length = EXT_MEM_CTRL_SIZE, | ||
51 | .type = MT_DEVICE, | ||
52 | }, | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | * Maps common IO regions for tcc8k. | ||
57 | * | ||
58 | */ | ||
59 | void __init tcc8k_map_common_io(void) | ||
60 | { | ||
61 | iotable_init(tcc8k_io_desc, ARRAY_SIZE(tcc8k_io_desc)); | ||
62 | } | ||
diff --git a/arch/arm/mach-tcc8k/irq.c b/arch/arm/mach-tcc8k/irq.c new file mode 100644 index 000000000000..34575c4963f0 --- /dev/null +++ b/arch/arm/mach-tcc8k/irq.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * Copyright (C) Telechips, Inc. | ||
3 | * Copyright (C) 2009-2010 Hans J. Koch <hjk@linutronix.de> | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL version 2. | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/io.h> | ||
11 | |||
12 | #include <asm/irq.h> | ||
13 | #include <asm/mach/irq.h> | ||
14 | |||
15 | #include <mach/tcc8k-regs.h> | ||
16 | #include <mach/irqs.h> | ||
17 | |||
18 | #include "common.h" | ||
19 | |||
20 | /* Disable IRQ */ | ||
21 | static void tcc8000_mask_ack_irq0(unsigned int irq) | ||
22 | { | ||
23 | PIC0_IEN &= ~(1 << irq); | ||
24 | PIC0_CREQ |= (1 << irq); | ||
25 | } | ||
26 | |||
27 | static void tcc8000_mask_ack_irq1(unsigned int irq) | ||
28 | { | ||
29 | PIC1_IEN &= ~(1 << (irq - 32)); | ||
30 | PIC1_CREQ |= (1 << (irq - 32)); | ||
31 | } | ||
32 | |||
33 | static void tcc8000_mask_irq0(unsigned int irq) | ||
34 | { | ||
35 | PIC0_IEN &= ~(1 << irq); | ||
36 | } | ||
37 | |||
38 | static void tcc8000_mask_irq1(unsigned int irq) | ||
39 | { | ||
40 | PIC1_IEN &= ~(1 << (irq - 32)); | ||
41 | } | ||
42 | |||
43 | static void tcc8000_ack_irq0(unsigned int irq) | ||
44 | { | ||
45 | PIC0_CREQ |= (1 << irq); | ||
46 | } | ||
47 | |||
48 | static void tcc8000_ack_irq1(unsigned int irq) | ||
49 | { | ||
50 | PIC1_CREQ |= (1 << (irq - 32)); | ||
51 | } | ||
52 | |||
53 | /* Enable IRQ */ | ||
54 | static void tcc8000_unmask_irq0(unsigned int irq) | ||
55 | { | ||
56 | PIC0_IEN |= (1 << irq); | ||
57 | PIC0_INTOEN |= (1 << irq); | ||
58 | } | ||
59 | |||
60 | static void tcc8000_unmask_irq1(unsigned int irq) | ||
61 | { | ||
62 | PIC1_IEN |= (1 << (irq - 32)); | ||
63 | PIC1_INTOEN |= (1 << (irq - 32)); | ||
64 | } | ||
65 | |||
66 | static struct irq_chip tcc8000_irq_chip0 = { | ||
67 | .name = "tcc_irq0", | ||
68 | .mask = tcc8000_mask_irq0, | ||
69 | .ack = tcc8000_ack_irq0, | ||
70 | .mask_ack = tcc8000_mask_ack_irq0, | ||
71 | .unmask = tcc8000_unmask_irq0, | ||
72 | }; | ||
73 | |||
74 | static struct irq_chip tcc8000_irq_chip1 = { | ||
75 | .name = "tcc_irq1", | ||
76 | .mask = tcc8000_mask_irq1, | ||
77 | .ack = tcc8000_ack_irq1, | ||
78 | .mask_ack = tcc8000_mask_ack_irq1, | ||
79 | .unmask = tcc8000_unmask_irq1, | ||
80 | }; | ||
81 | |||
82 | void __init tcc8k_init_irq(void) | ||
83 | { | ||
84 | int irqno; | ||
85 | |||
86 | /* Mask and clear all interrupts */ | ||
87 | PIC0_IEN = 0x00000000; | ||
88 | PIC0_CREQ = 0xffffffff; | ||
89 | PIC1_IEN = 0x00000000; | ||
90 | PIC1_CREQ = 0xffffffff; | ||
91 | |||
92 | PIC0_MEN0 = 0x00000003; | ||
93 | PIC1_MEN1 = 0x00000003; | ||
94 | PIC1_MEN = 0x00000003; | ||
95 | |||
96 | /* let all IRQs be level triggered */ | ||
97 | PIC0_TMODE = 0xffffffff; | ||
98 | PIC1_TMODE = 0xffffffff; | ||
99 | /* all IRQs are IRQs (not FIQs) */ | ||
100 | PIC0_IRQSEL = 0xffffffff; | ||
101 | PIC1_IRQSEL = 0xffffffff; | ||
102 | |||
103 | for (irqno = 0; irqno < NR_IRQS; irqno++) { | ||
104 | if (irqno < 32) | ||
105 | set_irq_chip(irqno, &tcc8000_irq_chip0); | ||
106 | else | ||
107 | set_irq_chip(irqno, &tcc8000_irq_chip1); | ||
108 | set_irq_handler(irqno, handle_level_irq); | ||
109 | set_irq_flags(irqno, IRQF_VALID); | ||
110 | } | ||
111 | } | ||
diff --git a/arch/arm/mach-tcc8k/time.c b/arch/arm/mach-tcc8k/time.c new file mode 100644 index 000000000000..78d06008841d --- /dev/null +++ b/arch/arm/mach-tcc8k/time.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * TCC8000 system timer setup | ||
3 | * | ||
4 | * (C) 2009 Hans J. Koch <hjk@linutronix.de> | ||
5 | * | ||
6 | * Licensed under the terms of the GPL version 2. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/clk.h> | ||
11 | #include <linux/clockchips.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | |||
19 | #include <asm/mach/time.h> | ||
20 | |||
21 | #include <mach/tcc8k-regs.h> | ||
22 | #include <mach/irqs.h> | ||
23 | |||
24 | #include "common.h" | ||
25 | |||
26 | static void __iomem *timer_base; | ||
27 | |||
28 | static cycle_t tcc_get_cycles(struct clocksource *cs) | ||
29 | { | ||
30 | return __raw_readl(timer_base + TC32MCNT_OFFS); | ||
31 | } | ||
32 | |||
33 | static struct clocksource clocksource_tcc = { | ||
34 | .name = "tcc_tc32", | ||
35 | .rating = 200, | ||
36 | .read = tcc_get_cycles, | ||
37 | .mask = CLOCKSOURCE_MASK(32), | ||
38 | .shift = 28, | ||
39 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
40 | }; | ||
41 | |||
42 | static int tcc_set_next_event(unsigned long evt, | ||
43 | struct clock_event_device *unused) | ||
44 | { | ||
45 | unsigned long reg = __raw_readl(timer_base + TC32MCNT_OFFS); | ||
46 | |||
47 | __raw_writel(reg + evt, timer_base + TC32CMP0_OFFS); | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void tcc_set_mode(enum clock_event_mode mode, | ||
52 | struct clock_event_device *evt) | ||
53 | { | ||
54 | unsigned long tc32irq; | ||
55 | |||
56 | switch (mode) { | ||
57 | case CLOCK_EVT_MODE_ONESHOT: | ||
58 | tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS); | ||
59 | tc32irq |= TC32IRQ_IRQEN0; | ||
60 | __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS); | ||
61 | break; | ||
62 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
63 | case CLOCK_EVT_MODE_UNUSED: | ||
64 | tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS); | ||
65 | tc32irq &= ~TC32IRQ_IRQEN0; | ||
66 | __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS); | ||
67 | break; | ||
68 | case CLOCK_EVT_MODE_PERIODIC: | ||
69 | case CLOCK_EVT_MODE_RESUME: | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static irqreturn_t tcc8k_timer_interrupt(int irq, void *dev_id) | ||
75 | { | ||
76 | struct clock_event_device *evt = dev_id; | ||
77 | |||
78 | /* Acknowledge TC32 interrupt by reading TC32IRQ */ | ||
79 | __raw_readl(timer_base + TC32IRQ_OFFS); | ||
80 | |||
81 | evt->event_handler(evt); | ||
82 | |||
83 | return IRQ_HANDLED; | ||
84 | } | ||
85 | |||
86 | static struct clock_event_device clockevent_tcc = { | ||
87 | .name = "tcc_timer1", | ||
88 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
89 | .shift = 32, | ||
90 | .set_mode = tcc_set_mode, | ||
91 | .set_next_event = tcc_set_next_event, | ||
92 | .rating = 200, | ||
93 | }; | ||
94 | |||
95 | static struct irqaction tcc8k_timer_irq = { | ||
96 | .name = "TC32_timer", | ||
97 | .flags = IRQF_DISABLED | IRQF_TIMER, | ||
98 | .handler = tcc8k_timer_interrupt, | ||
99 | .dev_id = &clockevent_tcc, | ||
100 | }; | ||
101 | |||
102 | static int __init tcc_clockevent_init(struct clk *clock) | ||
103 | { | ||
104 | unsigned int c = clk_get_rate(clock); | ||
105 | |||
106 | clocksource_tcc.mult = clocksource_hz2mult(c, | ||
107 | clocksource_tcc.shift); | ||
108 | clocksource_register(&clocksource_tcc); | ||
109 | |||
110 | clockevent_tcc.mult = div_sc(c, NSEC_PER_SEC, | ||
111 | clockevent_tcc.shift); | ||
112 | clockevent_tcc.max_delta_ns = | ||
113 | clockevent_delta2ns(0xfffffffe, &clockevent_tcc); | ||
114 | clockevent_tcc.min_delta_ns = | ||
115 | clockevent_delta2ns(0xff, &clockevent_tcc); | ||
116 | |||
117 | clockevent_tcc.cpumask = cpumask_of(0); | ||
118 | |||
119 | clockevents_register_device(&clockevent_tcc); | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | void __init tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq) | ||
125 | { | ||
126 | u32 reg; | ||
127 | |||
128 | timer_base = base; | ||
129 | tcc8k_timer_irq.irq = irq; | ||
130 | |||
131 | /* Enable clocks */ | ||
132 | clk_enable(clock); | ||
133 | |||
134 | /* Initialize 32-bit timer */ | ||
135 | reg = __raw_readl(timer_base + TC32EN_OFFS); | ||
136 | reg &= ~TC32EN_ENABLE; /* Disable timer */ | ||
137 | __raw_writel(reg, timer_base + TC32EN_OFFS); | ||
138 | /* Free running timer, counting from 0 to 0xffffffff */ | ||
139 | __raw_writel(0, timer_base + TC32EN_OFFS); | ||
140 | __raw_writel(0, timer_base + TC32LDV_OFFS); | ||
141 | reg = __raw_readl(timer_base + TC32IRQ_OFFS); | ||
142 | reg |= TC32IRQ_IRQEN0; /* irq at match with CMP0 */ | ||
143 | __raw_writel(reg, timer_base + TC32IRQ_OFFS); | ||
144 | |||
145 | __raw_writel(TC32EN_ENABLE, timer_base + TC32EN_OFFS); | ||
146 | |||
147 | tcc_clockevent_init(clock); | ||
148 | setup_irq(irq, &tcc8k_timer_irq); | ||
149 | } | ||