diff options
Diffstat (limited to 'arch/arm/mach-s3c2443')
-rw-r--r-- | arch/arm/mach-s3c2443/Kconfig | 29 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/Makefile | 20 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/clock.c | 1007 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/dma.c | 180 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/irq.c | 290 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/mach-smdk2443.c | 137 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/s3c2443.c | 97 |
7 files changed, 1760 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig new file mode 100644 index 000000000000..c649bb2e7ce8 --- /dev/null +++ b/arch/arm/mach-s3c2443/Kconfig | |||
@@ -0,0 +1,29 @@ | |||
1 | # arch/arm/mach-s3c2443/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | config CPU_S3C2443 | ||
8 | bool | ||
9 | depends on ARCH_S3C2410 | ||
10 | select S3C2443_DMA if S3C2410_DMA | ||
11 | help | ||
12 | Support for the S3C2443 SoC from the S3C24XX line | ||
13 | |||
14 | config S3C2443_DMA | ||
15 | bool | ||
16 | depends on CPU_S3C2443 | ||
17 | help | ||
18 | Internal config node for S3C2443 DMA support | ||
19 | |||
20 | menu "S3C2443 Machines" | ||
21 | |||
22 | config MACH_SMDK2443 | ||
23 | bool "SMDK2443" | ||
24 | select CPU_S3C2443 | ||
25 | select MACH_SMDK | ||
26 | help | ||
27 | Say Y here if you are using an SMDK2443 | ||
28 | |||
29 | endmenu | ||
diff --git a/arch/arm/mach-s3c2443/Makefile b/arch/arm/mach-s3c2443/Makefile new file mode 100644 index 000000000000..d1843c9eb8bd --- /dev/null +++ b/arch/arm/mach-s3c2443/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # arch/arm/mach-s3c2443/Makefile | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | obj-y := | ||
8 | obj-m := | ||
9 | obj-n := | ||
10 | obj- := | ||
11 | |||
12 | obj-$(CONFIG_CPU_S3C2443) += s3c2443.o | ||
13 | obj-$(CONFIG_CPU_S3C2443) += irq.o | ||
14 | obj-$(CONFIG_CPU_S3C2443) += clock.o | ||
15 | |||
16 | obj-$(CONFIG_S3C2443_DMA) += dma.o | ||
17 | |||
18 | # Machine support | ||
19 | |||
20 | obj-$(CONFIG_MACH_SMDK2443) += mach-smdk2443.o | ||
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c new file mode 100644 index 000000000000..dd2272fb1131 --- /dev/null +++ b/arch/arm/mach-s3c2443/clock.c | |||
@@ -0,0 +1,1007 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/clock.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2443 Clock control support | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/sysdev.h> | ||
30 | #include <linux/clk.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/serial_core.h> | ||
34 | |||
35 | #include <asm/mach/map.h> | ||
36 | |||
37 | #include <asm/hardware.h> | ||
38 | #include <asm/io.h> | ||
39 | |||
40 | #include <asm/arch/regs-s3c2443-clock.h> | ||
41 | |||
42 | #include <asm/plat-s3c24xx/s3c2443.h> | ||
43 | #include <asm/plat-s3c24xx/clock.h> | ||
44 | #include <asm/plat-s3c24xx/cpu.h> | ||
45 | |||
46 | /* We currently have to assume that the system is running | ||
47 | * from the XTPll input, and that all ***REFCLKs are being | ||
48 | * fed from it, as we cannot read the state of OM[4] from | ||
49 | * software. | ||
50 | * | ||
51 | * It would be possible for each board initialisation to | ||
52 | * set the correct muxing at initialisation | ||
53 | */ | ||
54 | |||
55 | static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) | ||
56 | { | ||
57 | unsigned int clocks = clk->ctrlbit; | ||
58 | unsigned long clkcon; | ||
59 | |||
60 | clkcon = __raw_readl(S3C2443_HCLKCON); | ||
61 | |||
62 | if (enable) | ||
63 | clkcon |= clocks; | ||
64 | else | ||
65 | clkcon &= ~clocks; | ||
66 | |||
67 | __raw_writel(clkcon, S3C2443_HCLKCON); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) | ||
73 | { | ||
74 | unsigned int clocks = clk->ctrlbit; | ||
75 | unsigned long clkcon; | ||
76 | |||
77 | clkcon = __raw_readl(S3C2443_PCLKCON); | ||
78 | |||
79 | if (enable) | ||
80 | clkcon |= clocks; | ||
81 | else | ||
82 | clkcon &= ~clocks; | ||
83 | |||
84 | __raw_writel(clkcon, S3C2443_HCLKCON); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) | ||
90 | { | ||
91 | unsigned int clocks = clk->ctrlbit; | ||
92 | unsigned long clkcon; | ||
93 | |||
94 | clkcon = __raw_readl(S3C2443_SCLKCON); | ||
95 | |||
96 | if (enable) | ||
97 | clkcon |= clocks; | ||
98 | else | ||
99 | clkcon &= ~clocks; | ||
100 | |||
101 | __raw_writel(clkcon, S3C2443_SCLKCON); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, | ||
107 | unsigned long rate, | ||
108 | unsigned int max) | ||
109 | { | ||
110 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
111 | int div; | ||
112 | |||
113 | if (rate > parent_rate) | ||
114 | return parent_rate; | ||
115 | |||
116 | /* note, we remove the +/- 1 calculations as they cancel out */ | ||
117 | |||
118 | div = (rate / parent_rate); | ||
119 | |||
120 | if (div < 1) | ||
121 | div = 1; | ||
122 | else if (div > max) | ||
123 | div = max; | ||
124 | |||
125 | return parent_rate / div; | ||
126 | } | ||
127 | |||
128 | static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk, | ||
129 | unsigned long rate) | ||
130 | { | ||
131 | return s3c2443_roundrate_clksrc(clk, rate, 4); | ||
132 | } | ||
133 | |||
134 | static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, | ||
135 | unsigned long rate) | ||
136 | { | ||
137 | return s3c2443_roundrate_clksrc(clk, rate, 16); | ||
138 | } | ||
139 | |||
140 | static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, | ||
141 | unsigned long rate) | ||
142 | { | ||
143 | return s3c2443_roundrate_clksrc(clk, rate, 256); | ||
144 | } | ||
145 | |||
146 | /* clock selections */ | ||
147 | |||
148 | /* CPU EXTCLK input */ | ||
149 | static struct clk clk_ext = { | ||
150 | .name = "ext", | ||
151 | .id = -1, | ||
152 | }; | ||
153 | |||
154 | static struct clk clk_mpllref = { | ||
155 | .name = "mpllref", | ||
156 | .parent = &clk_xtal, | ||
157 | .id = -1, | ||
158 | }; | ||
159 | |||
160 | #if 0 | ||
161 | static struct clk clk_mpll = { | ||
162 | .name = "mpll", | ||
163 | .parent = &clk_mpllref, | ||
164 | .id = -1, | ||
165 | }; | ||
166 | #endif | ||
167 | |||
168 | static struct clk clk_epllref; | ||
169 | |||
170 | static struct clk clk_epll = { | ||
171 | .name = "epll", | ||
172 | .parent = &clk_epllref, | ||
173 | .id = -1, | ||
174 | }; | ||
175 | |||
176 | static struct clk clk_i2s_ext = { | ||
177 | .name = "i2s-ext", | ||
178 | .id = -1, | ||
179 | }; | ||
180 | |||
181 | static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) | ||
182 | { | ||
183 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
184 | |||
185 | clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; | ||
186 | |||
187 | if (parent == &clk_xtal) | ||
188 | clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL; | ||
189 | else if (parent == &clk_ext) | ||
190 | clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK; | ||
191 | else if (parent != &clk_mpllref) | ||
192 | return -EINVAL; | ||
193 | |||
194 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
195 | clk->parent = parent; | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static struct clk clk_epllref = { | ||
201 | .name = "epllref", | ||
202 | .id = -1, | ||
203 | .set_parent = s3c2443_setparent_epllref, | ||
204 | }; | ||
205 | |||
206 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) | ||
207 | { | ||
208 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
209 | unsigned long div = __raw_readl(S3C2443_CLKDIV0); | ||
210 | |||
211 | div &= S3C2443_CLKDIV0_EXTDIV_MASK; | ||
212 | div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ | ||
213 | |||
214 | return parent_rate / (div + 1); | ||
215 | } | ||
216 | |||
217 | static struct clk clk_mdivclk = { | ||
218 | .name = "mdivclk", | ||
219 | .parent = &clk_mpllref, | ||
220 | .id = -1, | ||
221 | .get_rate = s3c2443_getrate_mdivclk, | ||
222 | }; | ||
223 | |||
224 | |||
225 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) | ||
226 | { | ||
227 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
228 | |||
229 | clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | | ||
230 | S3C2443_CLKSRC_EXTCLK_DIV); | ||
231 | |||
232 | if (parent == &clk_mpll) | ||
233 | clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL; | ||
234 | else if (parent == &clk_mdivclk) | ||
235 | clksrc |= S3C2443_CLKSRC_EXTCLK_DIV; | ||
236 | else if (parent != &clk_mpllref) | ||
237 | return -EINVAL; | ||
238 | |||
239 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
240 | clk->parent = parent; | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static struct clk clk_msysclk = { | ||
246 | .name = "msysclk", | ||
247 | .parent = &clk_xtal, | ||
248 | .id = -1, | ||
249 | .set_parent = s3c2443_setparent_msysclk, | ||
250 | }; | ||
251 | |||
252 | |||
253 | /* esysclk | ||
254 | * | ||
255 | * this is sourced from either the EPLL or the EPLLref clock | ||
256 | */ | ||
257 | |||
258 | static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) | ||
259 | { | ||
260 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
261 | |||
262 | if (parent == &clk_epll) | ||
263 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; | ||
264 | else if (parent == &clk_epllref) | ||
265 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; | ||
266 | else | ||
267 | return -EINVAL; | ||
268 | |||
269 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
270 | clk->parent = parent; | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static struct clk clk_esysclk = { | ||
276 | .name = "esysclk", | ||
277 | .parent = &clk_epll, | ||
278 | .id = -1, | ||
279 | .set_parent = s3c2443_setparent_esysclk, | ||
280 | }; | ||
281 | |||
282 | /* uartclk | ||
283 | * | ||
284 | * UART baud-rate clock sourced from esysclk via a divisor | ||
285 | */ | ||
286 | |||
287 | static unsigned long s3c2443_getrate_uart(struct clk *clk) | ||
288 | { | ||
289 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
290 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
291 | |||
292 | div &= S3C2443_CLKDIV1_UARTDIV_MASK; | ||
293 | div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
294 | |||
295 | return parent_rate / (div + 1); | ||
296 | } | ||
297 | |||
298 | |||
299 | static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) | ||
300 | { | ||
301 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
302 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
303 | |||
304 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
305 | rate = parent_rate / rate; | ||
306 | |||
307 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
308 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
309 | |||
310 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static struct clk clk_uart = { | ||
315 | .name = "uartclk", | ||
316 | .id = -1, | ||
317 | .parent = &clk_esysclk, | ||
318 | .get_rate = s3c2443_getrate_uart, | ||
319 | .set_rate = s3c2443_setrate_uart, | ||
320 | .round_rate = s3c2443_roundrate_clksrc16, | ||
321 | }; | ||
322 | |||
323 | /* hsspi | ||
324 | * | ||
325 | * high-speed spi clock, sourced from esysclk | ||
326 | */ | ||
327 | |||
328 | static unsigned long s3c2443_getrate_hsspi(struct clk *clk) | ||
329 | { | ||
330 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
331 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
332 | |||
333 | div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; | ||
334 | div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | ||
335 | |||
336 | return parent_rate / (div + 1); | ||
337 | } | ||
338 | |||
339 | |||
340 | static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate) | ||
341 | { | ||
342 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
343 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
344 | |||
345 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
346 | rate = parent_rate / rate; | ||
347 | |||
348 | clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK; | ||
349 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | ||
350 | |||
351 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static struct clk clk_hsspi = { | ||
356 | .name = "hsspi", | ||
357 | .id = -1, | ||
358 | .parent = &clk_esysclk, | ||
359 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, | ||
360 | .enable = s3c2443_clkcon_enable_s, | ||
361 | .get_rate = s3c2443_getrate_hsspi, | ||
362 | .set_rate = s3c2443_setrate_hsspi, | ||
363 | .round_rate = s3c2443_roundrate_clksrc4, | ||
364 | }; | ||
365 | |||
366 | /* usbhost | ||
367 | * | ||
368 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | ||
369 | */ | ||
370 | |||
371 | static unsigned long s3c2443_getrate_usbhost(struct clk *clk) | ||
372 | { | ||
373 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
374 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
375 | |||
376 | div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; | ||
377 | div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | ||
378 | |||
379 | return parent_rate / (div + 1); | ||
380 | } | ||
381 | |||
382 | static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) | ||
383 | { | ||
384 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
385 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
386 | |||
387 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
388 | rate = parent_rate / rate; | ||
389 | |||
390 | clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK; | ||
391 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | ||
392 | |||
393 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | struct clk clk_usb_bus_host = { | ||
398 | .name = "usb-bus-host-parent", | ||
399 | .id = -1, | ||
400 | .parent = &clk_esysclk, | ||
401 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | ||
402 | .enable = s3c2443_clkcon_enable_s, | ||
403 | .get_rate = s3c2443_getrate_usbhost, | ||
404 | .set_rate = s3c2443_setrate_usbhost, | ||
405 | .round_rate = s3c2443_roundrate_clksrc4, | ||
406 | }; | ||
407 | |||
408 | /* clk_hsmcc_div | ||
409 | * | ||
410 | * this clock is sourced from epll, and is fed through a divider, | ||
411 | * to a mux controlled by sclkcon where either it or a extclk can | ||
412 | * be fed to the hsmmc block | ||
413 | */ | ||
414 | |||
415 | static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) | ||
416 | { | ||
417 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
418 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
419 | |||
420 | div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
421 | div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
422 | |||
423 | return parent_rate / (div + 1); | ||
424 | } | ||
425 | |||
426 | static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate) | ||
427 | { | ||
428 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
429 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
430 | |||
431 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
432 | rate = parent_rate / rate; | ||
433 | |||
434 | clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
435 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
436 | |||
437 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static struct clk clk_hsmmc_div = { | ||
442 | .name = "hsmmc-div", | ||
443 | .id = -1, | ||
444 | .parent = &clk_esysclk, | ||
445 | .get_rate = s3c2443_getrate_hsmmc_div, | ||
446 | .set_rate = s3c2443_setrate_hsmmc_div, | ||
447 | .round_rate = s3c2443_roundrate_clksrc4, | ||
448 | }; | ||
449 | |||
450 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) | ||
451 | { | ||
452 | unsigned long clksrc = __raw_readl(S3C2443_SCLKCON); | ||
453 | |||
454 | clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT | | ||
455 | S3C2443_SCLKCON_HSMMCCLK_EPLL); | ||
456 | |||
457 | if (parent == &clk_epll) | ||
458 | clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL; | ||
459 | else if (parent == &clk_ext) | ||
460 | clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT; | ||
461 | else | ||
462 | return -EINVAL; | ||
463 | |||
464 | if (clk->usage > 0) { | ||
465 | __raw_writel(clksrc, S3C2443_SCLKCON); | ||
466 | } | ||
467 | |||
468 | clk->parent = parent; | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static int s3c2443_enable_hsmmc(struct clk *clk, int enable) | ||
473 | { | ||
474 | return s3c2443_setparent_hsmmc(clk, clk->parent); | ||
475 | } | ||
476 | |||
477 | static struct clk clk_hsmmc = { | ||
478 | .name = "hsmmc-if", | ||
479 | .id = -1, | ||
480 | .parent = &clk_hsmmc_div, | ||
481 | .enable = s3c2443_enable_hsmmc, | ||
482 | .set_parent = s3c2443_setparent_hsmmc, | ||
483 | }; | ||
484 | |||
485 | /* i2s_eplldiv | ||
486 | * | ||
487 | * this clock is the output from the i2s divisor of esysclk | ||
488 | */ | ||
489 | |||
490 | static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) | ||
491 | { | ||
492 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
493 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
494 | |||
495 | div &= S3C2443_CLKDIV1_I2SDIV_MASK; | ||
496 | div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
497 | |||
498 | return parent_rate / (div + 1); | ||
499 | } | ||
500 | |||
501 | static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate) | ||
502 | { | ||
503 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
504 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
505 | |||
506 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
507 | rate = parent_rate / rate; | ||
508 | |||
509 | clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK; | ||
510 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
511 | |||
512 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static struct clk clk_i2s_eplldiv = { | ||
517 | .name = "i2s-eplldiv", | ||
518 | .id = -1, | ||
519 | .parent = &clk_esysclk, | ||
520 | .get_rate = s3c2443_getrate_i2s_eplldiv, | ||
521 | .set_rate = s3c2443_setrate_i2s_eplldiv, | ||
522 | .round_rate = s3c2443_roundrate_clksrc16, | ||
523 | }; | ||
524 | |||
525 | /* i2s-ref | ||
526 | * | ||
527 | * i2s bus reference clock, selectable from external, esysclk or epllref | ||
528 | */ | ||
529 | |||
530 | static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) | ||
531 | { | ||
532 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
533 | |||
534 | clksrc &= ~S3C2443_CLKSRC_I2S_MASK; | ||
535 | |||
536 | if (parent == &clk_epllref) | ||
537 | clksrc |= S3C2443_CLKSRC_I2S_EPLLREF; | ||
538 | else if (parent == &clk_i2s_ext) | ||
539 | clksrc |= S3C2443_CLKSRC_I2S_EXT; | ||
540 | else if (parent != &clk_i2s_eplldiv) | ||
541 | return -EINVAL; | ||
542 | |||
543 | clk->parent = parent; | ||
544 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static struct clk clk_i2s = { | ||
550 | .name = "i2s-if", | ||
551 | .id = -1, | ||
552 | .parent = &clk_i2s_eplldiv, | ||
553 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | ||
554 | .enable = s3c2443_clkcon_enable_s, | ||
555 | .set_parent = s3c2443_setparent_i2s, | ||
556 | }; | ||
557 | |||
558 | /* cam-if | ||
559 | * | ||
560 | * camera interface bus-clock, divided down from esysclk | ||
561 | */ | ||
562 | |||
563 | static unsigned long s3c2443_getrate_cam(struct clk *clk) | ||
564 | { | ||
565 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
566 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
567 | |||
568 | div &= S3C2443_CLKDIV1_CAMDIV_MASK; | ||
569 | div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; | ||
570 | |||
571 | return parent_rate / (div + 1); | ||
572 | } | ||
573 | |||
574 | static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate) | ||
575 | { | ||
576 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
577 | unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1); | ||
578 | |||
579 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
580 | rate = parent_rate / rate; | ||
581 | |||
582 | clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK; | ||
583 | clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT; | ||
584 | |||
585 | __raw_writel(clkdiv1, S3C2443_CLKDIV1); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static struct clk clk_cam = { | ||
590 | .name = "camif-upll", /* same as 2440 name */ | ||
591 | .id = -1, | ||
592 | .parent = &clk_esysclk, | ||
593 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | ||
594 | .enable = s3c2443_clkcon_enable_s, | ||
595 | .get_rate = s3c2443_getrate_cam, | ||
596 | .set_rate = s3c2443_setrate_cam, | ||
597 | .round_rate = s3c2443_roundrate_clksrc16, | ||
598 | }; | ||
599 | |||
600 | /* display-if | ||
601 | * | ||
602 | * display interface clock, divided from esysclk | ||
603 | */ | ||
604 | |||
605 | static unsigned long s3c2443_getrate_display(struct clk *clk) | ||
606 | { | ||
607 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
608 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | ||
609 | |||
610 | div &= S3C2443_CLKDIV1_DISPDIV_MASK; | ||
611 | div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; | ||
612 | |||
613 | return parent_rate / (div + 1); | ||
614 | } | ||
615 | |||
616 | static int s3c2443_setrate_display(struct clk *clk, unsigned long rate) | ||
617 | { | ||
618 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
619 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
620 | |||
621 | rate = s3c2443_roundrate_clksrc256(clk, rate); | ||
622 | rate = parent_rate / rate; | ||
623 | |||
624 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
625 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
626 | |||
627 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static struct clk clk_display = { | ||
632 | .name = "display-if", | ||
633 | .id = -1, | ||
634 | .parent = &clk_esysclk, | ||
635 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | ||
636 | .enable = s3c2443_clkcon_enable_s, | ||
637 | .get_rate = s3c2443_getrate_display, | ||
638 | .set_rate = s3c2443_setrate_display, | ||
639 | .round_rate = s3c2443_roundrate_clksrc256, | ||
640 | }; | ||
641 | |||
642 | /* standard clock definitions */ | ||
643 | |||
644 | static struct clk init_clocks_disable[] = { | ||
645 | { | ||
646 | .name = "nand", | ||
647 | .id = -1, | ||
648 | .parent = &clk_h, | ||
649 | }, { | ||
650 | .name = "sdi", | ||
651 | .id = -1, | ||
652 | .parent = &clk_p, | ||
653 | .enable = s3c2443_clkcon_enable_p, | ||
654 | .ctrlbit = S3C2443_PCLKCON_SDI, | ||
655 | }, { | ||
656 | .name = "adc", | ||
657 | .id = -1, | ||
658 | .parent = &clk_p, | ||
659 | .enable = s3c2443_clkcon_enable_p, | ||
660 | .ctrlbit = S3C2443_PCLKCON_ADC, | ||
661 | }, { | ||
662 | .name = "i2c", | ||
663 | .id = -1, | ||
664 | .parent = &clk_p, | ||
665 | .enable = s3c2443_clkcon_enable_p, | ||
666 | .ctrlbit = S3C2443_PCLKCON_IIC, | ||
667 | }, { | ||
668 | .name = "iis", | ||
669 | .id = -1, | ||
670 | .parent = &clk_p, | ||
671 | .enable = s3c2443_clkcon_enable_p, | ||
672 | .ctrlbit = S3C2443_PCLKCON_IIS, | ||
673 | }, { | ||
674 | .name = "spi", | ||
675 | .id = 0, | ||
676 | .parent = &clk_p, | ||
677 | .enable = s3c2443_clkcon_enable_p, | ||
678 | .ctrlbit = S3C2443_PCLKCON_SPI0, | ||
679 | }, { | ||
680 | .name = "spi", | ||
681 | .id = 1, | ||
682 | .parent = &clk_p, | ||
683 | .enable = s3c2443_clkcon_enable_p, | ||
684 | .ctrlbit = S3C2443_PCLKCON_SPI1, | ||
685 | } | ||
686 | }; | ||
687 | |||
688 | static struct clk init_clocks[] = { | ||
689 | { | ||
690 | .name = "dma", | ||
691 | .id = 0, | ||
692 | .parent = &clk_h, | ||
693 | .enable = s3c2443_clkcon_enable_h, | ||
694 | .ctrlbit = S3C2443_HCLKCON_DMA0, | ||
695 | }, { | ||
696 | .name = "dma", | ||
697 | .id = 1, | ||
698 | .parent = &clk_h, | ||
699 | .enable = s3c2443_clkcon_enable_h, | ||
700 | .ctrlbit = S3C2443_HCLKCON_DMA1, | ||
701 | }, { | ||
702 | .name = "dma", | ||
703 | .id = 2, | ||
704 | .parent = &clk_h, | ||
705 | .enable = s3c2443_clkcon_enable_h, | ||
706 | .ctrlbit = S3C2443_HCLKCON_DMA2, | ||
707 | }, { | ||
708 | .name = "dma", | ||
709 | .id = 3, | ||
710 | .parent = &clk_h, | ||
711 | .enable = s3c2443_clkcon_enable_h, | ||
712 | .ctrlbit = S3C2443_HCLKCON_DMA3, | ||
713 | }, { | ||
714 | .name = "dma", | ||
715 | .id = 4, | ||
716 | .parent = &clk_h, | ||
717 | .enable = s3c2443_clkcon_enable_h, | ||
718 | .ctrlbit = S3C2443_HCLKCON_DMA4, | ||
719 | }, { | ||
720 | .name = "dma", | ||
721 | .id = 5, | ||
722 | .parent = &clk_h, | ||
723 | .enable = s3c2443_clkcon_enable_h, | ||
724 | .ctrlbit = S3C2443_HCLKCON_DMA5, | ||
725 | }, { | ||
726 | .name = "lcd", | ||
727 | .id = -1, | ||
728 | .parent = &clk_h, | ||
729 | .enable = s3c2443_clkcon_enable_h, | ||
730 | .ctrlbit = S3C2443_HCLKCON_LCDC, | ||
731 | }, { | ||
732 | .name = "gpio", | ||
733 | .id = -1, | ||
734 | .parent = &clk_p, | ||
735 | .enable = s3c2443_clkcon_enable_p, | ||
736 | .ctrlbit = S3C2443_PCLKCON_GPIO, | ||
737 | }, { | ||
738 | .name = "usb-host", | ||
739 | .id = -1, | ||
740 | .parent = &clk_h, | ||
741 | .enable = s3c2443_clkcon_enable_h, | ||
742 | .ctrlbit = S3C2443_HCLKCON_USBH, | ||
743 | }, { | ||
744 | .name = "usb-device", | ||
745 | .id = -1, | ||
746 | .parent = &clk_h, | ||
747 | .enable = s3c2443_clkcon_enable_h, | ||
748 | .ctrlbit = S3C2443_HCLKCON_USBD, | ||
749 | }, { | ||
750 | .name = "timers", | ||
751 | .id = -1, | ||
752 | .parent = &clk_p, | ||
753 | .enable = s3c2443_clkcon_enable_p, | ||
754 | .ctrlbit = S3C2443_PCLKCON_PWMT, | ||
755 | }, { | ||
756 | .name = "uart", | ||
757 | .id = 0, | ||
758 | .parent = &clk_p, | ||
759 | .enable = s3c2443_clkcon_enable_p, | ||
760 | .ctrlbit = S3C2443_PCLKCON_UART0, | ||
761 | }, { | ||
762 | .name = "uart", | ||
763 | .id = 1, | ||
764 | .parent = &clk_p, | ||
765 | .enable = s3c2443_clkcon_enable_p, | ||
766 | .ctrlbit = S3C2443_PCLKCON_UART1, | ||
767 | }, { | ||
768 | .name = "uart", | ||
769 | .id = 2, | ||
770 | .parent = &clk_p, | ||
771 | .enable = s3c2443_clkcon_enable_p, | ||
772 | .ctrlbit = S3C2443_PCLKCON_UART2, | ||
773 | }, { | ||
774 | .name = "uart", | ||
775 | .id = 3, | ||
776 | .parent = &clk_p, | ||
777 | .enable = s3c2443_clkcon_enable_p, | ||
778 | .ctrlbit = S3C2443_PCLKCON_UART3, | ||
779 | }, { | ||
780 | .name = "rtc", | ||
781 | .id = -1, | ||
782 | .parent = &clk_p, | ||
783 | .enable = s3c2443_clkcon_enable_p, | ||
784 | .ctrlbit = S3C2443_PCLKCON_RTC, | ||
785 | }, { | ||
786 | .name = "watchdog", | ||
787 | .id = -1, | ||
788 | .parent = &clk_p, | ||
789 | .ctrlbit = S3C2443_PCLKCON_WDT, | ||
790 | }, { | ||
791 | .name = "usb-bus-host", | ||
792 | .id = -1, | ||
793 | .parent = &clk_usb_bus_host, | ||
794 | } | ||
795 | }; | ||
796 | |||
797 | /* clocks to add where we need to check their parentage */ | ||
798 | |||
799 | /* s3c2443_clk_initparents | ||
800 | * | ||
801 | * Initialise the parents for the clocks that we get at start-time | ||
802 | */ | ||
803 | |||
804 | static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) | ||
805 | { | ||
806 | printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); | ||
807 | return clk_set_parent(clk, parent); | ||
808 | } | ||
809 | |||
810 | static void __init s3c2443_clk_initparents(void) | ||
811 | { | ||
812 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
813 | struct clk *parent; | ||
814 | |||
815 | switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) { | ||
816 | case S3C2443_CLKSRC_EPLLREF_EXTCLK: | ||
817 | parent = &clk_ext; | ||
818 | break; | ||
819 | |||
820 | case S3C2443_CLKSRC_EPLLREF_XTAL: | ||
821 | default: | ||
822 | parent = &clk_xtal; | ||
823 | break; | ||
824 | |||
825 | case S3C2443_CLKSRC_EPLLREF_MPLLREF: | ||
826 | case S3C2443_CLKSRC_EPLLREF_MPLLREF2: | ||
827 | parent = &clk_mpllref; | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | clk_init_set_parent(&clk_epllref, parent); | ||
832 | |||
833 | switch (clksrc & S3C2443_CLKSRC_I2S_MASK) { | ||
834 | case S3C2443_CLKSRC_I2S_EXT: | ||
835 | parent = &clk_i2s_ext; | ||
836 | break; | ||
837 | |||
838 | case S3C2443_CLKSRC_I2S_EPLLDIV: | ||
839 | default: | ||
840 | parent = &clk_i2s_eplldiv; | ||
841 | break; | ||
842 | |||
843 | case S3C2443_CLKSRC_I2S_EPLLREF: | ||
844 | case S3C2443_CLKSRC_I2S_EPLLREF3: | ||
845 | parent = &clk_epllref; | ||
846 | } | ||
847 | |||
848 | clk_init_set_parent(&clk_i2s, &clk_epllref); | ||
849 | |||
850 | /* esysclk source */ | ||
851 | |||
852 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? | ||
853 | &clk_epll : &clk_epllref; | ||
854 | |||
855 | clk_init_set_parent(&clk_esysclk, parent); | ||
856 | |||
857 | /* msysclk source */ | ||
858 | |||
859 | if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) { | ||
860 | parent = &clk_mpll; | ||
861 | } else { | ||
862 | parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ? | ||
863 | &clk_mdivclk : &clk_mpllref; | ||
864 | } | ||
865 | |||
866 | clk_init_set_parent(&clk_msysclk, parent); | ||
867 | } | ||
868 | |||
869 | /* armdiv divisor table */ | ||
870 | |||
871 | static unsigned int armdiv[16] = { | ||
872 | [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, | ||
873 | [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, | ||
874 | [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, | ||
875 | [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, | ||
876 | [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, | ||
877 | [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, | ||
878 | [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, | ||
879 | [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, | ||
880 | }; | ||
881 | |||
882 | static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) | ||
883 | { | ||
884 | clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; | ||
885 | |||
886 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; | ||
887 | } | ||
888 | |||
889 | static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0) | ||
890 | { | ||
891 | clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK; | ||
892 | clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; | ||
893 | |||
894 | return clkcon0 + 1; | ||
895 | } | ||
896 | |||
897 | /* clocks to add straight away */ | ||
898 | |||
899 | static struct clk *clks[] __initdata = { | ||
900 | &clk_ext, | ||
901 | &clk_epll, | ||
902 | &clk_usb_bus_host, | ||
903 | &clk_usb_bus, | ||
904 | &clk_esysclk, | ||
905 | &clk_epllref, | ||
906 | &clk_mpllref, | ||
907 | &clk_msysclk, | ||
908 | &clk_uart, | ||
909 | &clk_display, | ||
910 | &clk_cam, | ||
911 | &clk_i2s_eplldiv, | ||
912 | &clk_i2s, | ||
913 | &clk_hsspi, | ||
914 | &clk_hsmmc_div, | ||
915 | &clk_hsmmc, | ||
916 | }; | ||
917 | |||
918 | void __init s3c2443_init_clocks(int xtal) | ||
919 | { | ||
920 | unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); | ||
921 | unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); | ||
922 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | ||
923 | unsigned long pll; | ||
924 | unsigned long fclk; | ||
925 | unsigned long hclk; | ||
926 | unsigned long pclk; | ||
927 | struct clk *clkp; | ||
928 | int ret; | ||
929 | int ptr; | ||
930 | |||
931 | pll = s3c2443_get_mpll(mpllcon, xtal); | ||
932 | |||
933 | fclk = pll / s3c2443_fclk_div(clkdiv0); | ||
934 | hclk = fclk / s3c2443_get_prediv(clkdiv0); | ||
935 | hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1); | ||
936 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); | ||
937 | |||
938 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); | ||
939 | |||
940 | printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", | ||
941 | (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on", | ||
942 | print_mhz(pll), print_mhz(fclk), | ||
943 | print_mhz(hclk), print_mhz(pclk)); | ||
944 | |||
945 | s3c2443_clk_initparents(); | ||
946 | |||
947 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { | ||
948 | clkp = clks[ptr]; | ||
949 | |||
950 | ret = s3c24xx_register_clock(clkp); | ||
951 | if (ret < 0) { | ||
952 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
953 | clkp->name, ret); | ||
954 | } | ||
955 | } | ||
956 | |||
957 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); | ||
958 | |||
959 | clk_usb_bus.parent = &clk_usb_bus_host; | ||
960 | |||
961 | /* ensure usb bus clock is within correct rate of 48MHz */ | ||
962 | |||
963 | if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { | ||
964 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); | ||
965 | clk_set_rate(&clk_usb_bus_host, 48*1000*1000); | ||
966 | } | ||
967 | |||
968 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", | ||
969 | (epllcon & S3C2443_PLLCON_OFF) ? "off":"on", | ||
970 | print_mhz(clk_get_rate(&clk_epll)), | ||
971 | print_mhz(clk_get_rate(&clk_usb_bus))); | ||
972 | |||
973 | /* register clocks from clock array */ | ||
974 | |||
975 | clkp = init_clocks; | ||
976 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
977 | ret = s3c24xx_register_clock(clkp); | ||
978 | if (ret < 0) { | ||
979 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
980 | clkp->name, ret); | ||
981 | } | ||
982 | } | ||
983 | |||
984 | /* We must be careful disabling the clocks we are not intending to | ||
985 | * be using at boot time, as subsytems such as the LCD which do | ||
986 | * their own DMA requests to the bus can cause the system to lockup | ||
987 | * if they where in the middle of requesting bus access. | ||
988 | * | ||
989 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
990 | * and therefore the bootloader should be careful to not enable | ||
991 | * the LCD clock if it is not needed. | ||
992 | */ | ||
993 | |||
994 | /* install (and disable) the clocks we do not need immediately */ | ||
995 | |||
996 | clkp = init_clocks_disable; | ||
997 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | ||
998 | |||
999 | ret = s3c24xx_register_clock(clkp); | ||
1000 | if (ret < 0) { | ||
1001 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
1002 | clkp->name, ret); | ||
1003 | } | ||
1004 | |||
1005 | (clkp->enable)(clkp, 0); | ||
1006 | } | ||
1007 | } | ||
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c new file mode 100644 index 000000000000..f70e8ccffc3d --- /dev/null +++ b/arch/arm/mach-s3c2443/dma.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/dma.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2443 DMA selection | ||
7 | * | ||
8 | * http://armlinux.simtec.co.uk/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/sysdev.h> | ||
18 | #include <linux/serial_core.h> | ||
19 | |||
20 | #include <asm/dma.h> | ||
21 | #include <asm/arch/dma.h> | ||
22 | #include <asm/io.h> | ||
23 | |||
24 | #include <asm/plat-s3c24xx/dma.h> | ||
25 | #include <asm/plat-s3c24xx/cpu.h> | ||
26 | |||
27 | #include <asm/arch/regs-serial.h> | ||
28 | #include <asm/arch/regs-gpio.h> | ||
29 | #include <asm/arch/regs-ac97.h> | ||
30 | #include <asm/arch/regs-mem.h> | ||
31 | #include <asm/arch/regs-lcd.h> | ||
32 | #include <asm/arch/regs-sdi.h> | ||
33 | #include <asm/arch/regs-iis.h> | ||
34 | #include <asm/arch/regs-spi.h> | ||
35 | |||
36 | #define MAP(x) { \ | ||
37 | [0] = (x) | DMA_CH_VALID, \ | ||
38 | [1] = (x) | DMA_CH_VALID, \ | ||
39 | [2] = (x) | DMA_CH_VALID, \ | ||
40 | [3] = (x) | DMA_CH_VALID, \ | ||
41 | [4] = (x) | DMA_CH_VALID, \ | ||
42 | [5] = (x) | DMA_CH_VALID, \ | ||
43 | } | ||
44 | |||
45 | static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = { | ||
46 | [DMACH_XD0] = { | ||
47 | .name = "xdreq0", | ||
48 | .channels = MAP(S3C2443_DMAREQSEL_XDREQ0), | ||
49 | }, | ||
50 | [DMACH_XD1] = { | ||
51 | .name = "xdreq1", | ||
52 | .channels = MAP(S3C2443_DMAREQSEL_XDREQ1), | ||
53 | }, | ||
54 | [DMACH_SDI] = { | ||
55 | .name = "sdi", | ||
56 | .channels = MAP(S3C2443_DMAREQSEL_SDI), | ||
57 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
58 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
59 | }, | ||
60 | [DMACH_SPI0] = { | ||
61 | .name = "spi0", | ||
62 | .channels = MAP(S3C2443_DMAREQSEL_SPI0TX), | ||
63 | .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, | ||
64 | .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, | ||
65 | }, | ||
66 | [DMACH_SPI1] = { | ||
67 | .name = "spi1", | ||
68 | .channels = MAP(S3C2443_DMAREQSEL_SPI1TX), | ||
69 | .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, | ||
70 | .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, | ||
71 | }, | ||
72 | [DMACH_UART0] = { | ||
73 | .name = "uart0", | ||
74 | .channels = MAP(S3C2443_DMAREQSEL_UART0_0), | ||
75 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | ||
76 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | ||
77 | }, | ||
78 | [DMACH_UART1] = { | ||
79 | .name = "uart1", | ||
80 | .channels = MAP(S3C2443_DMAREQSEL_UART1_0), | ||
81 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | ||
82 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | ||
83 | }, | ||
84 | [DMACH_UART2] = { | ||
85 | .name = "uart2", | ||
86 | .channels = MAP(S3C2443_DMAREQSEL_UART2_0), | ||
87 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | ||
88 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | ||
89 | }, | ||
90 | [DMACH_UART3] = { | ||
91 | .name = "uart3", | ||
92 | .channels = MAP(S3C2443_DMAREQSEL_UART3_0), | ||
93 | .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH, | ||
94 | .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH, | ||
95 | }, | ||
96 | [DMACH_UART0_SRC2] = { | ||
97 | .name = "uart0", | ||
98 | .channels = MAP(S3C2443_DMAREQSEL_UART0_1), | ||
99 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | ||
100 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | ||
101 | }, | ||
102 | [DMACH_UART1_SRC2] = { | ||
103 | .name = "uart1", | ||
104 | .channels = MAP(S3C2443_DMAREQSEL_UART1_1), | ||
105 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | ||
106 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | ||
107 | }, | ||
108 | [DMACH_UART2_SRC2] = { | ||
109 | .name = "uart2", | ||
110 | .channels = MAP(S3C2443_DMAREQSEL_UART2_1), | ||
111 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | ||
112 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | ||
113 | }, | ||
114 | [DMACH_UART3_SRC2] = { | ||
115 | .name = "uart3", | ||
116 | .channels = MAP(S3C2443_DMAREQSEL_UART3_1), | ||
117 | .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH, | ||
118 | .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH, | ||
119 | }, | ||
120 | [DMACH_TIMER] = { | ||
121 | .name = "timer", | ||
122 | .channels = MAP(S3C2443_DMAREQSEL_TIMER), | ||
123 | }, | ||
124 | [DMACH_I2S_IN] = { | ||
125 | .name = "i2s-sdi", | ||
126 | .channels = MAP(S3C2443_DMAREQSEL_I2SRX), | ||
127 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
128 | }, | ||
129 | [DMACH_I2S_OUT] = { | ||
130 | .name = "i2s-sdo", | ||
131 | .channels = MAP(S3C2443_DMAREQSEL_I2STX), | ||
132 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
133 | }, | ||
134 | [DMACH_PCM_IN] = { | ||
135 | .name = "pcm-in", | ||
136 | .channels = MAP(S3C2443_DMAREQSEL_PCMIN), | ||
137 | .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, | ||
138 | }, | ||
139 | [DMACH_PCM_OUT] = { | ||
140 | .name = "pcm-out", | ||
141 | .channels = MAP(S3C2443_DMAREQSEL_PCMOUT), | ||
142 | .hw_addr.to = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA, | ||
143 | }, | ||
144 | [DMACH_MIC_IN] = { | ||
145 | .name = "mic-in", | ||
146 | .channels = MAP(S3C2443_DMAREQSEL_MICIN), | ||
147 | .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA, | ||
148 | }, | ||
149 | }; | ||
150 | |||
151 | static void s3c2443_dma_select(struct s3c2410_dma_chan *chan, | ||
152 | struct s3c24xx_dma_map *map) | ||
153 | { | ||
154 | writel(map->channels[0] | S3C2443_DMAREQSEL_HW, | ||
155 | chan->regs + S3C2443_DMA_DMAREQSEL); | ||
156 | } | ||
157 | |||
158 | static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = { | ||
159 | .select = s3c2443_dma_select, | ||
160 | .dcon_mask = 0, | ||
161 | .map = s3c2443_dma_mappings, | ||
162 | .map_size = ARRAY_SIZE(s3c2443_dma_mappings), | ||
163 | }; | ||
164 | |||
165 | static int s3c2443_dma_add(struct sys_device *sysdev) | ||
166 | { | ||
167 | s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100); | ||
168 | return s3c24xx_dma_init_map(&s3c2443_dma_sel); | ||
169 | } | ||
170 | |||
171 | static struct sysdev_driver s3c2443_dma_driver = { | ||
172 | .add = s3c2443_dma_add, | ||
173 | }; | ||
174 | |||
175 | static int __init s3c2443_dma_init(void) | ||
176 | { | ||
177 | return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_dma_driver); | ||
178 | } | ||
179 | |||
180 | arch_initcall(s3c2443_dma_init); | ||
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c new file mode 100644 index 000000000000..7a45b6dcb73e --- /dev/null +++ b/arch/arm/mach-s3c2443/irq.c | |||
@@ -0,0 +1,290 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/irq.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/ptrace.h> | ||
27 | #include <linux/sysdev.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | #include <asm/mach/irq.h> | ||
34 | |||
35 | #include <asm/arch/regs-irq.h> | ||
36 | #include <asm/arch/regs-gpio.h> | ||
37 | |||
38 | #include <asm/plat-s3c24xx/cpu.h> | ||
39 | #include <asm/plat-s3c24xx/pm.h> | ||
40 | #include <asm/plat-s3c24xx/irq.h> | ||
41 | |||
42 | #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) | ||
43 | |||
44 | static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len) | ||
45 | { | ||
46 | unsigned int subsrc, submsk; | ||
47 | unsigned int end; | ||
48 | struct irq_desc *mydesc; | ||
49 | |||
50 | /* read the current pending interrupts, and the mask | ||
51 | * for what it is available */ | ||
52 | |||
53 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
54 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
55 | |||
56 | subsrc &= ~submsk; | ||
57 | subsrc >>= (irq - S3C2410_IRQSUB(0)); | ||
58 | subsrc &= (1 << len)-1; | ||
59 | |||
60 | end = len + irq; | ||
61 | mydesc = irq_desc + irq; | ||
62 | |||
63 | for (; irq < end && subsrc; irq++) { | ||
64 | if (subsrc & 1) | ||
65 | desc_handle_irq(irq, mydesc); | ||
66 | |||
67 | mydesc++; | ||
68 | subsrc >>= 1; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /* WDT/AC97 sub interrupts */ | ||
73 | |||
74 | static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) | ||
75 | { | ||
76 | s3c2443_irq_demux(IRQ_S3C2443_WDT, 4); | ||
77 | } | ||
78 | |||
79 | #define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) | ||
80 | #define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) | ||
81 | |||
82 | static void s3c2443_irq_wdtac97_mask(unsigned int irqno) | ||
83 | { | ||
84 | s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); | ||
85 | } | ||
86 | |||
87 | static void s3c2443_irq_wdtac97_unmask(unsigned int irqno) | ||
88 | { | ||
89 | s3c_irqsub_unmask(irqno, INTMSK_WDTAC97); | ||
90 | } | ||
91 | |||
92 | static void s3c2443_irq_wdtac97_ack(unsigned int irqno) | ||
93 | { | ||
94 | s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); | ||
95 | } | ||
96 | |||
97 | static struct irq_chip s3c2443_irq_wdtac97 = { | ||
98 | .mask = s3c2443_irq_wdtac97_mask, | ||
99 | .unmask = s3c2443_irq_wdtac97_unmask, | ||
100 | .ack = s3c2443_irq_wdtac97_ack, | ||
101 | }; | ||
102 | |||
103 | |||
104 | /* LCD sub interrupts */ | ||
105 | |||
106 | static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) | ||
107 | { | ||
108 | s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4); | ||
109 | } | ||
110 | |||
111 | #define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) | ||
112 | #define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) | ||
113 | |||
114 | static void s3c2443_irq_lcd_mask(unsigned int irqno) | ||
115 | { | ||
116 | s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD); | ||
117 | } | ||
118 | |||
119 | static void s3c2443_irq_lcd_unmask(unsigned int irqno) | ||
120 | { | ||
121 | s3c_irqsub_unmask(irqno, INTMSK_LCD); | ||
122 | } | ||
123 | |||
124 | static void s3c2443_irq_lcd_ack(unsigned int irqno) | ||
125 | { | ||
126 | s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD); | ||
127 | } | ||
128 | |||
129 | static struct irq_chip s3c2443_irq_lcd = { | ||
130 | .mask = s3c2443_irq_lcd_mask, | ||
131 | .unmask = s3c2443_irq_lcd_unmask, | ||
132 | .ack = s3c2443_irq_lcd_ack, | ||
133 | }; | ||
134 | |||
135 | |||
136 | /* DMA sub interrupts */ | ||
137 | |||
138 | static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc) | ||
139 | { | ||
140 | s3c2443_irq_demux(IRQ_S3C2443_DMA1, 6); | ||
141 | } | ||
142 | |||
143 | #define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) | ||
144 | #define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) | ||
145 | |||
146 | |||
147 | static void s3c2443_irq_dma_mask(unsigned int irqno) | ||
148 | { | ||
149 | s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA); | ||
150 | } | ||
151 | |||
152 | static void s3c2443_irq_dma_unmask(unsigned int irqno) | ||
153 | { | ||
154 | s3c_irqsub_unmask(irqno, INTMSK_DMA); | ||
155 | } | ||
156 | |||
157 | static void s3c2443_irq_dma_ack(unsigned int irqno) | ||
158 | { | ||
159 | s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA); | ||
160 | } | ||
161 | |||
162 | static struct irq_chip s3c2443_irq_dma = { | ||
163 | .mask = s3c2443_irq_dma_mask, | ||
164 | .unmask = s3c2443_irq_dma_unmask, | ||
165 | .ack = s3c2443_irq_dma_ack, | ||
166 | }; | ||
167 | |||
168 | |||
169 | /* UART3 sub interrupts */ | ||
170 | |||
171 | static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) | ||
172 | { | ||
173 | s3c2443_irq_demux(IRQ_S3C2443_UART3, 3); | ||
174 | } | ||
175 | |||
176 | #define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) | ||
177 | #define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) | ||
178 | |||
179 | |||
180 | static void s3c2443_irq_uart3_mask(unsigned int irqno) | ||
181 | { | ||
182 | s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3); | ||
183 | } | ||
184 | |||
185 | static void s3c2443_irq_uart3_unmask(unsigned int irqno) | ||
186 | { | ||
187 | s3c_irqsub_unmask(irqno, INTMSK_UART3); | ||
188 | } | ||
189 | |||
190 | static void s3c2443_irq_uart3_ack(unsigned int irqno) | ||
191 | { | ||
192 | s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3); | ||
193 | } | ||
194 | |||
195 | static struct irq_chip s3c2443_irq_uart3 = { | ||
196 | .mask = s3c2443_irq_uart3_mask, | ||
197 | .unmask = s3c2443_irq_uart3_unmask, | ||
198 | .ack = s3c2443_irq_uart3_ack, | ||
199 | }; | ||
200 | |||
201 | |||
202 | /* CAM sub interrupts */ | ||
203 | |||
204 | static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc) | ||
205 | { | ||
206 | s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4); | ||
207 | } | ||
208 | |||
209 | #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) | ||
210 | #define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P) | ||
211 | |||
212 | static void s3c2443_irq_cam_mask(unsigned int irqno) | ||
213 | { | ||
214 | s3c_irqsub_mask(irqno, INTMSK_CAM, SUBMSK_CAM); | ||
215 | } | ||
216 | |||
217 | static void s3c2443_irq_cam_unmask(unsigned int irqno) | ||
218 | { | ||
219 | s3c_irqsub_unmask(irqno, INTMSK_CAM); | ||
220 | } | ||
221 | |||
222 | static void s3c2443_irq_cam_ack(unsigned int irqno) | ||
223 | { | ||
224 | s3c_irqsub_maskack(irqno, INTMSK_CAM, SUBMSK_CAM); | ||
225 | } | ||
226 | |||
227 | static struct irq_chip s3c2443_irq_cam = { | ||
228 | .mask = s3c2443_irq_cam_mask, | ||
229 | .unmask = s3c2443_irq_cam_unmask, | ||
230 | .ack = s3c2443_irq_cam_ack, | ||
231 | }; | ||
232 | |||
233 | /* IRQ initialisation code */ | ||
234 | |||
235 | static int __init s3c2443_add_sub(unsigned int base, | ||
236 | void (*demux)(unsigned int, | ||
237 | struct irq_desc *), | ||
238 | struct irq_chip *chip, | ||
239 | unsigned int start, unsigned int end) | ||
240 | { | ||
241 | unsigned int irqno; | ||
242 | |||
243 | set_irq_chip(base, &s3c_irq_level_chip); | ||
244 | set_irq_handler(base, handle_level_irq); | ||
245 | set_irq_chained_handler(base, demux); | ||
246 | |||
247 | for (irqno = start; irqno <= end; irqno++) { | ||
248 | set_irq_chip(irqno, chip); | ||
249 | set_irq_handler(irqno, handle_level_irq); | ||
250 | set_irq_flags(irqno, IRQF_VALID); | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int s3c2443_irq_add(struct sys_device *sysdev) | ||
257 | { | ||
258 | printk("S3C2443: IRQ Support\n"); | ||
259 | |||
260 | s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam, | ||
261 | IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P); | ||
262 | |||
263 | s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd, | ||
264 | IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4); | ||
265 | |||
266 | s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma, | ||
267 | &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); | ||
268 | |||
269 | s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3, | ||
270 | &s3c2443_irq_uart3, | ||
271 | IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); | ||
272 | |||
273 | s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97, | ||
274 | &s3c2443_irq_wdtac97, | ||
275 | IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static struct sysdev_driver s3c2443_irq_driver = { | ||
281 | .add = s3c2443_irq_add, | ||
282 | }; | ||
283 | |||
284 | static int s3c2443_irq_init(void) | ||
285 | { | ||
286 | return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_irq_driver); | ||
287 | } | ||
288 | |||
289 | arch_initcall(s3c2443_irq_init); | ||
290 | |||
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c new file mode 100644 index 000000000000..e82aaff7dee4 --- /dev/null +++ b/arch/arm/mach-s3c2443/mach-smdk2443.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/mach-smdk2443.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * http://www.fluff.org/ben/smdk2443/ | ||
7 | * | ||
8 | * Thanks to Samsung for the loan of an SMDK2443 | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/timer.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/serial_core.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include <asm/mach/arch.h> | ||
26 | #include <asm/mach/map.h> | ||
27 | #include <asm/mach/irq.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/mach-types.h> | ||
33 | |||
34 | #include <asm/arch/regs-serial.h> | ||
35 | #include <asm/arch/regs-gpio.h> | ||
36 | #include <asm/arch/regs-lcd.h> | ||
37 | |||
38 | #include <asm/arch/idle.h> | ||
39 | #include <asm/arch/fb.h> | ||
40 | |||
41 | #include <asm/plat-s3c24xx/s3c2410.h> | ||
42 | #include <asm/plat-s3c24xx/s3c2440.h> | ||
43 | #include <asm/plat-s3c24xx/clock.h> | ||
44 | #include <asm/plat-s3c24xx/devs.h> | ||
45 | #include <asm/plat-s3c24xx/cpu.h> | ||
46 | |||
47 | #include <asm/plat-s3c24xx/common-smdk.h> | ||
48 | |||
49 | static struct map_desc smdk2443_iodesc[] __initdata = { | ||
50 | /* ISA IO Space map (memory space selected by A24) */ | ||
51 | |||
52 | { | ||
53 | .virtual = (u32)S3C24XX_VA_ISA_WORD, | ||
54 | .pfn = __phys_to_pfn(S3C2410_CS2), | ||
55 | .length = 0x10000, | ||
56 | .type = MT_DEVICE, | ||
57 | }, { | ||
58 | .virtual = (u32)S3C24XX_VA_ISA_WORD + 0x10000, | ||
59 | .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), | ||
60 | .length = SZ_4M, | ||
61 | .type = MT_DEVICE, | ||
62 | }, { | ||
63 | .virtual = (u32)S3C24XX_VA_ISA_BYTE, | ||
64 | .pfn = __phys_to_pfn(S3C2410_CS2), | ||
65 | .length = 0x10000, | ||
66 | .type = MT_DEVICE, | ||
67 | }, { | ||
68 | .virtual = (u32)S3C24XX_VA_ISA_BYTE + 0x10000, | ||
69 | .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)), | ||
70 | .length = SZ_4M, | ||
71 | .type = MT_DEVICE, | ||
72 | } | ||
73 | }; | ||
74 | |||
75 | #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK | ||
76 | #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB | ||
77 | #define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE | ||
78 | |||
79 | static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = { | ||
80 | [0] = { | ||
81 | .hwport = 0, | ||
82 | .flags = 0, | ||
83 | .ucon = 0x3c5, | ||
84 | .ulcon = 0x03, | ||
85 | .ufcon = 0x51, | ||
86 | }, | ||
87 | [1] = { | ||
88 | .hwport = 1, | ||
89 | .flags = 0, | ||
90 | .ucon = 0x3c5, | ||
91 | .ulcon = 0x03, | ||
92 | .ufcon = 0x51, | ||
93 | }, | ||
94 | /* IR port */ | ||
95 | [2] = { | ||
96 | .hwport = 2, | ||
97 | .flags = 0, | ||
98 | .ucon = 0x3c5, | ||
99 | .ulcon = 0x43, | ||
100 | .ufcon = 0x51, | ||
101 | } | ||
102 | }; | ||
103 | |||
104 | static struct platform_device *smdk2443_devices[] __initdata = { | ||
105 | &s3c_device_wdt, | ||
106 | &s3c_device_i2c, | ||
107 | }; | ||
108 | |||
109 | static struct s3c24xx_board smdk2443_board __initdata = { | ||
110 | .devices = smdk2443_devices, | ||
111 | .devices_count = ARRAY_SIZE(smdk2443_devices) | ||
112 | }; | ||
113 | |||
114 | static void __init smdk2443_map_io(void) | ||
115 | { | ||
116 | s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc)); | ||
117 | s3c24xx_init_clocks(12000000); | ||
118 | s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs)); | ||
119 | s3c24xx_set_board(&smdk2443_board); | ||
120 | } | ||
121 | |||
122 | static void __init smdk2443_machine_init(void) | ||
123 | { | ||
124 | smdk_machine_init(); | ||
125 | } | ||
126 | |||
127 | MACHINE_START(SMDK2443, "SMDK2443") | ||
128 | /* Maintainer: Ben Dooks <ben@fluff.org> */ | ||
129 | .phys_io = S3C2410_PA_UART, | ||
130 | .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, | ||
131 | .boot_params = S3C2410_SDRAM_PA + 0x100, | ||
132 | |||
133 | .init_irq = s3c24xx_init_irq, | ||
134 | .map_io = smdk2443_map_io, | ||
135 | .init_machine = smdk2443_machine_init, | ||
136 | .timer = &s3c24xx_timer, | ||
137 | MACHINE_END | ||
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c new file mode 100644 index 000000000000..11b1d0b310c3 --- /dev/null +++ b/arch/arm/mach-s3c2443/s3c2443.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/s3c2443.c | ||
2 | * | ||
3 | * Copyright (c) 2007 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * Samsung S3C2443 Mobile CPU support | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/list.h> | ||
17 | #include <linux/timer.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/serial_core.h> | ||
21 | #include <linux/sysdev.h> | ||
22 | #include <linux/clk.h> | ||
23 | |||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach/map.h> | ||
26 | #include <asm/mach/irq.h> | ||
27 | |||
28 | #include <asm/hardware.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/irq.h> | ||
31 | |||
32 | #include <asm/arch/regs-s3c2443-clock.h> | ||
33 | #include <asm/arch/reset.h> | ||
34 | |||
35 | #include <asm/plat-s3c24xx/s3c2443.h> | ||
36 | #include <asm/plat-s3c24xx/devs.h> | ||
37 | #include <asm/plat-s3c24xx/cpu.h> | ||
38 | |||
39 | static struct map_desc s3c2443_iodesc[] __initdata = { | ||
40 | IODESC_ENT(WATCHDOG), | ||
41 | IODESC_ENT(CLKPWR), | ||
42 | IODESC_ENT(TIMER), | ||
43 | }; | ||
44 | |||
45 | struct sysdev_class s3c2443_sysclass = { | ||
46 | set_kset_name("s3c2443-core"), | ||
47 | }; | ||
48 | |||
49 | static struct sys_device s3c2443_sysdev = { | ||
50 | .cls = &s3c2443_sysclass, | ||
51 | }; | ||
52 | |||
53 | static void s3c2443_hard_reset(void) | ||
54 | { | ||
55 | __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST); | ||
56 | } | ||
57 | |||
58 | int __init s3c2443_init(void) | ||
59 | { | ||
60 | printk("S3C2443: Initialising architecture\n"); | ||
61 | |||
62 | s3c24xx_reset_hook = s3c2443_hard_reset; | ||
63 | |||
64 | s3c_device_nand.name = "s3c2412-nand"; | ||
65 | |||
66 | return sysdev_register(&s3c2443_sysdev); | ||
67 | } | ||
68 | |||
69 | void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no) | ||
70 | { | ||
71 | s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); | ||
72 | } | ||
73 | |||
74 | /* s3c2443_map_io | ||
75 | * | ||
76 | * register the standard cpu IO areas, and any passed in from the | ||
77 | * machine specific initialisation. | ||
78 | */ | ||
79 | |||
80 | void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size) | ||
81 | { | ||
82 | iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); | ||
83 | iotable_init(mach_desc, mach_size); | ||
84 | } | ||
85 | |||
86 | /* need to register class before we actually register the device, and | ||
87 | * we also need to ensure that it has been initialised before any of the | ||
88 | * drivers even try to use it (even if not on an s3c2443 based system) | ||
89 | * as a driver which may support both 2443 and 2440 may try and use it. | ||
90 | */ | ||
91 | |||
92 | static int __init s3c2443_core_init(void) | ||
93 | { | ||
94 | return sysdev_class_register(&s3c2443_sysclass); | ||
95 | } | ||
96 | |||
97 | core_initcall(s3c2443_core_init); | ||