diff options
-rw-r--r-- | arch/arm/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/mach-s3c2400/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mach-s3c2400/Makefile | 15 | ||||
-rw-r--r-- | arch/arm/mach-s3c2400/gpio.c (renamed from arch/arm/mach-s3c2410/s3c2400-gpio.c) | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/Kconfig | 356 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/Makefile | 95 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/bast-irq.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/bast.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/clock.c | 565 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/dma.c | 1528 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/gpio.c | 165 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/irq.c | 775 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-amlm5900.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-bast.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-h1940.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-n30.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-otom.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-smdk2410.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-vr1000.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/pm.c | 653 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-clock.c | 276 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-dma.c | 161 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-gpio.c | 71 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-irq.c | 48 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-pm.c | 156 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410-sleep.S | 68 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/s3c2410.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/sleep.S | 151 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/usb-simtec.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/Kconfig | 58 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/Makefile | 21 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/clock.c (renamed from arch/arm/mach-s3c2410/s3c2412-clock.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/dma.c (renamed from arch/arm/mach-s3c2410/s3c2412-dma.c) | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/irq.c (renamed from arch/arm/mach-s3c2410/s3c2412-irq.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/mach-smdk2413.c (renamed from arch/arm/mach-s3c2410/mach-smdk2413.c) | 14 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/mach-vstms.c (renamed from arch/arm/mach-s3c2410/mach-vstms.c) | 12 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/pm.c (renamed from arch/arm/mach-s3c2410/s3c2412-pm.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2412/s3c2412.c (renamed from arch/arm/mach-s3c2410/s3c2412.c) | 12 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/Kconfig | 71 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/Makefile | 23 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/clock.c (renamed from arch/arm/mach-s3c2410/s3c2440-clock.c) | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/dma.c (renamed from arch/arm/mach-s3c2410/s3c2440-dma.c) | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/dsc.c (renamed from arch/arm/mach-s3c2410/s3c2440-dsc.c) | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/irq.c (renamed from arch/arm/mach-s3c2410/s3c2440-irq.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-anubis.c (renamed from arch/arm/mach-s3c2410/mach-anubis.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-nexcoder.c (renamed from arch/arm/mach-s3c2410/mach-nexcoder.c) | 12 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-osiris.c (renamed from arch/arm/mach-s3c2410/mach-osiris.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-rx3715.c (renamed from arch/arm/mach-s3c2410/mach-rx3715.c) | 10 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/mach-smdk2440.c (renamed from arch/arm/mach-s3c2410/mach-smdk2440.c) | 14 | ||||
-rw-r--r-- | arch/arm/mach-s3c2440/s3c2440.c (renamed from arch/arm/mach-s3c2410/s3c2440.c) | 8 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/Kconfig | 27 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/Makefile | 16 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/clock.c (renamed from arch/arm/mach-s3c2410/s3c2442-clock.c) | 6 | ||||
-rw-r--r-- | arch/arm/mach-s3c2442/s3c2442.c (renamed from arch/arm/mach-s3c2410/s3c2442.c) | 6 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/Kconfig | 96 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/Makefile | 30 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/clock.c | 449 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/common-smdk.c (renamed from arch/arm/mach-s3c2410/common-smdk.c) | 8 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/cpu.c (renamed from arch/arm/mach-s3c2410/cpu.c) | 18 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/devs.c (renamed from arch/arm/mach-s3c2410/devs.c) | 6 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/dma.c | 1441 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/gpio.c | 188 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/irq.c | 801 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/pm-simtec.c (renamed from arch/arm/mach-s3c2410/pm-simtec.c) | 4 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/pm.c | 659 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/s3c244x-irq.c (renamed from arch/arm/mach-s3c2410/s3c244x-irq.c) | 8 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/s3c244x.c (renamed from arch/arm/mach-s3c2410/s3c244x.c) | 14 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/s3c244x.h (renamed from arch/arm/mach-s3c2410/s3c244x.h) | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/sleep.S | 159 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/time.c (renamed from arch/arm/mach-s3c2410/time.c) | 6 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/clock.h (renamed from arch/arm/mach-s3c2410/clock.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/common-smdk.h (renamed from arch/arm/mach-s3c2410/common-smdk.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/cpu.h (renamed from arch/arm/mach-s3c2410/cpu.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/devs.h (renamed from arch/arm/mach-s3c2410/devs.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/dma.h (renamed from arch/arm/mach-s3c2410/dma.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/irq.h (renamed from arch/arm/mach-s3c2410/irq.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/pm.h (renamed from arch/arm/mach-s3c2410/pm.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/s3c2400.h (renamed from arch/arm/mach-s3c2410/s3c2400.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/s3c2410.h (renamed from arch/arm/mach-s3c2410/s3c2410.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/s3c2412.h (renamed from arch/arm/mach-s3c2410/s3c2412.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/s3c2440.h (renamed from arch/arm/mach-s3c2410/s3c2440.h) | 2 | ||||
-rw-r--r-- | include/asm-arm/plat-s3c24xx/s3c2442.h (renamed from arch/arm/mach-s3c2410/s3c2442.h) | 2 |
83 files changed, 4783 insertions, 4689 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6783c2e5512d..51ee13e7c74c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -363,7 +363,15 @@ source "arch/arm/mach-omap1/Kconfig" | |||
363 | 363 | ||
364 | source "arch/arm/mach-omap2/Kconfig" | 364 | source "arch/arm/mach-omap2/Kconfig" |
365 | 365 | ||
366 | source "arch/arm/plat-s3c24xx/Kconfig" | ||
367 | |||
368 | if ARCH_S3C2410 | ||
369 | source "arch/arm/mach-s3c2400/Kconfig" | ||
366 | source "arch/arm/mach-s3c2410/Kconfig" | 370 | source "arch/arm/mach-s3c2410/Kconfig" |
371 | source "arch/arm/mach-s3c2412/Kconfig" | ||
372 | source "arch/arm/mach-s3c2440/Kconfig" | ||
373 | source "arch/arm/mach-s3c2442/Kconfig" | ||
374 | endif | ||
367 | 375 | ||
368 | source "arch/arm/mach-lh7a40x/Kconfig" | 376 | source "arch/arm/mach-lh7a40x/Kconfig" |
369 | 377 | ||
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 000f1100b553..2df1ea0a0c2d 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -149,7 +149,7 @@ MACHINE := arch/arm/mach-$(machine-y)/ | |||
149 | else | 149 | else |
150 | MACHINE := | 150 | MACHINE := |
151 | endif | 151 | endif |
152 | 152 | ||
153 | export TEXT_OFFSET GZFLAGS MMUEXT | 153 | export TEXT_OFFSET GZFLAGS MMUEXT |
154 | 154 | ||
155 | # Do we have FASTFPE? | 155 | # Do we have FASTFPE? |
@@ -161,6 +161,10 @@ endif | |||
161 | # If we have a machine-specific directory, then include it in the build. | 161 | # If we have a machine-specific directory, then include it in the build. |
162 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ | 162 | core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ |
163 | core-y += $(MACHINE) | 163 | core-y += $(MACHINE) |
164 | core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2400/ | ||
165 | core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2412/ | ||
166 | core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/ | ||
167 | core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/ | ||
164 | core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ | 168 | core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ |
165 | core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) | 169 | core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) |
166 | core-$(CONFIG_VFP) += arch/arm/vfp/ | 170 | core-$(CONFIG_VFP) += arch/arm/vfp/ |
@@ -168,6 +172,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/ | |||
168 | # If we have a common platform directory, then include it in the build. | 172 | # If we have a common platform directory, then include it in the build. |
169 | core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/ | 173 | core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/ |
170 | core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ | 174 | core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ |
175 | core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/ | ||
171 | 176 | ||
172 | drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ | 177 | drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ |
173 | drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ | 178 | drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ |
diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig new file mode 100644 index 000000000000..deab0722836e --- /dev/null +++ b/arch/arm/mach-s3c2400/Kconfig | |||
@@ -0,0 +1,13 @@ | |||
1 | # arch/arm/mach-s3c2400/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | |||
8 | |||
9 | menu "S3C2400 Machines" | ||
10 | |||
11 | |||
12 | endmenu | ||
13 | |||
diff --git a/arch/arm/mach-s3c2400/Makefile b/arch/arm/mach-s3c2400/Makefile new file mode 100644 index 000000000000..7e23f4e13766 --- /dev/null +++ b/arch/arm/mach-s3c2400/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | # arch/arm/mach-s3c2400/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_S3C2400) += gpio.o | ||
13 | |||
14 | # Machine support | ||
15 | |||
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2400/gpio.c index 1576d01d5f82..758e160410e9 100644 --- a/arch/arm/mach-s3c2410/s3c2400-gpio.c +++ b/arch/arm/mach-s3c2400/gpio.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c | 1 | /* linux/arch/arm/mach-s3c2400/gpio.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org> | 3 | * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org> |
4 | * | 4 | * |
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 0ab590ec4582..016b53f5d6fc 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig | |||
@@ -1,54 +1,51 @@ | |||
1 | if ARCH_S3C2410 | 1 | # arch/arm/mach-s3c2410/Kconfig |
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
2 | 6 | ||
3 | menu "S3C24XX Implementations" | 7 | config CPU_S3C2410 |
8 | bool | ||
9 | depends on ARCH_S3C2410 | ||
10 | select S3C2410_CLOCK | ||
11 | select S3C2410_GPIO | ||
12 | select S3C2410_PM if PM | ||
13 | help | ||
14 | Support for S3C2410 and S3C2410A family from the S3C24XX line | ||
15 | of Samsung Mobile CPUs. | ||
4 | 16 | ||
5 | config MACH_AML_M5900 | 17 | config CPU_S3C2410_DMA |
6 | bool "AML M5900 Series" | 18 | bool |
7 | select CPU_S3C2410 | 19 | depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442) |
8 | select PM_SIMTEC if PM | 20 | default y if CPU_S3C2410 || CPU_S3C2442 |
9 | help | 21 | help |
10 | Say Y here if you are using the American Microsystems M5900 Series | 22 | DMA device selection for S3C2410 and compatible CPUs |
11 | <http://www.amltd.com> | ||
12 | 23 | ||
13 | config MACH_ANUBIS | 24 | config S3C2410_PM |
14 | bool "Simtec Electronics ANUBIS" | 25 | bool |
15 | select CPU_S3C2440 | ||
16 | select PM_SIMTEC if PM | ||
17 | help | 26 | help |
18 | Say Y here if you are using the Simtec Electronics ANUBIS | 27 | Power Management code common to S3C2410 and better |
19 | development system | ||
20 | 28 | ||
21 | config MACH_OSIRIS | 29 | config S3C2410_GPIO |
22 | bool "Simtec IM2440D20 (OSIRIS) module" | 30 | bool |
23 | select CPU_S3C2440 | ||
24 | select PM_SIMTEC if PM | ||
25 | help | 31 | help |
26 | Say Y here if you are using the Simtec IM2440D20 module, also | 32 | GPIO code for S3C2410 and similar processors |
27 | known as the Osiris. | ||
28 | 33 | ||
29 | config ARCH_BAST | 34 | config S3C2410_CLOCK |
30 | bool "Simtec Electronics BAST (EB2410ITX)" | 35 | bool |
31 | select CPU_S3C2410 | ||
32 | select PM_SIMTEC if PM | ||
33 | select ISA | ||
34 | help | 36 | help |
35 | Say Y here if you are using the Simtec Electronics EB2410ITX | 37 | Clock code for the S3C2410, and similar processors |
36 | development board (also known as BAST) | ||
37 | 38 | ||
38 | Product page: <http://www.simtec.co.uk/products/EB2410ITX/>. | ||
39 | 39 | ||
40 | config BAST_PC104_IRQ | 40 | menu "S3C2410 Machines" |
41 | bool "BAST PC104 IRQ support" | ||
42 | depends on ARCH_BAST | ||
43 | default y | ||
44 | help | ||
45 | Say Y here to enable the PC104 IRQ routing on the | ||
46 | Simtec BAST (EB2410ITX) | ||
47 | 41 | ||
48 | config PM_H1940 | 42 | config ARCH_SMDK2410 |
49 | bool | 43 | bool "SMDK2410/A9M2410" |
44 | select CPU_S3C2410 | ||
45 | select MACH_SMDK | ||
50 | help | 46 | help |
51 | Internal node for H1940 and related PM | 47 | Say Y here if you are using the SMDK2410 or the derived module A9M2410 |
48 | <http://www.fsforth.de> | ||
52 | 49 | ||
53 | config ARCH_H1940 | 50 | config ARCH_H1940 |
54 | bool "IPAQ H1940" | 51 | bool "IPAQ H1940" |
@@ -57,7 +54,10 @@ config ARCH_H1940 | |||
57 | help | 54 | help |
58 | Say Y here if you are using the HP IPAQ H1940 | 55 | Say Y here if you are using the HP IPAQ H1940 |
59 | 56 | ||
60 | <http://www.handhelds.org/projects/h1940.html>. | 57 | config PM_H1940 |
58 | bool | ||
59 | help | ||
60 | Internal node for H1940 and related PM | ||
61 | 61 | ||
62 | config MACH_N30 | 62 | config MACH_N30 |
63 | bool "Acer N30" | 63 | bool "Acer N30" |
@@ -65,53 +65,36 @@ config MACH_N30 | |||
65 | help | 65 | help |
66 | Say Y here if you are using the Acer N30 | 66 | Say Y here if you are using the Acer N30 |
67 | 67 | ||
68 | <http://zoo.weinigel.se/n30>. | 68 | config ARCH_BAST |
69 | 69 | bool "Simtec Electronics BAST (EB2410ITX)" | |
70 | config MACH_SMDK | ||
71 | bool | ||
72 | help | ||
73 | Common machine code for SMDK2410 and SMDK2440 | ||
74 | |||
75 | config ARCH_SMDK2410 | ||
76 | bool "SMDK2410/A9M2410" | ||
77 | select CPU_S3C2410 | 70 | select CPU_S3C2410 |
78 | select MACH_SMDK | 71 | select PM_SIMTEC if PM |
72 | select ISA | ||
79 | help | 73 | help |
80 | Say Y here if you are using the SMDK2410 or the derived module A9M2410 | 74 | Say Y here if you are using the Simtec Electronics EB2410ITX |
81 | <http://www.fsforth.de> | 75 | development board (also known as BAST) |
82 | 76 | ||
83 | config ARCH_S3C2440 | 77 | config MACH_OTOM |
84 | bool "SMDK2440" | 78 | bool "NexVision OTOM Board" |
85 | select CPU_S3C2440 | 79 | select CPU_S3C2410 |
86 | select MACH_SMDK | ||
87 | help | 80 | help |
88 | Say Y here if you are using the SMDK2440. | 81 | Say Y here if you are using the Nex Vision OTOM board |
89 | |||
90 | config SMDK2440_CPU2440 | ||
91 | bool "SMDK2440 with S3C2440 CPU module" | ||
92 | depends on ARCH_S3C2440 | ||
93 | default y if ARCH_S3C2440 | ||
94 | select CPU_S3C2440 | ||
95 | |||
96 | config SMDK2440_CPU2442 | ||
97 | bool "SMDM2440 with S3C2442 CPU module" | ||
98 | depends on ARCH_S3C2440 | ||
99 | select CPU_S3C2442 | ||
100 | 82 | ||
101 | config MACH_S3C2413 | 83 | config MACH_AML_M5900 |
102 | bool | 84 | bool "AML M5900 Series" |
85 | select CPU_S3C2410 | ||
86 | select PM_SIMTEC if PM | ||
103 | help | 87 | help |
104 | Internal node for S3C2413 version of SMDK2413, so that | 88 | Say Y here if you are using the American Microsystems M5900 Series |
105 | machine_is_s3c2413() will work when MACH_SMDK2413 is | 89 | <http://www.amltd.com> |
106 | selected | ||
107 | 90 | ||
108 | config MACH_SMDK2413 | 91 | config BAST_PC104_IRQ |
109 | bool "SMDK2413" | 92 | bool "BAST PC104 IRQ support" |
110 | select CPU_S3C2412 | 93 | depends on ARCH_BAST |
111 | select MACH_S3C2413 | 94 | default y |
112 | select MACH_SMDK | ||
113 | help | 95 | help |
114 | Say Y here if you are using an SMDK2413 | 96 | Say Y here to enable the PC104 IRQ routing on the |
97 | Simtec BAST (EB2410ITX) | ||
115 | 98 | ||
116 | config MACH_VR1000 | 99 | config MACH_VR1000 |
117 | bool "Thorcom VR1000" | 100 | bool "Thorcom VR1000" |
@@ -120,223 +103,6 @@ config MACH_VR1000 | |||
120 | help | 103 | help |
121 | Say Y here if you are using the Thorcom VR1000 board. | 104 | Say Y here if you are using the Thorcom VR1000 board. |
122 | 105 | ||
123 | This linux port is currently being maintained by Simtec, on behalf | ||
124 | of Thorcom. Any queries, please contact Thorcom first. | ||
125 | |||
126 | config MACH_RX3715 | ||
127 | bool "HP iPAQ rx3715" | ||
128 | select CPU_S3C2440 | ||
129 | select PM_H1940 if PM | ||
130 | help | ||
131 | Say Y here if you are using the HP iPAQ rx3715. | ||
132 | |||
133 | See <http://www.handhelds.org/projects/rx3715.html> for more | ||
134 | information on this project | ||
135 | |||
136 | config MACH_OTOM | ||
137 | bool "NexVision OTOM Board" | ||
138 | select CPU_S3C2410 | ||
139 | help | ||
140 | Say Y here if you are using the Nex Vision OTOM board | ||
141 | |||
142 | config MACH_NEXCODER_2440 | ||
143 | bool "NexVision NEXCODER 2440 Light Board" | ||
144 | select CPU_S3C2440 | ||
145 | help | ||
146 | Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board | ||
147 | |||
148 | config MACH_VSTMS | ||
149 | bool "VMSTMS" | ||
150 | select CPU_S3C2412 | ||
151 | help | ||
152 | Say Y here if you are using an VSTMS board | ||
153 | 106 | ||
154 | endmenu | 107 | endmenu |
155 | 108 | ||
156 | config S3C2410_CLOCK | ||
157 | bool | ||
158 | help | ||
159 | Clock code for the S3C2410, and similar processors | ||
160 | |||
161 | config S3C2410_GPIO | ||
162 | bool | ||
163 | help | ||
164 | GPIO code for S3C2410 and similar processors | ||
165 | |||
166 | config S3C2410_PM | ||
167 | bool | ||
168 | help | ||
169 | Power Management code common to S3C2410 and better | ||
170 | |||
171 | config CPU_S3C2410_DMA | ||
172 | bool | ||
173 | depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442) | ||
174 | default y if CPU_S3C2410 || CPU_S3C2442 | ||
175 | help | ||
176 | DMA device selection for S3C2410 and compatible CPUs | ||
177 | |||
178 | config CPU_S3C2410 | ||
179 | bool | ||
180 | depends on ARCH_S3C2410 | ||
181 | select S3C2410_CLOCK | ||
182 | select S3C2410_GPIO | ||
183 | select S3C2410_PM if PM | ||
184 | help | ||
185 | Support for S3C2410 and S3C2410A family from the S3C24XX line | ||
186 | of Samsung Mobile CPUs. | ||
187 | |||
188 | # internal node to signify if we are only dealing with an S3C2412 | ||
189 | |||
190 | config CPU_S3C2412_ONLY | ||
191 | bool | ||
192 | depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ | ||
193 | !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 | ||
194 | default y if CPU_S3C2412 | ||
195 | |||
196 | config S3C2412_PM | ||
197 | bool | ||
198 | help | ||
199 | Internal config node to apply S3C2412 power management | ||
200 | |||
201 | config S3C2412_DMA | ||
202 | bool | ||
203 | depends on CPU_S3C2412 | ||
204 | help | ||
205 | Internal config node for S3C2412 DMA support | ||
206 | |||
207 | config CPU_S3C2412 | ||
208 | bool | ||
209 | depends on ARCH_S3C2410 | ||
210 | select S3C2412_PM if PM | ||
211 | select S3C2412_DMA if S3C2410_DMA | ||
212 | help | ||
213 | Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line | ||
214 | |||
215 | config CPU_S3C244X | ||
216 | bool | ||
217 | depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) | ||
218 | help | ||
219 | Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems. | ||
220 | |||
221 | config S3C2440_DMA | ||
222 | bool | ||
223 | depends on ARCH_S3C2410 && CPU_S3C24405B | ||
224 | help | ||
225 | Support for S3C2440 specific DMA code5A | ||
226 | |||
227 | config CPU_S3C2440 | ||
228 | bool | ||
229 | depends on ARCH_S3C2410 | ||
230 | select S3C2410_CLOCK | ||
231 | select S3C2410_PM if PM | ||
232 | select S3C2410_GPIO | ||
233 | select S3C2440_DMA if S3C2410_DMA | ||
234 | select CPU_S3C244X | ||
235 | help | ||
236 | Support for S3C2440 Samsung Mobile CPU based systems. | ||
237 | |||
238 | config CPU_S3C2442 | ||
239 | bool | ||
240 | depends on ARCH_S3C2420 | ||
241 | select S3C2410_CLOCK | ||
242 | select S3C2410_GPIO | ||
243 | select S3C2410_PM if PM | ||
244 | select CPU_S3C244X | ||
245 | help | ||
246 | Support for S3C2442 Samsung Mobile CPU based systems. | ||
247 | |||
248 | comment "S3C2410 Boot" | ||
249 | |||
250 | config S3C2410_BOOT_WATCHDOG | ||
251 | bool "S3C2410 Initialisation watchdog" | ||
252 | depends on ARCH_S3C2410 && S3C2410_WATCHDOG | ||
253 | help | ||
254 | Say y to enable the watchdog during the kernel decompression | ||
255 | stage. If the kernel fails to uncompress, then the watchdog | ||
256 | will trigger a reset and the system should restart. | ||
257 | |||
258 | Although this uses the same hardware unit as the kernel watchdog | ||
259 | driver, it is not a replacement for it. If you use this option, | ||
260 | you will have to use the watchdg driver to either stop the timeout | ||
261 | or restart it. If you do not, then your kernel will reboot after | ||
262 | startup. | ||
263 | |||
264 | The driver uses a fixed timeout value, so the exact time till the | ||
265 | system resets depends on the value of PCLK. The timeout on an | ||
266 | 200MHz s3c2410 should be about 30 seconds. | ||
267 | |||
268 | config S3C2410_BOOT_ERROR_RESET | ||
269 | bool "S3C2410 Reboot on decompression error" | ||
270 | depends on ARCH_S3C2410 | ||
271 | help | ||
272 | Say y here to use the watchdog to reset the system if the | ||
273 | kernel decompressor detects an error during decompression. | ||
274 | |||
275 | |||
276 | comment "S3C2410 Setup" | ||
277 | |||
278 | config S3C2410_DMA | ||
279 | bool "S3C2410 DMA support" | ||
280 | depends on ARCH_S3C2410 | ||
281 | help | ||
282 | S3C2410 DMA support. This is needed for drivers like sound which | ||
283 | use the S3C2410's DMA system to move data to and from the | ||
284 | peripheral blocks. | ||
285 | |||
286 | config S3C2410_DMA_DEBUG | ||
287 | bool "S3C2410 DMA support debug" | ||
288 | depends on ARCH_S3C2410 && S3C2410_DMA | ||
289 | help | ||
290 | Enable debugging output for the DMA code. This option sends info | ||
291 | to the kernel log, at priority KERN_DEBUG. | ||
292 | |||
293 | Note, it is easy to create and fill the log buffer in a small | ||
294 | amount of time, as well as using an significant percentage of | ||
295 | the CPU time doing so. | ||
296 | |||
297 | config S3C2410_PM_DEBUG | ||
298 | bool "S3C2410 PM Suspend debug" | ||
299 | depends on ARCH_S3C2410 && PM | ||
300 | help | ||
301 | Say Y here if you want verbose debugging from the PM Suspend and | ||
302 | Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> | ||
303 | for more information. | ||
304 | |||
305 | config S3C2410_PM_CHECK | ||
306 | bool "S3C2410 PM Suspend Memory CRC" | ||
307 | depends on ARCH_S3C2410 && PM && CRC32 | ||
308 | help | ||
309 | Enable the PM code's memory area checksum over sleep. This option | ||
310 | will generate CRCs of all blocks of memory, and store them before | ||
311 | going to sleep. The blocks are then checked on resume for any | ||
312 | errors. | ||
313 | |||
314 | config S3C2410_PM_CHECK_CHUNKSIZE | ||
315 | int "S3C2410 PM Suspend CRC Chunksize (KiB)" | ||
316 | depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK | ||
317 | default 64 | ||
318 | help | ||
319 | Set the chunksize in Kilobytes of the CRC for checking memory | ||
320 | corruption over suspend and resume. A smaller value will mean that | ||
321 | the CRC data block will take more memory, but wil identify any | ||
322 | faults with better precision. | ||
323 | |||
324 | config PM_SIMTEC | ||
325 | bool | ||
326 | help | ||
327 | Common power management code for systems that are | ||
328 | compatible with the Simtec style of power management | ||
329 | |||
330 | config S3C2410_LOWLEVEL_UART_PORT | ||
331 | int "S3C2410 UART to use for low-level messages" | ||
332 | default 0 | ||
333 | help | ||
334 | Choice of which UART port to use for the low-level messages, | ||
335 | such as the `Uncompressing...` at start time. The value of | ||
336 | this configuration should be between zero and two. The port | ||
337 | must have been initialised by the boot-loader before use. | ||
338 | |||
339 | Note, this does not affect the port used by the debug messages, | ||
340 | which is a separate configuration. | ||
341 | |||
342 | endif | ||
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 1cc5febdaabd..b33ac5b84773 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile | |||
@@ -1,85 +1,30 @@ | |||
1 | 1 | # arch/arm/mach-s3c2410/Makefile | |
2 | # | 2 | # |
3 | # Makefile for the linux kernel. | 3 | # Copyright 2007 Simtec Electronics |
4 | # | 4 | # |
5 | # Licensed under GPLv2 | ||
5 | 6 | ||
6 | # Object file lists. | 7 | obj-y := |
7 | 8 | obj-m := | |
8 | obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o | 9 | obj-n := |
9 | obj-m := | 10 | obj- := |
10 | obj-n := | ||
11 | obj- := | ||
12 | |||
13 | # DMA | ||
14 | obj-$(CONFIG_S3C2410_DMA) += dma.o | ||
15 | |||
16 | # S3C2400 support files | ||
17 | obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o | ||
18 | |||
19 | # S3C2410 support files | ||
20 | 11 | ||
21 | obj-$(CONFIG_CPU_S3C2410) += s3c2410.o | 12 | obj-$(CONFIG_CPU_S3C2410) += s3c2410.o |
22 | obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o | 13 | obj-$(CONFIG_CPU_S3C2410) += irq.o |
23 | 14 | obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o | |
24 | obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o | 15 | obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o |
25 | obj-$(CONFIG_S3C2410_GPIO) += s3c2410-gpio.o | 16 | obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o |
26 | obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o | 17 | obj-$(CONFIG_S3C2410_GPIO) += gpio.o |
27 | 18 | obj-$(CONFIG_S3C2410_CLOCK) += clock.o | |
28 | # Power Management support | ||
29 | |||
30 | obj-$(CONFIG_PM) += pm.o sleep.o | ||
31 | obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o | ||
32 | obj-$(CONFIG_PM_H1940) += pm-h1940.o | ||
33 | |||
34 | # S3C2412 support | ||
35 | obj-$(CONFIG_CPU_S3C2412) += s3c2412.o | ||
36 | obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o | ||
37 | obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o | ||
38 | |||
39 | obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o | ||
40 | obj-$(CONFIG_S3C2412_DMA) += s3c2412-dma.o | ||
41 | |||
42 | # | ||
43 | # S3C244X support | ||
44 | |||
45 | obj-$(CONFIG_CPU_S3C244X) += s3c244x.o | ||
46 | obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o | ||
47 | |||
48 | # Clock control | ||
49 | |||
50 | obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o | ||
51 | |||
52 | # S3C2440 support | ||
53 | 19 | ||
54 | obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o | 20 | # Machine support |
55 | obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o | ||
56 | obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o | ||
57 | obj-$(CONFIG_S3C2440_DMA) += s3c2440-dma.o | ||
58 | 21 | ||
59 | # S3C2442 support | 22 | obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o |
60 | |||
61 | obj-$(CONFIG_CPU_S3C2442) += s3c2442.o | ||
62 | obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o | ||
63 | |||
64 | # bast extras | ||
65 | |||
66 | obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o | ||
67 | |||
68 | # machine specific support | ||
69 | |||
70 | obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o | ||
71 | obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o | ||
72 | obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o | ||
73 | obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o | ||
74 | obj-$(CONFIG_ARCH_H1940) += mach-h1940.o | 23 | obj-$(CONFIG_ARCH_H1940) += mach-h1940.o |
24 | obj-$(CONFIG_PM_H1940) += pm-h1940.o | ||
75 | obj-$(CONFIG_MACH_N30) += mach-n30.o | 25 | obj-$(CONFIG_MACH_N30) += mach-n30.o |
76 | obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o | 26 | obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o |
77 | obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o | ||
78 | obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o | ||
79 | obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o | ||
80 | obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o | ||
81 | obj-$(CONFIG_MACH_OTOM) += mach-otom.o | 27 | obj-$(CONFIG_MACH_OTOM) += mach-otom.o |
82 | obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o | 28 | obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o |
83 | obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o | 29 | obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o |
84 | 30 | obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o | |
85 | obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file | ||
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c index 379efe70778c..daeba427d781 100644 --- a/arch/arm/mach-s3c2410/bast-irq.c +++ b/arch/arm/mach-s3c2410/bast-irq.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/arch/bast-map.h> | 39 | #include <asm/arch/bast-map.h> |
40 | #include <asm/arch/bast-irq.h> | 40 | #include <asm/arch/bast-irq.h> |
41 | 41 | ||
42 | #include "irq.h" | 42 | #include <asm/plat-s3c24xx/irq.h> |
43 | 43 | ||
44 | #if 0 | 44 | #if 0 |
45 | #include <asm/debug-ll.h> | 45 | #include <asm/debug-ll.h> |
diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h index e5d03311752c..e98543742eb9 100644 --- a/arch/arm/mach-s3c2410/bast.h +++ b/arch/arm/mach-s3c2410/bast.h | |||
@@ -1,2 +1,2 @@ | |||
1 | 1 | /* linux/arch/arm/mach-s3c2410/bast.h | |
2 | extern void bast_init_irq(void); | 2 | extern void bast_init_irq(void); |
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index e13fb6778890..5b4831c4c1d8 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c | |||
@@ -1,15 +1,9 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/clock.c | 1 | /* linux/arch/arm/mach-s3c2410/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C24XX Core clock control support | 6 | * S3C2410,S3C2440,S3C2442 Clock control support |
7 | * | ||
8 | * Based on, and code from linux/arch/arm/mach-versatile/clock.c | ||
9 | ** | ||
10 | ** Copyright (C) 2004 ARM Limited. | ||
11 | ** Written by Deep Blue Solutions Limited. | ||
12 | * | ||
13 | * | 7 | * |
14 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -32,418 +26,251 @@ | |||
32 | #include <linux/list.h> | 26 | #include <linux/list.h> |
33 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
34 | #include <linux/err.h> | 28 | #include <linux/err.h> |
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/sysdev.h> | 29 | #include <linux/sysdev.h> |
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/ioport.h> | ||
39 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
40 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
41 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/serial_core.h> | ||
34 | |||
35 | #include <asm/mach/map.h> | ||
42 | 36 | ||
43 | #include <asm/hardware.h> | 37 | #include <asm/hardware.h> |
44 | #include <asm/irq.h> | ||
45 | #include <asm/io.h> | 38 | #include <asm/io.h> |
46 | 39 | ||
40 | #include <asm/arch/regs-serial.h> | ||
47 | #include <asm/arch/regs-clock.h> | 41 | #include <asm/arch/regs-clock.h> |
48 | #include <asm/arch/regs-gpio.h> | 42 | #include <asm/arch/regs-gpio.h> |
49 | 43 | ||
50 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/s3c2410.h> |
51 | #include "cpu.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
52 | 46 | #include <asm/plat-s3c24xx/cpu.h> | |
53 | /* clock information */ | ||
54 | 47 | ||
55 | static LIST_HEAD(clocks); | 48 | int s3c2410_clkcon_enable(struct clk *clk, int enable) |
56 | |||
57 | DEFINE_MUTEX(clocks_mutex); | ||
58 | |||
59 | /* enable and disable calls for use with the clk struct */ | ||
60 | |||
61 | static int clk_null_enable(struct clk *clk, int enable) | ||
62 | { | 49 | { |
63 | return 0; | 50 | unsigned int clocks = clk->ctrlbit; |
64 | } | 51 | unsigned long clkcon; |
65 | |||
66 | /* Clock API calls */ | ||
67 | 52 | ||
68 | struct clk *clk_get(struct device *dev, const char *id) | 53 | clkcon = __raw_readl(S3C2410_CLKCON); |
69 | { | ||
70 | struct clk *p; | ||
71 | struct clk *clk = ERR_PTR(-ENOENT); | ||
72 | int idno; | ||
73 | 54 | ||
74 | if (dev == NULL || dev->bus != &platform_bus_type) | 55 | if (enable) |
75 | idno = -1; | 56 | clkcon |= clocks; |
76 | else | 57 | else |
77 | idno = to_platform_device(dev)->id; | 58 | clkcon &= ~clocks; |
78 | |||
79 | mutex_lock(&clocks_mutex); | ||
80 | |||
81 | list_for_each_entry(p, &clocks, list) { | ||
82 | if (p->id == idno && | ||
83 | strcmp(id, p->name) == 0 && | ||
84 | try_module_get(p->owner)) { | ||
85 | clk = p; | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* check for the case where a device was supplied, but the | ||
91 | * clock that was being searched for is not device specific */ | ||
92 | |||
93 | if (IS_ERR(clk)) { | ||
94 | list_for_each_entry(p, &clocks, list) { | ||
95 | if (p->id == -1 && strcmp(id, p->name) == 0 && | ||
96 | try_module_get(p->owner)) { | ||
97 | clk = p; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | 59 | ||
103 | mutex_unlock(&clocks_mutex); | 60 | /* ensure none of the special function bits set */ |
104 | return clk; | 61 | clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); |
105 | } | ||
106 | 62 | ||
107 | void clk_put(struct clk *clk) | 63 | __raw_writel(clkcon, S3C2410_CLKCON); |
108 | { | ||
109 | module_put(clk->owner); | ||
110 | } | ||
111 | 64 | ||
112 | int clk_enable(struct clk *clk) | ||
113 | { | ||
114 | if (IS_ERR(clk) || clk == NULL) | ||
115 | return -EINVAL; | ||
116 | |||
117 | clk_enable(clk->parent); | ||
118 | |||
119 | mutex_lock(&clocks_mutex); | ||
120 | |||
121 | if ((clk->usage++) == 0) | ||
122 | (clk->enable)(clk, 1); | ||
123 | |||
124 | mutex_unlock(&clocks_mutex); | ||
125 | return 0; | 65 | return 0; |
126 | } | 66 | } |
127 | 67 | ||
128 | void clk_disable(struct clk *clk) | 68 | static int s3c2410_upll_enable(struct clk *clk, int enable) |
129 | { | ||
130 | if (IS_ERR(clk) || clk == NULL) | ||
131 | return; | ||
132 | |||
133 | mutex_lock(&clocks_mutex); | ||
134 | |||
135 | if ((--clk->usage) == 0) | ||
136 | (clk->enable)(clk, 0); | ||
137 | |||
138 | mutex_unlock(&clocks_mutex); | ||
139 | clk_disable(clk->parent); | ||
140 | } | ||
141 | |||
142 | |||
143 | unsigned long clk_get_rate(struct clk *clk) | ||
144 | { | ||
145 | if (IS_ERR(clk)) | ||
146 | return 0; | ||
147 | |||
148 | if (clk->rate != 0) | ||
149 | return clk->rate; | ||
150 | |||
151 | if (clk->get_rate != NULL) | ||
152 | return (clk->get_rate)(clk); | ||
153 | |||
154 | if (clk->parent != NULL) | ||
155 | return clk_get_rate(clk->parent); | ||
156 | |||
157 | return clk->rate; | ||
158 | } | ||
159 | |||
160 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
161 | { | ||
162 | if (!IS_ERR(clk) && clk->round_rate) | ||
163 | return (clk->round_rate)(clk, rate); | ||
164 | |||
165 | return rate; | ||
166 | } | ||
167 | |||
168 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | if (IS_ERR(clk)) | ||
173 | return -EINVAL; | ||
174 | |||
175 | mutex_lock(&clocks_mutex); | ||
176 | ret = (clk->set_rate)(clk, rate); | ||
177 | mutex_unlock(&clocks_mutex); | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | struct clk *clk_get_parent(struct clk *clk) | ||
183 | { | 69 | { |
184 | return clk->parent; | 70 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); |
185 | } | 71 | unsigned long orig = clkslow; |
186 | |||
187 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
188 | { | ||
189 | int ret = 0; | ||
190 | |||
191 | if (IS_ERR(clk)) | ||
192 | return -EINVAL; | ||
193 | |||
194 | mutex_lock(&clocks_mutex); | ||
195 | |||
196 | if (clk->set_parent) | ||
197 | ret = (clk->set_parent)(clk, parent); | ||
198 | |||
199 | mutex_unlock(&clocks_mutex); | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | EXPORT_SYMBOL(clk_get); | ||
205 | EXPORT_SYMBOL(clk_put); | ||
206 | EXPORT_SYMBOL(clk_enable); | ||
207 | EXPORT_SYMBOL(clk_disable); | ||
208 | EXPORT_SYMBOL(clk_get_rate); | ||
209 | EXPORT_SYMBOL(clk_round_rate); | ||
210 | EXPORT_SYMBOL(clk_set_rate); | ||
211 | EXPORT_SYMBOL(clk_get_parent); | ||
212 | EXPORT_SYMBOL(clk_set_parent); | ||
213 | |||
214 | /* base clocks */ | ||
215 | |||
216 | struct clk clk_xtal = { | ||
217 | .name = "xtal", | ||
218 | .id = -1, | ||
219 | .rate = 0, | ||
220 | .parent = NULL, | ||
221 | .ctrlbit = 0, | ||
222 | }; | ||
223 | |||
224 | struct clk clk_mpll = { | ||
225 | .name = "mpll", | ||
226 | .id = -1, | ||
227 | }; | ||
228 | |||
229 | struct clk clk_upll = { | ||
230 | .name = "upll", | ||
231 | .id = -1, | ||
232 | .parent = NULL, | ||
233 | .ctrlbit = 0, | ||
234 | }; | ||
235 | |||
236 | struct clk clk_f = { | ||
237 | .name = "fclk", | ||
238 | .id = -1, | ||
239 | .rate = 0, | ||
240 | .parent = &clk_mpll, | ||
241 | .ctrlbit = 0, | ||
242 | }; | ||
243 | |||
244 | struct clk clk_h = { | ||
245 | .name = "hclk", | ||
246 | .id = -1, | ||
247 | .rate = 0, | ||
248 | .parent = NULL, | ||
249 | .ctrlbit = 0, | ||
250 | }; | ||
251 | |||
252 | struct clk clk_p = { | ||
253 | .name = "pclk", | ||
254 | .id = -1, | ||
255 | .rate = 0, | ||
256 | .parent = NULL, | ||
257 | .ctrlbit = 0, | ||
258 | }; | ||
259 | |||
260 | struct clk clk_usb_bus = { | ||
261 | .name = "usb-bus", | ||
262 | .id = -1, | ||
263 | .rate = 0, | ||
264 | .parent = &clk_upll, | ||
265 | }; | ||
266 | |||
267 | /* clocks that could be registered by external code */ | ||
268 | |||
269 | static int s3c24xx_dclk_enable(struct clk *clk, int enable) | ||
270 | { | ||
271 | unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
272 | 72 | ||
273 | if (enable) | 73 | if (enable) |
274 | dclkcon |= clk->ctrlbit; | 74 | clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; |
275 | else | 75 | else |
276 | dclkcon &= ~clk->ctrlbit; | 76 | clkslow |= S3C2410_CLKSLOW_UCLK_OFF; |
277 | 77 | ||
278 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | 78 | __raw_writel(clkslow, S3C2410_CLKSLOW); |
279 | 79 | ||
280 | return 0; | 80 | /* if we started the UPLL, then allow to settle */ |
281 | } | ||
282 | 81 | ||
283 | static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) | 82 | if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) |
284 | { | 83 | udelay(200); |
285 | unsigned long dclkcon; | ||
286 | unsigned int uclk; | ||
287 | |||
288 | if (parent == &clk_upll) | ||
289 | uclk = 1; | ||
290 | else if (parent == &clk_p) | ||
291 | uclk = 0; | ||
292 | else | ||
293 | return -EINVAL; | ||
294 | |||
295 | clk->parent = parent; | ||
296 | |||
297 | dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
298 | |||
299 | if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { | ||
300 | if (uclk) | ||
301 | dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; | ||
302 | else | ||
303 | dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; | ||
304 | } else { | ||
305 | if (uclk) | ||
306 | dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; | ||
307 | else | ||
308 | dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; | ||
309 | } | ||
310 | |||
311 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | ||
312 | 84 | ||
313 | return 0; | 85 | return 0; |
314 | } | 86 | } |
315 | 87 | ||
316 | 88 | /* standard clock definitions */ | |
317 | static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) | 89 | |
318 | { | 90 | static struct clk init_clocks_disable[] = { |
319 | unsigned long mask; | 91 | { |
320 | unsigned long source; | 92 | .name = "nand", |
321 | 93 | .id = -1, | |
322 | /* calculate the MISCCR setting for the clock */ | 94 | .parent = &clk_h, |
323 | 95 | .enable = s3c2410_clkcon_enable, | |
324 | if (parent == &clk_xtal) | 96 | .ctrlbit = S3C2410_CLKCON_NAND, |
325 | source = S3C2410_MISCCR_CLK0_MPLL; | 97 | }, { |
326 | else if (parent == &clk_upll) | 98 | .name = "sdi", |
327 | source = S3C2410_MISCCR_CLK0_UPLL; | 99 | .id = -1, |
328 | else if (parent == &clk_f) | 100 | .parent = &clk_p, |
329 | source = S3C2410_MISCCR_CLK0_FCLK; | 101 | .enable = s3c2410_clkcon_enable, |
330 | else if (parent == &clk_h) | 102 | .ctrlbit = S3C2410_CLKCON_SDI, |
331 | source = S3C2410_MISCCR_CLK0_HCLK; | 103 | }, { |
332 | else if (parent == &clk_p) | 104 | .name = "adc", |
333 | source = S3C2410_MISCCR_CLK0_PCLK; | 105 | .id = -1, |
334 | else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) | 106 | .parent = &clk_p, |
335 | source = S3C2410_MISCCR_CLK0_DCLK0; | 107 | .enable = s3c2410_clkcon_enable, |
336 | else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) | 108 | .ctrlbit = S3C2410_CLKCON_ADC, |
337 | source = S3C2410_MISCCR_CLK0_DCLK0; | 109 | }, { |
338 | else | 110 | .name = "i2c", |
339 | return -EINVAL; | 111 | .id = -1, |
340 | 112 | .parent = &clk_p, | |
341 | clk->parent = parent; | 113 | .enable = s3c2410_clkcon_enable, |
342 | 114 | .ctrlbit = S3C2410_CLKCON_IIC, | |
343 | if (clk == &s3c24xx_dclk0) | 115 | }, { |
344 | mask = S3C2410_MISCCR_CLK0_MASK; | 116 | .name = "iis", |
345 | else { | 117 | .id = -1, |
346 | source <<= 4; | 118 | .parent = &clk_p, |
347 | mask = S3C2410_MISCCR_CLK1_MASK; | 119 | .enable = s3c2410_clkcon_enable, |
120 | .ctrlbit = S3C2410_CLKCON_IIS, | ||
121 | }, { | ||
122 | .name = "spi", | ||
123 | .id = -1, | ||
124 | .parent = &clk_p, | ||
125 | .enable = s3c2410_clkcon_enable, | ||
126 | .ctrlbit = S3C2410_CLKCON_SPI, | ||
348 | } | 127 | } |
349 | |||
350 | s3c2410_modify_misccr(mask, source); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* external clock definitions */ | ||
355 | |||
356 | struct clk s3c24xx_dclk0 = { | ||
357 | .name = "dclk0", | ||
358 | .id = -1, | ||
359 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
360 | .enable = s3c24xx_dclk_enable, | ||
361 | .set_parent = s3c24xx_dclk_setparent, | ||
362 | }; | ||
363 | |||
364 | struct clk s3c24xx_dclk1 = { | ||
365 | .name = "dclk1", | ||
366 | .id = -1, | ||
367 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
368 | .enable = s3c24xx_dclk_enable, | ||
369 | .set_parent = s3c24xx_dclk_setparent, | ||
370 | }; | 128 | }; |
371 | 129 | ||
372 | struct clk s3c24xx_clkout0 = { | 130 | static struct clk init_clocks[] = { |
373 | .name = "clkout0", | 131 | { |
374 | .id = -1, | 132 | .name = "lcd", |
375 | .set_parent = s3c24xx_clkout_setparent, | 133 | .id = -1, |
134 | .parent = &clk_h, | ||
135 | .enable = s3c2410_clkcon_enable, | ||
136 | .ctrlbit = S3C2410_CLKCON_LCDC, | ||
137 | }, { | ||
138 | .name = "gpio", | ||
139 | .id = -1, | ||
140 | .parent = &clk_p, | ||
141 | .enable = s3c2410_clkcon_enable, | ||
142 | .ctrlbit = S3C2410_CLKCON_GPIO, | ||
143 | }, { | ||
144 | .name = "usb-host", | ||
145 | .id = -1, | ||
146 | .parent = &clk_h, | ||
147 | .enable = s3c2410_clkcon_enable, | ||
148 | .ctrlbit = S3C2410_CLKCON_USBH, | ||
149 | }, { | ||
150 | .name = "usb-device", | ||
151 | .id = -1, | ||
152 | .parent = &clk_h, | ||
153 | .enable = s3c2410_clkcon_enable, | ||
154 | .ctrlbit = S3C2410_CLKCON_USBD, | ||
155 | }, { | ||
156 | .name = "timers", | ||
157 | .id = -1, | ||
158 | .parent = &clk_p, | ||
159 | .enable = s3c2410_clkcon_enable, | ||
160 | .ctrlbit = S3C2410_CLKCON_PWMT, | ||
161 | }, { | ||
162 | .name = "uart", | ||
163 | .id = 0, | ||
164 | .parent = &clk_p, | ||
165 | .enable = s3c2410_clkcon_enable, | ||
166 | .ctrlbit = S3C2410_CLKCON_UART0, | ||
167 | }, { | ||
168 | .name = "uart", | ||
169 | .id = 1, | ||
170 | .parent = &clk_p, | ||
171 | .enable = s3c2410_clkcon_enable, | ||
172 | .ctrlbit = S3C2410_CLKCON_UART1, | ||
173 | }, { | ||
174 | .name = "uart", | ||
175 | .id = 2, | ||
176 | .parent = &clk_p, | ||
177 | .enable = s3c2410_clkcon_enable, | ||
178 | .ctrlbit = S3C2410_CLKCON_UART2, | ||
179 | }, { | ||
180 | .name = "rtc", | ||
181 | .id = -1, | ||
182 | .parent = &clk_p, | ||
183 | .enable = s3c2410_clkcon_enable, | ||
184 | .ctrlbit = S3C2410_CLKCON_RTC, | ||
185 | }, { | ||
186 | .name = "watchdog", | ||
187 | .id = -1, | ||
188 | .parent = &clk_p, | ||
189 | .ctrlbit = 0, | ||
190 | }, { | ||
191 | .name = "usb-bus-host", | ||
192 | .id = -1, | ||
193 | .parent = &clk_usb_bus, | ||
194 | }, { | ||
195 | .name = "usb-bus-gadget", | ||
196 | .id = -1, | ||
197 | .parent = &clk_usb_bus, | ||
198 | }, | ||
376 | }; | 199 | }; |
377 | 200 | ||
378 | struct clk s3c24xx_clkout1 = { | 201 | /* s3c2410_baseclk_add() |
379 | .name = "clkout1", | 202 | * |
380 | .id = -1, | 203 | * Add all the clocks used by the s3c2410 or compatible CPUs |
381 | .set_parent = s3c24xx_clkout_setparent, | 204 | * such as the S3C2440 and S3C2442. |
382 | }; | 205 | * |
383 | 206 | * We cannot use a system device as we are needed before any | |
384 | struct clk s3c24xx_uclk = { | 207 | * of the init-calls that initialise the devices are actually |
385 | .name = "uclk", | 208 | * done. |
386 | .id = -1, | 209 | */ |
387 | }; | ||
388 | |||
389 | /* initialise the clock system */ | ||
390 | |||
391 | int s3c24xx_register_clock(struct clk *clk) | ||
392 | { | ||
393 | clk->owner = THIS_MODULE; | ||
394 | |||
395 | if (clk->enable == NULL) | ||
396 | clk->enable = clk_null_enable; | ||
397 | |||
398 | /* add to the list of available clocks */ | ||
399 | |||
400 | mutex_lock(&clocks_mutex); | ||
401 | list_add(&clk->list, &clocks); | ||
402 | mutex_unlock(&clocks_mutex); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* initalise all the clocks */ | ||
408 | 210 | ||
409 | int __init s3c24xx_setup_clocks(unsigned long xtal, | 211 | int __init s3c2410_baseclk_add(void) |
410 | unsigned long fclk, | ||
411 | unsigned long hclk, | ||
412 | unsigned long pclk) | ||
413 | { | 212 | { |
414 | printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); | 213 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); |
214 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | ||
215 | struct clk *clkp; | ||
216 | struct clk *xtal; | ||
217 | int ret; | ||
218 | int ptr; | ||
415 | 219 | ||
416 | /* initialise the main system clocks */ | 220 | clk_upll.enable = s3c2410_upll_enable; |
417 | 221 | ||
418 | clk_xtal.rate = xtal; | 222 | if (s3c24xx_register_clock(&clk_usb_bus) < 0) |
419 | clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); | 223 | printk(KERN_ERR "failed to register usb bus clock\n"); |
420 | 224 | ||
421 | clk_mpll.rate = fclk; | 225 | /* register clocks from clock array */ |
422 | clk_h.rate = hclk; | ||
423 | clk_p.rate = pclk; | ||
424 | clk_f.rate = fclk; | ||
425 | 226 | ||
426 | /* assume uart clocks are correctly setup */ | 227 | clkp = init_clocks; |
228 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
229 | /* ensure that we note the clock state */ | ||
427 | 230 | ||
428 | /* register our clocks */ | 231 | clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; |
429 | 232 | ||
430 | if (s3c24xx_register_clock(&clk_xtal) < 0) | 233 | ret = s3c24xx_register_clock(clkp); |
431 | printk(KERN_ERR "failed to register master xtal\n"); | 234 | if (ret < 0) { |
235 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
236 | clkp->name, ret); | ||
237 | } | ||
238 | } | ||
432 | 239 | ||
433 | if (s3c24xx_register_clock(&clk_mpll) < 0) | 240 | /* We must be careful disabling the clocks we are not intending to |
434 | printk(KERN_ERR "failed to register mpll clock\n"); | 241 | * be using at boot time, as subsytems such as the LCD which do |
242 | * their own DMA requests to the bus can cause the system to lockup | ||
243 | * if they where in the middle of requesting bus access. | ||
244 | * | ||
245 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
246 | * and therefore the bootloader should be careful to not enable | ||
247 | * the LCD clock if it is not needed. | ||
248 | */ | ||
249 | |||
250 | /* install (and disable) the clocks we do not need immediately */ | ||
251 | |||
252 | clkp = init_clocks_disable; | ||
253 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | ||
254 | |||
255 | ret = s3c24xx_register_clock(clkp); | ||
256 | if (ret < 0) { | ||
257 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
258 | clkp->name, ret); | ||
259 | } | ||
435 | 260 | ||
436 | if (s3c24xx_register_clock(&clk_upll) < 0) | 261 | s3c2410_clkcon_enable(clkp, 0); |
437 | printk(KERN_ERR "failed to register upll clock\n"); | 262 | } |
438 | 263 | ||
439 | if (s3c24xx_register_clock(&clk_f) < 0) | 264 | /* show the clock-slow value */ |
440 | printk(KERN_ERR "failed to register cpu fclk\n"); | ||
441 | 265 | ||
442 | if (s3c24xx_register_clock(&clk_h) < 0) | 266 | xtal = clk_get(NULL, "xtal"); |
443 | printk(KERN_ERR "failed to register cpu hclk\n"); | ||
444 | 267 | ||
445 | if (s3c24xx_register_clock(&clk_p) < 0) | 268 | printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", |
446 | printk(KERN_ERR "failed to register cpu pclk\n"); | 269 | print_mhz(clk_get_rate(xtal) / |
270 | ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), | ||
271 | (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", | ||
272 | (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", | ||
273 | (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); | ||
447 | 274 | ||
448 | return 0; | 275 | return 0; |
449 | } | 276 | } |
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c index fa860e716b4f..22c613600caa 100644 --- a/arch/arm/mach-s3c2410/dma.c +++ b/arch/arm/mach-s3c2410/dma.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/dma.c | 1 | /* linux/arch/arm/mach-s3c2410/dma.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003-2005,2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C2410 DMA core | 6 | * S3C2410 DMA selection |
7 | * | 7 | * |
8 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
9 | * | 9 | * |
@@ -12,1430 +12,150 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | 15 | #include <linux/kernel.h> | |
16 | #ifdef CONFIG_S3C2410_DMA_DEBUG | ||
17 | #define DEBUG | ||
18 | #endif | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | 16 | #include <linux/init.h> |
22 | #include <linux/sched.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/sysdev.h> | 17 | #include <linux/sysdev.h> |
26 | #include <linux/slab.h> | 18 | #include <linux/serial_core.h> |
27 | #include <linux/errno.h> | ||
28 | #include <linux/delay.h> | ||
29 | 19 | ||
30 | #include <asm/system.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/hardware.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/dma.h> | 20 | #include <asm/dma.h> |
35 | 21 | #include <asm/arch/dma.h> | |
36 | #include <asm/mach/dma.h> | 22 | #include <asm/plat-s3c24xx/dma.h> |
37 | #include <asm/arch/map.h> | 23 | |
38 | 24 | #include <asm/plat-s3c24xx/cpu.h> | |
39 | #include "dma.h" | 25 | |
40 | 26 | #include <asm/arch/regs-serial.h> | |
41 | /* io map for dma */ | 27 | #include <asm/arch/regs-gpio.h> |
42 | static void __iomem *dma_base; | 28 | #include <asm/arch/regs-ac97.h> |
43 | static struct kmem_cache *dma_kmem; | 29 | #include <asm/arch/regs-mem.h> |
44 | 30 | #include <asm/arch/regs-lcd.h> | |
45 | struct s3c24xx_dma_selection dma_sel; | 31 | #include <asm/arch/regs-sdi.h> |
46 | 32 | #include <asm/arch/regs-iis.h> | |
47 | /* dma channel state information */ | 33 | #include <asm/arch/regs-spi.h> |
48 | struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; | 34 | |
49 | 35 | static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { | |
50 | /* debugging functions */ | 36 | [DMACH_XD0] = { |
51 | 37 | .name = "xdreq0", | |
52 | #define BUF_MAGIC (0xcafebabe) | 38 | .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, |
53 | 39 | }, | |
54 | #define dmawarn(fmt...) printk(KERN_DEBUG fmt) | 40 | [DMACH_XD1] = { |
55 | 41 | .name = "xdreq1", | |
56 | #define dma_regaddr(chan, reg) ((chan)->regs + (reg)) | 42 | .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, |
57 | 43 | }, | |
58 | #if 1 | 44 | [DMACH_SDI] = { |
59 | #define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) | 45 | .name = "sdi", |
60 | #else | 46 | .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, |
61 | static inline void | 47 | .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, |
62 | dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) | 48 | .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, |
63 | { | 49 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, |
64 | pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); | 50 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, |
65 | writel(val, dma_regaddr(chan, reg)); | 51 | }, |
66 | } | 52 | [DMACH_SPI0] = { |
67 | #endif | 53 | .name = "spi0", |
68 | 54 | .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, | |
69 | #define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) | 55 | .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, |
70 | 56 | .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, | |
71 | /* captured register state for debug */ | 57 | }, |
72 | 58 | [DMACH_SPI1] = { | |
73 | struct s3c2410_dma_regstate { | 59 | .name = "spi1", |
74 | unsigned long dcsrc; | 60 | .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, |
75 | unsigned long disrc; | 61 | .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, |
76 | unsigned long dstat; | 62 | .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, |
77 | unsigned long dcon; | 63 | }, |
78 | unsigned long dmsktrig; | 64 | [DMACH_UART0] = { |
65 | .name = "uart0", | ||
66 | .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, | ||
67 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | ||
68 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | ||
69 | }, | ||
70 | [DMACH_UART1] = { | ||
71 | .name = "uart1", | ||
72 | .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, | ||
73 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | ||
74 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | ||
75 | }, | ||
76 | [DMACH_UART2] = { | ||
77 | .name = "uart2", | ||
78 | .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, | ||
79 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | ||
80 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | ||
81 | }, | ||
82 | [DMACH_TIMER] = { | ||
83 | .name = "timer", | ||
84 | .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, | ||
85 | .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, | ||
86 | .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, | ||
87 | }, | ||
88 | [DMACH_I2S_IN] = { | ||
89 | .name = "i2s-sdi", | ||
90 | .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, | ||
91 | .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, | ||
92 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
93 | }, | ||
94 | [DMACH_I2S_OUT] = { | ||
95 | .name = "i2s-sdo", | ||
96 | .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, | ||
97 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
98 | }, | ||
99 | [DMACH_USB_EP1] = { | ||
100 | .name = "usb-ep1", | ||
101 | .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, | ||
102 | }, | ||
103 | [DMACH_USB_EP2] = { | ||
104 | .name = "usb-ep2", | ||
105 | .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, | ||
106 | }, | ||
107 | [DMACH_USB_EP3] = { | ||
108 | .name = "usb-ep3", | ||
109 | .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, | ||
110 | }, | ||
111 | [DMACH_USB_EP4] = { | ||
112 | .name = "usb-ep4", | ||
113 | .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, | ||
114 | }, | ||
79 | }; | 115 | }; |
80 | 116 | ||
81 | #ifdef CONFIG_S3C2410_DMA_DEBUG | 117 | static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, |
82 | 118 | struct s3c24xx_dma_map *map) | |
83 | /* dmadbg_showregs | ||
84 | * | ||
85 | * simple debug routine to print the current state of the dma registers | ||
86 | */ | ||
87 | |||
88 | static void | ||
89 | dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) | ||
90 | { | ||
91 | regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); | ||
92 | regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); | ||
93 | regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); | ||
94 | regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
95 | regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, | ||
100 | struct s3c2410_dma_regstate *regs) | ||
101 | { | ||
102 | printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", | ||
103 | chan->number, fname, line, | ||
104 | regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, | ||
105 | regs->dcon); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) | ||
110 | { | ||
111 | struct s3c2410_dma_regstate state; | ||
112 | |||
113 | dmadbg_capture(chan, &state); | ||
114 | |||
115 | printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", | ||
116 | chan->number, fname, line, chan->load_state, | ||
117 | chan->curr, chan->next, chan->end); | ||
118 | |||
119 | dmadbg_dumpregs(fname, line, chan, &state); | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) | ||
124 | { | ||
125 | struct s3c2410_dma_regstate state; | ||
126 | |||
127 | dmadbg_capture(chan, &state); | ||
128 | dmadbg_dumpregs(fname, line, chan, &state); | ||
129 | } | ||
130 | |||
131 | #define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) | ||
132 | #define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) | ||
133 | #else | ||
134 | #define dbg_showregs(chan) do { } while(0) | ||
135 | #define dbg_showchan(chan) do { } while(0) | ||
136 | #endif /* CONFIG_S3C2410_DMA_DEBUG */ | ||
137 | |||
138 | static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX]; | ||
139 | |||
140 | /* lookup_dma_channel | ||
141 | * | ||
142 | * change the dma channel number given into a real dma channel id | ||
143 | */ | ||
144 | |||
145 | static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) | ||
146 | { | ||
147 | if (channel & DMACH_LOW_LEVEL) | ||
148 | return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; | ||
149 | else | ||
150 | return dma_chan_map[channel]; | ||
151 | } | ||
152 | |||
153 | /* s3c2410_dma_stats_timeout | ||
154 | * | ||
155 | * Update DMA stats from timeout info | ||
156 | */ | ||
157 | |||
158 | static void | ||
159 | s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) | ||
160 | { | 119 | { |
161 | if (stats == NULL) | 120 | chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; |
162 | return; | ||
163 | |||
164 | if (val > stats->timeout_longest) | ||
165 | stats->timeout_longest = val; | ||
166 | if (val < stats->timeout_shortest) | ||
167 | stats->timeout_shortest = val; | ||
168 | |||
169 | stats->timeout_avg += val; | ||
170 | } | 121 | } |
171 | 122 | ||
172 | /* s3c2410_dma_waitforload | 123 | static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { |
173 | * | 124 | .select = s3c2410_dma_select, |
174 | * wait for the DMA engine to load a buffer, and update the state accordingly | 125 | .dcon_mask = 7 << 24, |
175 | */ | 126 | .map = s3c2410_dma_mappings, |
176 | 127 | .map_size = ARRAY_SIZE(s3c2410_dma_mappings), | |
177 | static int | 128 | }; |
178 | s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) | ||
179 | { | ||
180 | int timeout = chan->load_timeout; | ||
181 | int took; | ||
182 | |||
183 | if (chan->load_state != S3C2410_DMALOAD_1LOADED) { | ||
184 | printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | if (chan->stats != NULL) | ||
189 | chan->stats->loads++; | ||
190 | |||
191 | while (--timeout > 0) { | ||
192 | if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { | ||
193 | took = chan->load_timeout - timeout; | ||
194 | |||
195 | s3c2410_dma_stats_timeout(chan->stats, took); | ||
196 | |||
197 | switch (chan->load_state) { | ||
198 | case S3C2410_DMALOAD_1LOADED: | ||
199 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
200 | break; | ||
201 | |||
202 | default: | ||
203 | printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); | ||
204 | } | ||
205 | |||
206 | return 1; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if (chan->stats != NULL) { | ||
211 | chan->stats->timeout_failed++; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | |||
218 | |||
219 | /* s3c2410_dma_loadbuffer | ||
220 | * | ||
221 | * load a buffer, and update the channel state | ||
222 | */ | ||
223 | |||
224 | static inline int | ||
225 | s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, | ||
226 | struct s3c2410_dma_buf *buf) | ||
227 | { | ||
228 | unsigned long reload; | ||
229 | |||
230 | pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", | ||
231 | buf, (unsigned long)buf->data, buf->size); | ||
232 | |||
233 | if (buf == NULL) { | ||
234 | dmawarn("buffer is NULL\n"); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | /* check the state of the channel before we do anything */ | ||
239 | |||
240 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
241 | dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); | ||
242 | } | ||
243 | |||
244 | if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { | ||
245 | dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); | ||
246 | } | ||
247 | |||
248 | /* it would seem sensible if we are the last buffer to not bother | ||
249 | * with the auto-reload bit, so that the DMA engine will not try | ||
250 | * and load another transfer after this one has finished... | ||
251 | */ | ||
252 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
253 | pr_debug("load_state is none, checking for noreload (next=%p)\n", | ||
254 | buf->next); | ||
255 | reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; | ||
256 | } else { | ||
257 | //pr_debug("load_state is %d => autoreload\n", chan->load_state); | ||
258 | reload = S3C2410_DCON_AUTORELOAD; | ||
259 | } | ||
260 | |||
261 | if ((buf->data & 0xf0000000) != 0x30000000) { | ||
262 | dmawarn("dmaload: buffer is %p\n", (void *)buf->data); | ||
263 | } | ||
264 | |||
265 | writel(buf->data, chan->addr_reg); | ||
266 | |||
267 | dma_wrreg(chan, S3C2410_DMA_DCON, | ||
268 | chan->dcon | reload | (buf->size/chan->xfer_unit)); | ||
269 | |||
270 | chan->next = buf->next; | ||
271 | |||
272 | /* update the state of the channel */ | ||
273 | |||
274 | switch (chan->load_state) { | ||
275 | case S3C2410_DMALOAD_NONE: | ||
276 | chan->load_state = S3C2410_DMALOAD_1LOADED; | ||
277 | break; | ||
278 | |||
279 | case S3C2410_DMALOAD_1RUNNING: | ||
280 | chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; | ||
281 | break; | ||
282 | |||
283 | default: | ||
284 | dmawarn("dmaload: unknown state %d in loadbuffer\n", | ||
285 | chan->load_state); | ||
286 | break; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* s3c2410_dma_call_op | ||
293 | * | ||
294 | * small routine to call the op routine with the given op if it has been | ||
295 | * registered | ||
296 | */ | ||
297 | |||
298 | static void | ||
299 | s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) | ||
300 | { | ||
301 | if (chan->op_fn != NULL) { | ||
302 | (chan->op_fn)(chan, op); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* s3c2410_dma_buffdone | ||
307 | * | ||
308 | * small wrapper to check if callback routine needs to be called, and | ||
309 | * if so, call it | ||
310 | */ | ||
311 | |||
312 | static inline void | ||
313 | s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, | ||
314 | enum s3c2410_dma_buffresult result) | ||
315 | { | ||
316 | #if 0 | ||
317 | pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", | ||
318 | chan->callback_fn, buf, buf->id, buf->size, result); | ||
319 | #endif | ||
320 | |||
321 | if (chan->callback_fn != NULL) { | ||
322 | (chan->callback_fn)(chan, buf->id, buf->size, result); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /* s3c2410_dma_start | ||
327 | * | ||
328 | * start a dma channel going | ||
329 | */ | ||
330 | |||
331 | static int s3c2410_dma_start(struct s3c2410_dma_chan *chan) | ||
332 | { | ||
333 | unsigned long tmp; | ||
334 | unsigned long flags; | ||
335 | |||
336 | pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); | ||
337 | |||
338 | local_irq_save(flags); | ||
339 | |||
340 | if (chan->state == S3C2410_DMA_RUNNING) { | ||
341 | pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); | ||
342 | local_irq_restore(flags); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | chan->state = S3C2410_DMA_RUNNING; | ||
347 | |||
348 | /* check wether there is anything to load, and if not, see | ||
349 | * if we can find anything to load | ||
350 | */ | ||
351 | |||
352 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
353 | if (chan->next == NULL) { | ||
354 | printk(KERN_ERR "dma%d: channel has nothing loaded\n", | ||
355 | chan->number); | ||
356 | chan->state = S3C2410_DMA_IDLE; | ||
357 | local_irq_restore(flags); | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
362 | } | ||
363 | |||
364 | dbg_showchan(chan); | ||
365 | |||
366 | /* enable the channel */ | ||
367 | |||
368 | if (!chan->irq_enabled) { | ||
369 | enable_irq(chan->irq); | ||
370 | chan->irq_enabled = 1; | ||
371 | } | ||
372 | |||
373 | /* start the channel going */ | ||
374 | |||
375 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
376 | tmp &= ~S3C2410_DMASKTRIG_STOP; | ||
377 | tmp |= S3C2410_DMASKTRIG_ON; | ||
378 | dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); | ||
379 | |||
380 | pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); | ||
381 | |||
382 | #if 0 | ||
383 | /* the dma buffer loads should take care of clearing the AUTO | ||
384 | * reloading feature */ | ||
385 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
386 | tmp &= ~S3C2410_DCON_NORELOAD; | ||
387 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
388 | #endif | ||
389 | |||
390 | s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); | ||
391 | |||
392 | dbg_showchan(chan); | ||
393 | |||
394 | /* if we've only loaded one buffer onto the channel, then chec | ||
395 | * to see if we have another, and if so, try and load it so when | ||
396 | * the first buffer is finished, the new one will be loaded onto | ||
397 | * the channel */ | ||
398 | |||
399 | if (chan->next != NULL) { | ||
400 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
401 | |||
402 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
403 | pr_debug("%s: buff not yet loaded, no more todo\n", | ||
404 | __FUNCTION__); | ||
405 | } else { | ||
406 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
407 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
408 | } | ||
409 | |||
410 | } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { | ||
411 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | |||
416 | local_irq_restore(flags); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /* s3c2410_dma_canload | ||
422 | * | ||
423 | * work out if we can queue another buffer into the DMA engine | ||
424 | */ | ||
425 | |||
426 | static int | ||
427 | s3c2410_dma_canload(struct s3c2410_dma_chan *chan) | ||
428 | { | ||
429 | if (chan->load_state == S3C2410_DMALOAD_NONE || | ||
430 | chan->load_state == S3C2410_DMALOAD_1RUNNING) | ||
431 | return 1; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* s3c2410_dma_enqueue | ||
437 | * | ||
438 | * queue an given buffer for dma transfer. | ||
439 | * | ||
440 | * id the device driver's id information for this buffer | ||
441 | * data the physical address of the buffer data | ||
442 | * size the size of the buffer in bytes | ||
443 | * | ||
444 | * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART | ||
445 | * is checked, and if set, the channel is started. If this flag isn't set, | ||
446 | * then an error will be returned. | ||
447 | * | ||
448 | * It is possible to queue more than one DMA buffer onto a channel at | ||
449 | * once, and the code will deal with the re-loading of the next buffer | ||
450 | * when necessary. | ||
451 | */ | ||
452 | |||
453 | int s3c2410_dma_enqueue(unsigned int channel, void *id, | ||
454 | dma_addr_t data, int size) | ||
455 | { | ||
456 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
457 | struct s3c2410_dma_buf *buf; | ||
458 | unsigned long flags; | ||
459 | |||
460 | if (chan == NULL) | ||
461 | return -EINVAL; | ||
462 | |||
463 | pr_debug("%s: id=%p, data=%08x, size=%d\n", | ||
464 | __FUNCTION__, id, (unsigned int)data, size); | ||
465 | |||
466 | buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); | ||
467 | if (buf == NULL) { | ||
468 | pr_debug("%s: out of memory (%ld alloc)\n", | ||
469 | __FUNCTION__, (long)sizeof(*buf)); | ||
470 | return -ENOMEM; | ||
471 | } | ||
472 | |||
473 | //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); | ||
474 | //dbg_showchan(chan); | ||
475 | |||
476 | buf->next = NULL; | ||
477 | buf->data = buf->ptr = data; | ||
478 | buf->size = size; | ||
479 | buf->id = id; | ||
480 | buf->magic = BUF_MAGIC; | ||
481 | |||
482 | local_irq_save(flags); | ||
483 | |||
484 | if (chan->curr == NULL) { | ||
485 | /* we've got nothing loaded... */ | ||
486 | pr_debug("%s: buffer %p queued onto empty channel\n", | ||
487 | __FUNCTION__, buf); | ||
488 | |||
489 | chan->curr = buf; | ||
490 | chan->end = buf; | ||
491 | chan->next = NULL; | ||
492 | } else { | ||
493 | pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", | ||
494 | chan->number, __FUNCTION__, buf); | ||
495 | |||
496 | if (chan->end == NULL) | ||
497 | pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", | ||
498 | chan->number, __FUNCTION__, chan); | ||
499 | |||
500 | chan->end->next = buf; | ||
501 | chan->end = buf; | ||
502 | } | ||
503 | |||
504 | /* if necessary, update the next buffer field */ | ||
505 | if (chan->next == NULL) | ||
506 | chan->next = buf; | ||
507 | |||
508 | /* check to see if we can load a buffer */ | ||
509 | if (chan->state == S3C2410_DMA_RUNNING) { | ||
510 | if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { | ||
511 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
512 | printk(KERN_ERR "dma%d: loadbuffer:" | ||
513 | "timeout loading buffer\n", | ||
514 | chan->number); | ||
515 | dbg_showchan(chan); | ||
516 | local_irq_restore(flags); | ||
517 | return -EINVAL; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | while (s3c2410_dma_canload(chan) && chan->next != NULL) { | ||
522 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
523 | } | ||
524 | } else if (chan->state == S3C2410_DMA_IDLE) { | ||
525 | if (chan->flags & S3C2410_DMAF_AUTOSTART) { | ||
526 | s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | local_irq_restore(flags); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | EXPORT_SYMBOL(s3c2410_dma_enqueue); | ||
535 | |||
536 | static inline void | ||
537 | s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) | ||
538 | { | ||
539 | int magicok = (buf->magic == BUF_MAGIC); | ||
540 | |||
541 | buf->magic = -1; | ||
542 | |||
543 | if (magicok) { | ||
544 | kmem_cache_free(dma_kmem, buf); | ||
545 | } else { | ||
546 | printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* s3c2410_dma_lastxfer | ||
551 | * | ||
552 | * called when the system is out of buffers, to ensure that the channel | ||
553 | * is prepared for shutdown. | ||
554 | */ | ||
555 | |||
556 | static inline void | ||
557 | s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) | ||
558 | { | ||
559 | #if 0 | ||
560 | pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", | ||
561 | chan->number, chan->load_state); | ||
562 | #endif | ||
563 | |||
564 | switch (chan->load_state) { | ||
565 | case S3C2410_DMALOAD_NONE: | ||
566 | break; | ||
567 | |||
568 | case S3C2410_DMALOAD_1LOADED: | ||
569 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
570 | /* flag error? */ | ||
571 | printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", | ||
572 | chan->number, __FUNCTION__); | ||
573 | return; | ||
574 | } | ||
575 | break; | ||
576 | |||
577 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
578 | /* I belive in this case we do not have anything to do | ||
579 | * until the next buffer comes along, and we turn off the | ||
580 | * reload */ | ||
581 | return; | ||
582 | |||
583 | default: | ||
584 | pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", | ||
585 | chan->number, chan->load_state); | ||
586 | return; | ||
587 | |||
588 | } | ||
589 | |||
590 | /* hopefully this'll shut the damned thing up after the transfer... */ | ||
591 | dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); | ||
592 | } | ||
593 | |||
594 | |||
595 | #define dmadbg2(x...) | ||
596 | |||
597 | static irqreturn_t | ||
598 | s3c2410_dma_irq(int irq, void *devpw) | ||
599 | { | ||
600 | struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; | ||
601 | struct s3c2410_dma_buf *buf; | ||
602 | |||
603 | buf = chan->curr; | ||
604 | |||
605 | dbg_showchan(chan); | ||
606 | |||
607 | /* modify the channel state */ | ||
608 | |||
609 | switch (chan->load_state) { | ||
610 | case S3C2410_DMALOAD_1RUNNING: | ||
611 | /* TODO - if we are running only one buffer, we probably | ||
612 | * want to reload here, and then worry about the buffer | ||
613 | * callback */ | ||
614 | |||
615 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
616 | break; | ||
617 | |||
618 | case S3C2410_DMALOAD_1LOADED: | ||
619 | /* iirc, we should go back to NONE loaded here, we | ||
620 | * had a buffer, and it was never verified as being | ||
621 | * loaded. | ||
622 | */ | ||
623 | |||
624 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
625 | break; | ||
626 | |||
627 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
628 | /* we'll worry about checking to see if another buffer is | ||
629 | * ready after we've called back the owner. This should | ||
630 | * ensure we do not wait around too long for the DMA | ||
631 | * engine to start the next transfer | ||
632 | */ | ||
633 | |||
634 | chan->load_state = S3C2410_DMALOAD_1LOADED; | ||
635 | break; | ||
636 | |||
637 | case S3C2410_DMALOAD_NONE: | ||
638 | printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", | ||
639 | chan->number); | ||
640 | break; | ||
641 | |||
642 | default: | ||
643 | printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", | ||
644 | chan->number, chan->load_state); | ||
645 | break; | ||
646 | } | ||
647 | |||
648 | if (buf != NULL) { | ||
649 | /* update the chain to make sure that if we load any more | ||
650 | * buffers when we call the callback function, things should | ||
651 | * work properly */ | ||
652 | |||
653 | chan->curr = buf->next; | ||
654 | buf->next = NULL; | ||
655 | |||
656 | if (buf->magic != BUF_MAGIC) { | ||
657 | printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", | ||
658 | chan->number, __FUNCTION__, buf); | ||
659 | return IRQ_HANDLED; | ||
660 | } | ||
661 | |||
662 | s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); | ||
663 | |||
664 | /* free resouces */ | ||
665 | s3c2410_dma_freebuf(buf); | ||
666 | } else { | ||
667 | } | ||
668 | |||
669 | /* only reload if the channel is still running... our buffer done | ||
670 | * routine may have altered the state by requesting the dma channel | ||
671 | * to stop or shutdown... */ | ||
672 | |||
673 | /* todo: check that when the channel is shut-down from inside this | ||
674 | * function, we cope with unsetting reload, etc */ | ||
675 | |||
676 | if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { | ||
677 | unsigned long flags; | ||
678 | |||
679 | switch (chan->load_state) { | ||
680 | case S3C2410_DMALOAD_1RUNNING: | ||
681 | /* don't need to do anything for this state */ | ||
682 | break; | ||
683 | |||
684 | case S3C2410_DMALOAD_NONE: | ||
685 | /* can load buffer immediately */ | ||
686 | break; | ||
687 | |||
688 | case S3C2410_DMALOAD_1LOADED: | ||
689 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
690 | /* flag error? */ | ||
691 | printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", | ||
692 | chan->number, __FUNCTION__); | ||
693 | return IRQ_HANDLED; | ||
694 | } | ||
695 | |||
696 | break; | ||
697 | |||
698 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
699 | goto no_load; | ||
700 | |||
701 | default: | ||
702 | printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", | ||
703 | chan->number, chan->load_state); | ||
704 | return IRQ_HANDLED; | ||
705 | } | ||
706 | |||
707 | local_irq_save(flags); | ||
708 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
709 | local_irq_restore(flags); | ||
710 | } else { | ||
711 | s3c2410_dma_lastxfer(chan); | ||
712 | |||
713 | /* see if we can stop this channel.. */ | ||
714 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
715 | pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", | ||
716 | chan->number, jiffies); | ||
717 | s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, | ||
718 | S3C2410_DMAOP_STOP); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | no_load: | ||
723 | return IRQ_HANDLED; | ||
724 | } | ||
725 | |||
726 | static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); | ||
727 | |||
728 | /* s3c2410_request_dma | ||
729 | * | ||
730 | * get control of an dma channel | ||
731 | */ | ||
732 | |||
733 | int s3c2410_dma_request(unsigned int channel, | ||
734 | struct s3c2410_dma_client *client, | ||
735 | void *dev) | ||
736 | { | ||
737 | struct s3c2410_dma_chan *chan; | ||
738 | unsigned long flags; | ||
739 | int err; | ||
740 | |||
741 | pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", | ||
742 | channel, client->name, dev); | ||
743 | |||
744 | local_irq_save(flags); | ||
745 | |||
746 | chan = s3c2410_dma_map_channel(channel); | ||
747 | if (chan == NULL) { | ||
748 | local_irq_restore(flags); | ||
749 | return -EBUSY; | ||
750 | } | ||
751 | |||
752 | dbg_showchan(chan); | ||
753 | |||
754 | chan->client = client; | ||
755 | chan->in_use = 1; | ||
756 | |||
757 | if (!chan->irq_claimed) { | ||
758 | pr_debug("dma%d: %s : requesting irq %d\n", | ||
759 | channel, __FUNCTION__, chan->irq); | ||
760 | |||
761 | chan->irq_claimed = 1; | ||
762 | local_irq_restore(flags); | ||
763 | |||
764 | err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED, | ||
765 | client->name, (void *)chan); | ||
766 | |||
767 | local_irq_save(flags); | ||
768 | |||
769 | if (err) { | ||
770 | chan->in_use = 0; | ||
771 | chan->irq_claimed = 0; | ||
772 | local_irq_restore(flags); | ||
773 | |||
774 | printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", | ||
775 | client->name, chan->irq, chan->number); | ||
776 | return err; | ||
777 | } | ||
778 | |||
779 | chan->irq_enabled = 1; | ||
780 | } | ||
781 | |||
782 | local_irq_restore(flags); | ||
783 | |||
784 | /* need to setup */ | ||
785 | |||
786 | pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | EXPORT_SYMBOL(s3c2410_dma_request); | ||
792 | |||
793 | /* s3c2410_dma_free | ||
794 | * | ||
795 | * release the given channel back to the system, will stop and flush | ||
796 | * any outstanding transfers, and ensure the channel is ready for the | ||
797 | * next claimant. | ||
798 | * | ||
799 | * Note, although a warning is currently printed if the freeing client | ||
800 | * info is not the same as the registrant's client info, the free is still | ||
801 | * allowed to go through. | ||
802 | */ | ||
803 | 129 | ||
804 | int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) | 130 | static int s3c2410_dma_add(struct sys_device *sysdev) |
805 | { | 131 | { |
806 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | 132 | return s3c24xx_dma_init_map(&s3c2410_dma_sel); |
807 | unsigned long flags; | ||
808 | |||
809 | if (chan == NULL) | ||
810 | return -EINVAL; | ||
811 | |||
812 | local_irq_save(flags); | ||
813 | |||
814 | if (chan->client != client) { | ||
815 | printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", | ||
816 | channel, chan->client, client); | ||
817 | } | ||
818 | |||
819 | /* sort out stopping and freeing the channel */ | ||
820 | |||
821 | if (chan->state != S3C2410_DMA_IDLE) { | ||
822 | pr_debug("%s: need to stop dma channel %p\n", | ||
823 | __FUNCTION__, chan); | ||
824 | |||
825 | /* possibly flush the channel */ | ||
826 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); | ||
827 | } | ||
828 | |||
829 | chan->client = NULL; | ||
830 | chan->in_use = 0; | ||
831 | |||
832 | if (chan->irq_claimed) | ||
833 | free_irq(chan->irq, (void *)chan); | ||
834 | |||
835 | chan->irq_claimed = 0; | ||
836 | |||
837 | if (!(channel & DMACH_LOW_LEVEL)) | ||
838 | dma_chan_map[channel] = NULL; | ||
839 | |||
840 | local_irq_restore(flags); | ||
841 | |||
842 | return 0; | ||
843 | } | 133 | } |
844 | 134 | ||
845 | EXPORT_SYMBOL(s3c2410_dma_free); | 135 | #if defined(CONFIG_CPU_S3C2410) |
846 | 136 | static struct sysdev_driver s3c2410_dma_driver = { | |
847 | static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) | 137 | .add = s3c2410_dma_add, |
848 | { | 138 | }; |
849 | unsigned long flags; | ||
850 | unsigned long tmp; | ||
851 | |||
852 | pr_debug("%s:\n", __FUNCTION__); | ||
853 | |||
854 | dbg_showchan(chan); | ||
855 | |||
856 | local_irq_save(flags); | ||
857 | |||
858 | s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); | ||
859 | |||
860 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
861 | tmp |= S3C2410_DMASKTRIG_STOP; | ||
862 | //tmp &= ~S3C2410_DMASKTRIG_ON; | ||
863 | dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); | ||
864 | |||
865 | #if 0 | ||
866 | /* should also clear interrupts, according to WinCE BSP */ | ||
867 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
868 | tmp |= S3C2410_DCON_NORELOAD; | ||
869 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
870 | #endif | ||
871 | |||
872 | /* should stop do this, or should we wait for flush? */ | ||
873 | chan->state = S3C2410_DMA_IDLE; | ||
874 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
875 | |||
876 | local_irq_restore(flags); | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | 139 | ||
881 | void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) | 140 | static int __init s3c2410_dma_init(void) |
882 | { | 141 | { |
883 | unsigned long tmp; | 142 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver); |
884 | unsigned int timeout = 0x10000; | ||
885 | |||
886 | while (timeout-- > 0) { | ||
887 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
888 | |||
889 | if (!(tmp & S3C2410_DMASKTRIG_ON)) | ||
890 | return; | ||
891 | } | ||
892 | |||
893 | pr_debug("dma%d: failed to stop?\n", chan->number); | ||
894 | } | 143 | } |
895 | 144 | ||
896 | 145 | arch_initcall(s3c2410_dma_init); | |
897 | /* s3c2410_dma_flush | ||
898 | * | ||
899 | * stop the channel, and remove all current and pending transfers | ||
900 | */ | ||
901 | |||
902 | static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) | ||
903 | { | ||
904 | struct s3c2410_dma_buf *buf, *next; | ||
905 | unsigned long flags; | ||
906 | |||
907 | pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number); | ||
908 | |||
909 | dbg_showchan(chan); | ||
910 | |||
911 | local_irq_save(flags); | ||
912 | |||
913 | if (chan->state != S3C2410_DMA_IDLE) { | ||
914 | pr_debug("%s: stopping channel...\n", __FUNCTION__ ); | ||
915 | s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); | ||
916 | } | ||
917 | |||
918 | buf = chan->curr; | ||
919 | if (buf == NULL) | ||
920 | buf = chan->next; | ||
921 | |||
922 | chan->curr = chan->next = chan->end = NULL; | ||
923 | |||
924 | if (buf != NULL) { | ||
925 | for ( ; buf != NULL; buf = next) { | ||
926 | next = buf->next; | ||
927 | |||
928 | pr_debug("%s: free buffer %p, next %p\n", | ||
929 | __FUNCTION__, buf, buf->next); | ||
930 | |||
931 | s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); | ||
932 | s3c2410_dma_freebuf(buf); | ||
933 | } | ||
934 | } | ||
935 | |||
936 | dbg_showregs(chan); | ||
937 | |||
938 | s3c2410_dma_waitforstop(chan); | ||
939 | |||
940 | #if 0 | ||
941 | /* should also clear interrupts, according to WinCE BSP */ | ||
942 | { | ||
943 | unsigned long tmp; | ||
944 | |||
945 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
946 | tmp |= S3C2410_DCON_NORELOAD; | ||
947 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
948 | } | ||
949 | #endif | 146 | #endif |
950 | 147 | ||
951 | dbg_showregs(chan); | 148 | #if defined(CONFIG_CPU_S3C2442) |
952 | 149 | /* S3C2442 DMA contains the same selection table as the S3C2410 */ | |
953 | local_irq_restore(flags); | 150 | static struct sysdev_driver s3c2442_dma_driver = { |
954 | 151 | .add = s3c2410_dma_add, | |
955 | return 0; | ||
956 | } | ||
957 | |||
958 | int | ||
959 | s3c2410_dma_started(struct s3c2410_dma_chan *chan) | ||
960 | { | ||
961 | unsigned long flags; | ||
962 | |||
963 | local_irq_save(flags); | ||
964 | |||
965 | dbg_showchan(chan); | ||
966 | |||
967 | /* if we've only loaded one buffer onto the channel, then chec | ||
968 | * to see if we have another, and if so, try and load it so when | ||
969 | * the first buffer is finished, the new one will be loaded onto | ||
970 | * the channel */ | ||
971 | |||
972 | if (chan->next != NULL) { | ||
973 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
974 | |||
975 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
976 | pr_debug("%s: buff not yet loaded, no more todo\n", | ||
977 | __FUNCTION__); | ||
978 | } else { | ||
979 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
980 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
981 | } | ||
982 | |||
983 | } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { | ||
984 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
985 | } | ||
986 | } | ||
987 | |||
988 | |||
989 | local_irq_restore(flags); | ||
990 | |||
991 | return 0; | ||
992 | |||
993 | } | ||
994 | |||
995 | int | ||
996 | s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op) | ||
997 | { | ||
998 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
999 | |||
1000 | if (chan == NULL) | ||
1001 | return -EINVAL; | ||
1002 | |||
1003 | switch (op) { | ||
1004 | case S3C2410_DMAOP_START: | ||
1005 | return s3c2410_dma_start(chan); | ||
1006 | |||
1007 | case S3C2410_DMAOP_STOP: | ||
1008 | return s3c2410_dma_dostop(chan); | ||
1009 | |||
1010 | case S3C2410_DMAOP_PAUSE: | ||
1011 | case S3C2410_DMAOP_RESUME: | ||
1012 | return -ENOENT; | ||
1013 | |||
1014 | case S3C2410_DMAOP_FLUSH: | ||
1015 | return s3c2410_dma_flush(chan); | ||
1016 | |||
1017 | case S3C2410_DMAOP_STARTED: | ||
1018 | return s3c2410_dma_started(chan); | ||
1019 | |||
1020 | case S3C2410_DMAOP_TIMEOUT: | ||
1021 | return 0; | ||
1022 | |||
1023 | } | ||
1024 | |||
1025 | return -ENOENT; /* unknown, don't bother */ | ||
1026 | } | ||
1027 | |||
1028 | EXPORT_SYMBOL(s3c2410_dma_ctrl); | ||
1029 | |||
1030 | /* DMA configuration for each channel | ||
1031 | * | ||
1032 | * DISRCC -> source of the DMA (AHB,APB) | ||
1033 | * DISRC -> source address of the DMA | ||
1034 | * DIDSTC -> destination of the DMA (AHB,APD) | ||
1035 | * DIDST -> destination address of the DMA | ||
1036 | */ | ||
1037 | |||
1038 | /* s3c2410_dma_config | ||
1039 | * | ||
1040 | * xfersize: size of unit in bytes (1,2,4) | ||
1041 | * dcon: base value of the DCONx register | ||
1042 | */ | ||
1043 | |||
1044 | int s3c2410_dma_config(dmach_t channel, | ||
1045 | int xferunit, | ||
1046 | int dcon) | ||
1047 | { | ||
1048 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1049 | |||
1050 | pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", | ||
1051 | __FUNCTION__, channel, xferunit, dcon); | ||
1052 | |||
1053 | if (chan == NULL) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon); | ||
1057 | |||
1058 | dcon |= chan->dcon & dma_sel.dcon_mask; | ||
1059 | |||
1060 | pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon); | ||
1061 | |||
1062 | switch (xferunit) { | ||
1063 | case 1: | ||
1064 | dcon |= S3C2410_DCON_BYTE; | ||
1065 | break; | ||
1066 | |||
1067 | case 2: | ||
1068 | dcon |= S3C2410_DCON_HALFWORD; | ||
1069 | break; | ||
1070 | |||
1071 | case 4: | ||
1072 | dcon |= S3C2410_DCON_WORD; | ||
1073 | break; | ||
1074 | |||
1075 | default: | ||
1076 | pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); | ||
1077 | return -EINVAL; | ||
1078 | } | ||
1079 | |||
1080 | dcon |= S3C2410_DCON_HWTRIG; | ||
1081 | dcon |= S3C2410_DCON_INTREQ; | ||
1082 | |||
1083 | pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); | ||
1084 | |||
1085 | chan->dcon = dcon; | ||
1086 | chan->xfer_unit = xferunit; | ||
1087 | |||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | EXPORT_SYMBOL(s3c2410_dma_config); | ||
1092 | |||
1093 | int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) | ||
1094 | { | ||
1095 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1096 | |||
1097 | if (chan == NULL) | ||
1098 | return -EINVAL; | ||
1099 | |||
1100 | pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); | ||
1101 | |||
1102 | chan->flags = flags; | ||
1103 | |||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | EXPORT_SYMBOL(s3c2410_dma_setflags); | ||
1108 | |||
1109 | |||
1110 | /* do we need to protect the settings of the fields from | ||
1111 | * irq? | ||
1112 | */ | ||
1113 | |||
1114 | int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) | ||
1115 | { | ||
1116 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1117 | |||
1118 | if (chan == NULL) | ||
1119 | return -EINVAL; | ||
1120 | |||
1121 | pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); | ||
1122 | |||
1123 | chan->op_fn = rtn; | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | EXPORT_SYMBOL(s3c2410_dma_set_opfn); | ||
1129 | |||
1130 | int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) | ||
1131 | { | ||
1132 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1133 | |||
1134 | if (chan == NULL) | ||
1135 | return -EINVAL; | ||
1136 | |||
1137 | pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); | ||
1138 | |||
1139 | chan->callback_fn = rtn; | ||
1140 | |||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); | ||
1145 | |||
1146 | /* s3c2410_dma_devconfig | ||
1147 | * | ||
1148 | * configure the dma source/destination hardware type and address | ||
1149 | * | ||
1150 | * source: S3C2410_DMASRC_HW: source is hardware | ||
1151 | * S3C2410_DMASRC_MEM: source is memory | ||
1152 | * | ||
1153 | * hwcfg: the value for xxxSTCn register, | ||
1154 | * bit 0: 0=increment pointer, 1=leave pointer | ||
1155 | * bit 1: 0=soucre is AHB, 1=soucre is APB | ||
1156 | * | ||
1157 | * devaddr: physical address of the source | ||
1158 | */ | ||
1159 | |||
1160 | int s3c2410_dma_devconfig(int channel, | ||
1161 | enum s3c2410_dmasrc source, | ||
1162 | int hwcfg, | ||
1163 | unsigned long devaddr) | ||
1164 | { | ||
1165 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1166 | |||
1167 | if (chan == NULL) | ||
1168 | return -EINVAL; | ||
1169 | |||
1170 | pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", | ||
1171 | __FUNCTION__, (int)source, hwcfg, devaddr); | ||
1172 | |||
1173 | chan->source = source; | ||
1174 | chan->dev_addr = devaddr; | ||
1175 | |||
1176 | switch (source) { | ||
1177 | case S3C2410_DMASRC_HW: | ||
1178 | /* source is hardware */ | ||
1179 | pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", | ||
1180 | __FUNCTION__, devaddr, hwcfg); | ||
1181 | dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); | ||
1182 | dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); | ||
1183 | dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); | ||
1184 | |||
1185 | chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); | ||
1186 | return 0; | ||
1187 | |||
1188 | case S3C2410_DMASRC_MEM: | ||
1189 | /* source is memory */ | ||
1190 | pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", | ||
1191 | __FUNCTION__, devaddr, hwcfg); | ||
1192 | dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); | ||
1193 | dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); | ||
1194 | dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); | ||
1195 | |||
1196 | chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); | ||
1201 | return -EINVAL; | ||
1202 | } | ||
1203 | |||
1204 | EXPORT_SYMBOL(s3c2410_dma_devconfig); | ||
1205 | |||
1206 | /* s3c2410_dma_getposition | ||
1207 | * | ||
1208 | * returns the current transfer points for the dma source and destination | ||
1209 | */ | ||
1210 | |||
1211 | int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst) | ||
1212 | { | ||
1213 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1214 | |||
1215 | if (chan == NULL) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | if (src != NULL) | ||
1219 | *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); | ||
1220 | |||
1221 | if (dst != NULL) | ||
1222 | *dst = dma_rdreg(chan, S3C2410_DMA_DCDST); | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | EXPORT_SYMBOL(s3c2410_dma_getposition); | ||
1228 | |||
1229 | |||
1230 | /* system device class */ | ||
1231 | |||
1232 | #ifdef CONFIG_PM | ||
1233 | |||
1234 | static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) | ||
1235 | { | ||
1236 | struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev); | ||
1237 | |||
1238 | printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); | ||
1239 | |||
1240 | if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { | ||
1241 | /* the dma channel is still working, which is probably | ||
1242 | * a bad thing to do over suspend/resume. We stop the | ||
1243 | * channel and assume that the client is either going to | ||
1244 | * retry after resume, or that it is broken. | ||
1245 | */ | ||
1246 | |||
1247 | printk(KERN_INFO "dma: stopping channel %d due to suspend\n", | ||
1248 | cp->number); | ||
1249 | |||
1250 | s3c2410_dma_dostop(cp); | ||
1251 | } | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int s3c2410_dma_resume(struct sys_device *dev) | ||
1257 | { | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | #else | ||
1262 | #define s3c2410_dma_suspend NULL | ||
1263 | #define s3c2410_dma_resume NULL | ||
1264 | #endif /* CONFIG_PM */ | ||
1265 | |||
1266 | struct sysdev_class dma_sysclass = { | ||
1267 | set_kset_name("s3c24xx-dma"), | ||
1268 | .suspend = s3c2410_dma_suspend, | ||
1269 | .resume = s3c2410_dma_resume, | ||
1270 | }; | 152 | }; |
1271 | 153 | ||
1272 | /* kmem cache implementation */ | 154 | static int __init s3c2442_dma_init(void) |
1273 | |||
1274 | static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f) | ||
1275 | { | ||
1276 | memset(p, 0, sizeof(struct s3c2410_dma_buf)); | ||
1277 | } | ||
1278 | |||
1279 | /* initialisation code */ | ||
1280 | |||
1281 | static int __init s3c2410_init_dma(void) | ||
1282 | { | ||
1283 | struct s3c2410_dma_chan *cp; | ||
1284 | int channel; | ||
1285 | int ret; | ||
1286 | |||
1287 | printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n"); | ||
1288 | |||
1289 | dma_base = ioremap(S3C24XX_PA_DMA, 0x200); | ||
1290 | if (dma_base == NULL) { | ||
1291 | printk(KERN_ERR "dma failed to remap register block\n"); | ||
1292 | return -ENOMEM; | ||
1293 | } | ||
1294 | |||
1295 | printk("Registering sysclass\n"); | ||
1296 | |||
1297 | ret = sysdev_class_register(&dma_sysclass); | ||
1298 | if (ret != 0) { | ||
1299 | printk(KERN_ERR "dma sysclass registration failed\n"); | ||
1300 | goto err; | ||
1301 | } | ||
1302 | |||
1303 | dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0, | ||
1304 | SLAB_HWCACHE_ALIGN, | ||
1305 | s3c2410_dma_cache_ctor, NULL); | ||
1306 | |||
1307 | if (dma_kmem == NULL) { | ||
1308 | printk(KERN_ERR "dma failed to make kmem cache\n"); | ||
1309 | ret = -ENOMEM; | ||
1310 | goto err; | ||
1311 | } | ||
1312 | |||
1313 | for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { | ||
1314 | cp = &s3c2410_chans[channel]; | ||
1315 | |||
1316 | memset(cp, 0, sizeof(struct s3c2410_dma_chan)); | ||
1317 | |||
1318 | /* dma channel irqs are in order.. */ | ||
1319 | cp->number = channel; | ||
1320 | cp->irq = channel + IRQ_DMA0; | ||
1321 | cp->regs = dma_base + (channel*0x40); | ||
1322 | |||
1323 | /* point current stats somewhere */ | ||
1324 | cp->stats = &cp->stats_store; | ||
1325 | cp->stats_store.timeout_shortest = LONG_MAX; | ||
1326 | |||
1327 | /* basic channel configuration */ | ||
1328 | |||
1329 | cp->load_timeout = 1<<18; | ||
1330 | |||
1331 | /* register system device */ | ||
1332 | |||
1333 | cp->dev.cls = &dma_sysclass; | ||
1334 | cp->dev.id = channel; | ||
1335 | ret = sysdev_register(&cp->dev); | ||
1336 | |||
1337 | printk("DMA channel %d at %p, irq %d\n", | ||
1338 | cp->number, cp->regs, cp->irq); | ||
1339 | } | ||
1340 | |||
1341 | return 0; | ||
1342 | |||
1343 | err: | ||
1344 | kmem_cache_destroy(dma_kmem); | ||
1345 | iounmap(dma_base); | ||
1346 | dma_base = NULL; | ||
1347 | return ret; | ||
1348 | } | ||
1349 | |||
1350 | core_initcall(s3c2410_init_dma); | ||
1351 | |||
1352 | static inline int is_channel_valid(unsigned int channel) | ||
1353 | { | 155 | { |
1354 | return (channel & DMA_CH_VALID); | 156 | return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver); |
1355 | } | 157 | } |
1356 | 158 | ||
1357 | /* s3c2410_dma_map_channel() | 159 | arch_initcall(s3c2442_dma_init); |
1358 | * | 160 | #endif |
1359 | * turn the virtual channel number into a real, and un-used hardware | ||
1360 | * channel. | ||
1361 | * | ||
1362 | * currently this code uses first-free channel from the specified harware | ||
1363 | * map, not taking into account anything that the board setup code may | ||
1364 | * have to say about the likely peripheral set to be in use. | ||
1365 | */ | ||
1366 | |||
1367 | struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) | ||
1368 | { | ||
1369 | struct s3c24xx_dma_map *ch_map; | ||
1370 | struct s3c2410_dma_chan *dmach; | ||
1371 | int ch; | ||
1372 | |||
1373 | if (dma_sel.map == NULL || channel > dma_sel.map_size) | ||
1374 | return NULL; | ||
1375 | |||
1376 | ch_map = dma_sel.map + channel; | ||
1377 | |||
1378 | for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) { | ||
1379 | if (!is_channel_valid(ch_map->channels[ch])) | ||
1380 | continue; | ||
1381 | |||
1382 | if (s3c2410_chans[ch].in_use == 0) { | ||
1383 | printk("mapped channel %d to %d\n", channel, ch); | ||
1384 | break; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | if (ch >= S3C2410_DMA_CHANNELS) | ||
1389 | return NULL; | ||
1390 | |||
1391 | /* update our channel mapping */ | ||
1392 | |||
1393 | dmach = &s3c2410_chans[ch]; | ||
1394 | dma_chan_map[channel] = dmach; | ||
1395 | |||
1396 | /* select the channel */ | ||
1397 | |||
1398 | (dma_sel.select)(dmach, ch_map); | ||
1399 | |||
1400 | return dmach; | ||
1401 | } | ||
1402 | |||
1403 | static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch) | ||
1404 | { | ||
1405 | /* show the channel configuration */ | ||
1406 | |||
1407 | printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name, | ||
1408 | (is_channel_valid(map->channels[0]) ? '0' : '-'), | ||
1409 | (is_channel_valid(map->channels[1]) ? '1' : '-'), | ||
1410 | (is_channel_valid(map->channels[2]) ? '2' : '-'), | ||
1411 | (is_channel_valid(map->channels[3]) ? '3' : '-')); | ||
1412 | } | ||
1413 | |||
1414 | static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) | ||
1415 | { | ||
1416 | if (1) | ||
1417 | s3c24xx_dma_show_ch(map, ch); | ||
1418 | |||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) | ||
1423 | { | ||
1424 | struct s3c24xx_dma_map *nmap; | ||
1425 | size_t map_sz = sizeof(*nmap) * sel->map_size; | ||
1426 | int ptr; | ||
1427 | |||
1428 | nmap = kmalloc(map_sz, GFP_KERNEL); | ||
1429 | if (nmap == NULL) | ||
1430 | return -ENOMEM; | ||
1431 | |||
1432 | memcpy(nmap, sel->map, map_sz); | ||
1433 | memcpy(&dma_sel, sel, sizeof(*sel)); | ||
1434 | |||
1435 | dma_sel.map = nmap; | ||
1436 | |||
1437 | for (ptr = 0; ptr < sel->map_size; ptr++) | ||
1438 | s3c24xx_dma_check_entry(nmap+ptr, ptr); | ||
1439 | 161 | ||
1440 | return 0; | ||
1441 | } | ||
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c index f6fb215bb48c..01e795d1146e 100644 --- a/arch/arm/mach-s3c2410/gpio.c +++ b/arch/arm/mach-s3c2410/gpio.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/gpio.c | 1 | /* linux/arch/arm/mach-s3c2410/gpio.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C24XX GPIO support | 6 | * S3C2410 GPIO support |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 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 | 9 | * it under the terms of the GNU General Public License as published by |
@@ -18,8 +18,7 @@ | |||
18 | * You should have received a copy of the GNU General Public License | 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 | 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 | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | |||
23 | 22 | ||
24 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
@@ -33,156 +32,40 @@ | |||
33 | 32 | ||
34 | #include <asm/arch/regs-gpio.h> | 33 | #include <asm/arch/regs-gpio.h> |
35 | 34 | ||
36 | void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) | 35 | int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, |
37 | { | 36 | unsigned int config) |
38 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
39 | unsigned long mask; | ||
40 | unsigned long con; | ||
41 | unsigned long flags; | ||
42 | |||
43 | if (pin < S3C2410_GPIO_BANKB) { | ||
44 | mask = 1 << S3C2410_GPIO_OFFSET(pin); | ||
45 | } else { | ||
46 | mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; | ||
47 | } | ||
48 | |||
49 | switch (function) { | ||
50 | case S3C2410_GPIO_LEAVE: | ||
51 | mask = 0; | ||
52 | function = 0; | ||
53 | break; | ||
54 | |||
55 | case S3C2410_GPIO_INPUT: | ||
56 | case S3C2410_GPIO_OUTPUT: | ||
57 | case S3C2410_GPIO_SFN2: | ||
58 | case S3C2410_GPIO_SFN3: | ||
59 | if (pin < S3C2410_GPIO_BANKB) { | ||
60 | function -= 1; | ||
61 | function &= 1; | ||
62 | function <<= S3C2410_GPIO_OFFSET(pin); | ||
63 | } else { | ||
64 | function &= 3; | ||
65 | function <<= S3C2410_GPIO_OFFSET(pin)*2; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /* modify the specified register wwith IRQs off */ | ||
70 | |||
71 | local_irq_save(flags); | ||
72 | |||
73 | con = __raw_readl(base + 0x00); | ||
74 | con &= ~mask; | ||
75 | con |= function; | ||
76 | |||
77 | __raw_writel(con, base + 0x00); | ||
78 | |||
79 | local_irq_restore(flags); | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL(s3c2410_gpio_cfgpin); | ||
83 | |||
84 | unsigned int s3c2410_gpio_getcfg(unsigned int pin) | ||
85 | { | ||
86 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
87 | unsigned long val = __raw_readl(base); | ||
88 | |||
89 | if (pin < S3C2410_GPIO_BANKB) { | ||
90 | val >>= S3C2410_GPIO_OFFSET(pin); | ||
91 | val &= 1; | ||
92 | val += 1; | ||
93 | } else { | ||
94 | val >>= S3C2410_GPIO_OFFSET(pin)*2; | ||
95 | val &= 3; | ||
96 | } | ||
97 | |||
98 | return val | S3C2410_GPIO_INPUT; | ||
99 | } | ||
100 | |||
101 | EXPORT_SYMBOL(s3c2410_gpio_getcfg); | ||
102 | |||
103 | void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) | ||
104 | { | 37 | { |
105 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | 38 | void __iomem *reg = S3C24XX_EINFLT0; |
106 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
107 | unsigned long flags; | 39 | unsigned long flags; |
108 | unsigned long up; | 40 | unsigned long val; |
109 | |||
110 | if (pin < S3C2410_GPIO_BANKB) | ||
111 | return; | ||
112 | |||
113 | local_irq_save(flags); | ||
114 | |||
115 | up = __raw_readl(base + 0x08); | ||
116 | up &= ~(1L << offs); | ||
117 | up |= to << offs; | ||
118 | __raw_writel(up, base + 0x08); | ||
119 | 41 | ||
120 | local_irq_restore(flags); | 42 | if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) |
121 | } | 43 | return -1; |
122 | 44 | ||
123 | EXPORT_SYMBOL(s3c2410_gpio_pullup); | 45 | config &= 0xff; |
124 | 46 | ||
125 | void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) | 47 | pin -= S3C2410_GPG8; |
126 | { | 48 | reg += pin & ~3; |
127 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
128 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
129 | unsigned long flags; | ||
130 | unsigned long dat; | ||
131 | 49 | ||
132 | local_irq_save(flags); | 50 | local_irq_save(flags); |
133 | 51 | ||
134 | dat = __raw_readl(base + 0x04); | 52 | /* update filter width and clock source */ |
135 | dat &= ~(1 << offs); | ||
136 | dat |= to << offs; | ||
137 | __raw_writel(dat, base + 0x04); | ||
138 | |||
139 | local_irq_restore(flags); | ||
140 | } | ||
141 | |||
142 | EXPORT_SYMBOL(s3c2410_gpio_setpin); | ||
143 | |||
144 | unsigned int s3c2410_gpio_getpin(unsigned int pin) | ||
145 | { | ||
146 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
147 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
148 | 53 | ||
149 | return __raw_readl(base + 0x04) & (1<< offs); | 54 | val = __raw_readl(reg); |
150 | } | 55 | val &= ~(0xff << ((pin & 3) * 8)); |
56 | val |= config << ((pin & 3) * 8); | ||
57 | __raw_writel(val, reg); | ||
151 | 58 | ||
152 | EXPORT_SYMBOL(s3c2410_gpio_getpin); | 59 | /* update filter enable */ |
153 | 60 | ||
154 | unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) | 61 | val = __raw_readl(S3C24XX_EXTINT2); |
155 | { | 62 | val &= ~(1 << ((pin * 4) + 3)); |
156 | unsigned long flags; | 63 | val |= on << ((pin * 4) + 3); |
157 | unsigned long misccr; | 64 | __raw_writel(val, S3C24XX_EXTINT2); |
158 | 65 | ||
159 | local_irq_save(flags); | ||
160 | misccr = __raw_readl(S3C24XX_MISCCR); | ||
161 | misccr &= ~clear; | ||
162 | misccr ^= change; | ||
163 | __raw_writel(misccr, S3C24XX_MISCCR); | ||
164 | local_irq_restore(flags); | 66 | local_irq_restore(flags); |
165 | 67 | ||
166 | return misccr; | 68 | return 0; |
167 | } | ||
168 | |||
169 | EXPORT_SYMBOL(s3c2410_modify_misccr); | ||
170 | |||
171 | int s3c2410_gpio_getirq(unsigned int pin) | ||
172 | { | ||
173 | if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) | ||
174 | return -1; /* not valid interrupts */ | ||
175 | |||
176 | if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) | ||
177 | return -1; /* not valid pin */ | ||
178 | |||
179 | if (pin < S3C2410_GPF4) | ||
180 | return (pin - S3C2410_GPF0) + IRQ_EINT0; | ||
181 | |||
182 | if (pin < S3C2410_GPG0) | ||
183 | return (pin - S3C2410_GPF4) + IRQ_EINT4; | ||
184 | |||
185 | return (pin - S3C2410_GPG0) + IRQ_EINT8; | ||
186 | } | 69 | } |
187 | 70 | ||
188 | EXPORT_SYMBOL(s3c2410_gpio_getirq); | 71 | EXPORT_SYMBOL(s3c2410_gpio_irqfilter); |
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index 3c0ed7871c55..53cbdaa43ac6 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/irq.c | 1 | /* linux/arch/arm/mach-s3c2410/irq.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
@@ -17,37 +17,6 @@ | |||
17 | * along with this program; if not, write to the Free Software | 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 | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | * | 19 | * |
20 | * Changelog: | ||
21 | * | ||
22 | * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> | ||
23 | * Fixed compile warnings | ||
24 | * | ||
25 | * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> | ||
26 | * Fixed s3c_extirq_type | ||
27 | * | ||
28 | * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> | ||
29 | * Addition of ADC/TC demux | ||
30 | * | ||
31 | * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> | ||
32 | * Fix for set_irq_type() on low EINT numbers | ||
33 | * | ||
34 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
35 | * Tidy up KF's patch and sort out new release | ||
36 | * | ||
37 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
38 | * Add support for power management controls | ||
39 | * | ||
40 | * 04-Nov-2004 Ben Dooks | ||
41 | * Fix standard IRQ wake for EINT0..4 and RTC | ||
42 | * | ||
43 | * 22-Feb-2005 Ben Dooks | ||
44 | * Fixed edge-triggering on ADC IRQ | ||
45 | * | ||
46 | * 28-Jun-2005 Ben Dooks | ||
47 | * Mark IRQ_LCD valid | ||
48 | * | ||
49 | * 25-Jul-2005 Ben Dooks | ||
50 | * Split the S3C2440 IRQ code to seperate file | ||
51 | */ | 20 | */ |
52 | 21 | ||
53 | #include <linux/init.h> | 22 | #include <linux/init.h> |
@@ -57,745 +26,23 @@ | |||
57 | #include <linux/ptrace.h> | 26 | #include <linux/ptrace.h> |
58 | #include <linux/sysdev.h> | 27 | #include <linux/sysdev.h> |
59 | 28 | ||
60 | #include <asm/hardware.h> | 29 | #include <asm/plat-s3c24xx/cpu.h> |
61 | #include <asm/irq.h> | 30 | #include <asm/plat-s3c24xx/pm.h> |
62 | #include <asm/io.h> | ||
63 | |||
64 | #include <asm/mach/irq.h> | ||
65 | |||
66 | #include <asm/arch/regs-irq.h> | ||
67 | #include <asm/arch/regs-gpio.h> | ||
68 | |||
69 | #include "cpu.h" | ||
70 | #include "pm.h" | ||
71 | #include "irq.h" | ||
72 | |||
73 | /* wakeup irq control */ | ||
74 | |||
75 | #ifdef CONFIG_PM | ||
76 | |||
77 | /* state for IRQs over sleep */ | ||
78 | |||
79 | /* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources | ||
80 | * | ||
81 | * set bit to 1 in allow bitfield to enable the wakeup settings on it | ||
82 | */ | ||
83 | |||
84 | unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; | ||
85 | unsigned long s3c_irqwake_intmask = 0xffffffffL; | ||
86 | unsigned long s3c_irqwake_eintallow = 0x0000fff0L; | ||
87 | unsigned long s3c_irqwake_eintmask = 0xffffffffL; | ||
88 | |||
89 | int | ||
90 | s3c_irq_wake(unsigned int irqno, unsigned int state) | ||
91 | { | ||
92 | unsigned long irqbit = 1 << (irqno - IRQ_EINT0); | ||
93 | |||
94 | if (!(s3c_irqwake_intallow & irqbit)) | ||
95 | return -ENOENT; | ||
96 | |||
97 | printk(KERN_INFO "wake %s for irq %d\n", | ||
98 | state ? "enabled" : "disabled", irqno); | ||
99 | |||
100 | if (!state) | ||
101 | s3c_irqwake_intmask |= irqbit; | ||
102 | else | ||
103 | s3c_irqwake_intmask &= ~irqbit; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | s3c_irqext_wake(unsigned int irqno, unsigned int state) | ||
110 | { | ||
111 | unsigned long bit = 1L << (irqno - EXTINT_OFF); | ||
112 | |||
113 | if (!(s3c_irqwake_eintallow & bit)) | ||
114 | return -ENOENT; | ||
115 | |||
116 | printk(KERN_INFO "wake %s for irq %d\n", | ||
117 | state ? "enabled" : "disabled", irqno); | ||
118 | |||
119 | if (!state) | ||
120 | s3c_irqwake_eintmask |= bit; | ||
121 | else | ||
122 | s3c_irqwake_eintmask &= ~bit; | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | #else | ||
128 | #define s3c_irqext_wake NULL | ||
129 | #define s3c_irq_wake NULL | ||
130 | #endif | ||
131 | |||
132 | |||
133 | static void | ||
134 | s3c_irq_mask(unsigned int irqno) | ||
135 | { | ||
136 | unsigned long mask; | ||
137 | |||
138 | irqno -= IRQ_EINT0; | ||
139 | |||
140 | mask = __raw_readl(S3C2410_INTMSK); | ||
141 | mask |= 1UL << irqno; | ||
142 | __raw_writel(mask, S3C2410_INTMSK); | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | s3c_irq_ack(unsigned int irqno) | ||
147 | { | ||
148 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
149 | |||
150 | __raw_writel(bitval, S3C2410_SRCPND); | ||
151 | __raw_writel(bitval, S3C2410_INTPND); | ||
152 | } | ||
153 | |||
154 | static inline void | ||
155 | s3c_irq_maskack(unsigned int irqno) | ||
156 | { | ||
157 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
158 | unsigned long mask; | ||
159 | |||
160 | mask = __raw_readl(S3C2410_INTMSK); | ||
161 | __raw_writel(mask|bitval, S3C2410_INTMSK); | ||
162 | |||
163 | __raw_writel(bitval, S3C2410_SRCPND); | ||
164 | __raw_writel(bitval, S3C2410_INTPND); | ||
165 | } | ||
166 | |||
167 | |||
168 | static void | ||
169 | s3c_irq_unmask(unsigned int irqno) | ||
170 | { | ||
171 | unsigned long mask; | ||
172 | |||
173 | if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) | ||
174 | irqdbf2("s3c_irq_unmask %d\n", irqno); | ||
175 | |||
176 | irqno -= IRQ_EINT0; | ||
177 | |||
178 | mask = __raw_readl(S3C2410_INTMSK); | ||
179 | mask &= ~(1UL << irqno); | ||
180 | __raw_writel(mask, S3C2410_INTMSK); | ||
181 | } | ||
182 | |||
183 | struct irq_chip s3c_irq_level_chip = { | ||
184 | .name = "s3c-level", | ||
185 | .ack = s3c_irq_maskack, | ||
186 | .mask = s3c_irq_mask, | ||
187 | .unmask = s3c_irq_unmask, | ||
188 | .set_wake = s3c_irq_wake | ||
189 | }; | ||
190 | |||
191 | static struct irq_chip s3c_irq_chip = { | ||
192 | .name = "s3c", | ||
193 | .ack = s3c_irq_ack, | ||
194 | .mask = s3c_irq_mask, | ||
195 | .unmask = s3c_irq_unmask, | ||
196 | .set_wake = s3c_irq_wake | ||
197 | }; | ||
198 | |||
199 | static void | ||
200 | s3c_irqext_mask(unsigned int irqno) | ||
201 | { | ||
202 | unsigned long mask; | ||
203 | |||
204 | irqno -= EXTINT_OFF; | ||
205 | |||
206 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
207 | mask |= ( 1UL << irqno); | ||
208 | __raw_writel(mask, S3C24XX_EINTMASK); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | s3c_irqext_ack(unsigned int irqno) | ||
213 | { | ||
214 | unsigned long req; | ||
215 | unsigned long bit; | ||
216 | unsigned long mask; | ||
217 | 31 | ||
218 | bit = 1UL << (irqno - EXTINT_OFF); | 32 | static int s3c2410_irq_add(struct sys_device *sysdev) |
219 | |||
220 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
221 | |||
222 | __raw_writel(bit, S3C24XX_EINTPEND); | ||
223 | |||
224 | req = __raw_readl(S3C24XX_EINTPEND); | ||
225 | req &= ~mask; | ||
226 | |||
227 | /* not sure if we should be acking the parent irq... */ | ||
228 | |||
229 | if (irqno <= IRQ_EINT7 ) { | ||
230 | if ((req & 0xf0) == 0) | ||
231 | s3c_irq_ack(IRQ_EINT4t7); | ||
232 | } else { | ||
233 | if ((req >> 8) == 0) | ||
234 | s3c_irq_ack(IRQ_EINT8t23); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | static void | ||
239 | s3c_irqext_unmask(unsigned int irqno) | ||
240 | { | 33 | { |
241 | unsigned long mask; | ||
242 | |||
243 | irqno -= EXTINT_OFF; | ||
244 | |||
245 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
246 | mask &= ~( 1UL << irqno); | ||
247 | __raw_writel(mask, S3C24XX_EINTMASK); | ||
248 | } | ||
249 | |||
250 | int | ||
251 | s3c_irqext_type(unsigned int irq, unsigned int type) | ||
252 | { | ||
253 | void __iomem *extint_reg; | ||
254 | void __iomem *gpcon_reg; | ||
255 | unsigned long gpcon_offset, extint_offset; | ||
256 | unsigned long newvalue = 0, value; | ||
257 | |||
258 | if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) | ||
259 | { | ||
260 | gpcon_reg = S3C2410_GPFCON; | ||
261 | extint_reg = S3C24XX_EXTINT0; | ||
262 | gpcon_offset = (irq - IRQ_EINT0) * 2; | ||
263 | extint_offset = (irq - IRQ_EINT0) * 4; | ||
264 | } | ||
265 | else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) | ||
266 | { | ||
267 | gpcon_reg = S3C2410_GPFCON; | ||
268 | extint_reg = S3C24XX_EXTINT0; | ||
269 | gpcon_offset = (irq - (EXTINT_OFF)) * 2; | ||
270 | extint_offset = (irq - (EXTINT_OFF)) * 4; | ||
271 | } | ||
272 | else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) | ||
273 | { | ||
274 | gpcon_reg = S3C2410_GPGCON; | ||
275 | extint_reg = S3C24XX_EXTINT1; | ||
276 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
277 | extint_offset = (irq - IRQ_EINT8) * 4; | ||
278 | } | ||
279 | else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) | ||
280 | { | ||
281 | gpcon_reg = S3C2410_GPGCON; | ||
282 | extint_reg = S3C24XX_EXTINT2; | ||
283 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
284 | extint_offset = (irq - IRQ_EINT16) * 4; | ||
285 | } else | ||
286 | return -1; | ||
287 | |||
288 | /* Set the GPIO to external interrupt mode */ | ||
289 | value = __raw_readl(gpcon_reg); | ||
290 | value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); | ||
291 | __raw_writel(value, gpcon_reg); | ||
292 | |||
293 | /* Set the external interrupt to pointed trigger type */ | ||
294 | switch (type) | ||
295 | { | ||
296 | case IRQT_NOEDGE: | ||
297 | printk(KERN_WARNING "No edge setting!\n"); | ||
298 | break; | ||
299 | |||
300 | case IRQT_RISING: | ||
301 | newvalue = S3C2410_EXTINT_RISEEDGE; | ||
302 | break; | ||
303 | |||
304 | case IRQT_FALLING: | ||
305 | newvalue = S3C2410_EXTINT_FALLEDGE; | ||
306 | break; | ||
307 | |||
308 | case IRQT_BOTHEDGE: | ||
309 | newvalue = S3C2410_EXTINT_BOTHEDGE; | ||
310 | break; | ||
311 | |||
312 | case IRQT_LOW: | ||
313 | newvalue = S3C2410_EXTINT_LOWLEV; | ||
314 | break; | ||
315 | |||
316 | case IRQT_HIGH: | ||
317 | newvalue = S3C2410_EXTINT_HILEV; | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | printk(KERN_ERR "No such irq type %d", type); | ||
322 | return -1; | ||
323 | } | ||
324 | |||
325 | value = __raw_readl(extint_reg); | ||
326 | value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); | ||
327 | __raw_writel(value, extint_reg); | ||
328 | |||
329 | return 0; | 34 | return 0; |
330 | } | 35 | } |
331 | 36 | ||
332 | static struct irq_chip s3c_irqext_chip = { | 37 | static struct sysdev_driver s3c2410_irq_driver = { |
333 | .name = "s3c-ext", | 38 | .add = s3c2410_irq_add, |
334 | .mask = s3c_irqext_mask, | 39 | .suspend = s3c24xx_irq_suspend, |
335 | .unmask = s3c_irqext_unmask, | 40 | .resume = s3c24xx_irq_resume, |
336 | .ack = s3c_irqext_ack, | ||
337 | .set_type = s3c_irqext_type, | ||
338 | .set_wake = s3c_irqext_wake | ||
339 | }; | ||
340 | |||
341 | static struct irq_chip s3c_irq_eint0t4 = { | ||
342 | .name = "s3c-ext0", | ||
343 | .ack = s3c_irq_ack, | ||
344 | .mask = s3c_irq_mask, | ||
345 | .unmask = s3c_irq_unmask, | ||
346 | .set_wake = s3c_irq_wake, | ||
347 | .set_type = s3c_irqext_type, | ||
348 | }; | ||
349 | |||
350 | /* mask values for the parent registers for each of the interrupt types */ | ||
351 | |||
352 | #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) | ||
353 | #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) | ||
354 | #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) | ||
355 | #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) | ||
356 | |||
357 | |||
358 | /* UART0 */ | ||
359 | |||
360 | static void | ||
361 | s3c_irq_uart0_mask(unsigned int irqno) | ||
362 | { | ||
363 | s3c_irqsub_mask(irqno, INTMSK_UART0, 7); | ||
364 | } | ||
365 | |||
366 | static void | ||
367 | s3c_irq_uart0_unmask(unsigned int irqno) | ||
368 | { | ||
369 | s3c_irqsub_unmask(irqno, INTMSK_UART0); | ||
370 | } | ||
371 | |||
372 | static void | ||
373 | s3c_irq_uart0_ack(unsigned int irqno) | ||
374 | { | ||
375 | s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); | ||
376 | } | ||
377 | |||
378 | static struct irq_chip s3c_irq_uart0 = { | ||
379 | .name = "s3c-uart0", | ||
380 | .mask = s3c_irq_uart0_mask, | ||
381 | .unmask = s3c_irq_uart0_unmask, | ||
382 | .ack = s3c_irq_uart0_ack, | ||
383 | }; | ||
384 | |||
385 | /* UART1 */ | ||
386 | |||
387 | static void | ||
388 | s3c_irq_uart1_mask(unsigned int irqno) | ||
389 | { | ||
390 | s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); | ||
391 | } | ||
392 | |||
393 | static void | ||
394 | s3c_irq_uart1_unmask(unsigned int irqno) | ||
395 | { | ||
396 | s3c_irqsub_unmask(irqno, INTMSK_UART1); | ||
397 | } | ||
398 | |||
399 | static void | ||
400 | s3c_irq_uart1_ack(unsigned int irqno) | ||
401 | { | ||
402 | s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); | ||
403 | } | ||
404 | |||
405 | static struct irq_chip s3c_irq_uart1 = { | ||
406 | .name = "s3c-uart1", | ||
407 | .mask = s3c_irq_uart1_mask, | ||
408 | .unmask = s3c_irq_uart1_unmask, | ||
409 | .ack = s3c_irq_uart1_ack, | ||
410 | }; | ||
411 | |||
412 | /* UART2 */ | ||
413 | |||
414 | static void | ||
415 | s3c_irq_uart2_mask(unsigned int irqno) | ||
416 | { | ||
417 | s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); | ||
418 | } | ||
419 | |||
420 | static void | ||
421 | s3c_irq_uart2_unmask(unsigned int irqno) | ||
422 | { | ||
423 | s3c_irqsub_unmask(irqno, INTMSK_UART2); | ||
424 | } | ||
425 | |||
426 | static void | ||
427 | s3c_irq_uart2_ack(unsigned int irqno) | ||
428 | { | ||
429 | s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); | ||
430 | } | ||
431 | |||
432 | static struct irq_chip s3c_irq_uart2 = { | ||
433 | .name = "s3c-uart2", | ||
434 | .mask = s3c_irq_uart2_mask, | ||
435 | .unmask = s3c_irq_uart2_unmask, | ||
436 | .ack = s3c_irq_uart2_ack, | ||
437 | }; | ||
438 | |||
439 | /* ADC and Touchscreen */ | ||
440 | |||
441 | static void | ||
442 | s3c_irq_adc_mask(unsigned int irqno) | ||
443 | { | ||
444 | s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
445 | } | ||
446 | |||
447 | static void | ||
448 | s3c_irq_adc_unmask(unsigned int irqno) | ||
449 | { | ||
450 | s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); | ||
451 | } | ||
452 | |||
453 | static void | ||
454 | s3c_irq_adc_ack(unsigned int irqno) | ||
455 | { | ||
456 | s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
457 | } | ||
458 | |||
459 | static struct irq_chip s3c_irq_adc = { | ||
460 | .name = "s3c-adc", | ||
461 | .mask = s3c_irq_adc_mask, | ||
462 | .unmask = s3c_irq_adc_unmask, | ||
463 | .ack = s3c_irq_adc_ack, | ||
464 | }; | ||
465 | |||
466 | /* irq demux for adc */ | ||
467 | static void s3c_irq_demux_adc(unsigned int irq, | ||
468 | struct irq_desc *desc) | ||
469 | { | ||
470 | unsigned int subsrc, submsk; | ||
471 | unsigned int offset = 9; | ||
472 | struct irq_desc *mydesc; | ||
473 | |||
474 | /* read the current pending interrupts, and the mask | ||
475 | * for what it is available */ | ||
476 | |||
477 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
478 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
479 | |||
480 | subsrc &= ~submsk; | ||
481 | subsrc >>= offset; | ||
482 | subsrc &= 3; | ||
483 | |||
484 | if (subsrc != 0) { | ||
485 | if (subsrc & 1) { | ||
486 | mydesc = irq_desc + IRQ_TC; | ||
487 | desc_handle_irq(IRQ_TC, mydesc); | ||
488 | } | ||
489 | if (subsrc & 2) { | ||
490 | mydesc = irq_desc + IRQ_ADC; | ||
491 | desc_handle_irq(IRQ_ADC, mydesc); | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static void s3c_irq_demux_uart(unsigned int start) | ||
497 | { | ||
498 | unsigned int subsrc, submsk; | ||
499 | unsigned int offset = start - IRQ_S3CUART_RX0; | ||
500 | struct irq_desc *desc; | ||
501 | |||
502 | /* read the current pending interrupts, and the mask | ||
503 | * for what it is available */ | ||
504 | |||
505 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
506 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
507 | |||
508 | irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", | ||
509 | start, offset, subsrc, submsk); | ||
510 | |||
511 | subsrc &= ~submsk; | ||
512 | subsrc >>= offset; | ||
513 | subsrc &= 7; | ||
514 | |||
515 | if (subsrc != 0) { | ||
516 | desc = irq_desc + start; | ||
517 | |||
518 | if (subsrc & 1) | ||
519 | desc_handle_irq(start, desc); | ||
520 | |||
521 | desc++; | ||
522 | |||
523 | if (subsrc & 2) | ||
524 | desc_handle_irq(start+1, desc); | ||
525 | |||
526 | desc++; | ||
527 | |||
528 | if (subsrc & 4) | ||
529 | desc_handle_irq(start+2, desc); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* uart demux entry points */ | ||
534 | |||
535 | static void | ||
536 | s3c_irq_demux_uart0(unsigned int irq, | ||
537 | struct irq_desc *desc) | ||
538 | { | ||
539 | irq = irq; | ||
540 | s3c_irq_demux_uart(IRQ_S3CUART_RX0); | ||
541 | } | ||
542 | |||
543 | static void | ||
544 | s3c_irq_demux_uart1(unsigned int irq, | ||
545 | struct irq_desc *desc) | ||
546 | { | ||
547 | irq = irq; | ||
548 | s3c_irq_demux_uart(IRQ_S3CUART_RX1); | ||
549 | } | ||
550 | |||
551 | static void | ||
552 | s3c_irq_demux_uart2(unsigned int irq, | ||
553 | struct irq_desc *desc) | ||
554 | { | ||
555 | irq = irq; | ||
556 | s3c_irq_demux_uart(IRQ_S3CUART_RX2); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | s3c_irq_demux_extint8(unsigned int irq, | ||
561 | struct irq_desc *desc) | ||
562 | { | ||
563 | unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); | ||
564 | unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); | ||
565 | |||
566 | eintpnd &= ~eintmsk; | ||
567 | eintpnd &= ~0xff; /* ignore lower irqs */ | ||
568 | |||
569 | /* we may as well handle all the pending IRQs here */ | ||
570 | |||
571 | while (eintpnd) { | ||
572 | irq = __ffs(eintpnd); | ||
573 | eintpnd &= ~(1<<irq); | ||
574 | |||
575 | irq += (IRQ_EINT4 - 4); | ||
576 | desc_handle_irq(irq, irq_desc + irq); | ||
577 | } | ||
578 | |||
579 | } | ||
580 | |||
581 | static void | ||
582 | s3c_irq_demux_extint4t7(unsigned int irq, | ||
583 | struct irq_desc *desc) | ||
584 | { | ||
585 | unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); | ||
586 | unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); | ||
587 | |||
588 | eintpnd &= ~eintmsk; | ||
589 | eintpnd &= 0xff; /* only lower irqs */ | ||
590 | |||
591 | /* we may as well handle all the pending IRQs here */ | ||
592 | |||
593 | while (eintpnd) { | ||
594 | irq = __ffs(eintpnd); | ||
595 | eintpnd &= ~(1<<irq); | ||
596 | |||
597 | irq += (IRQ_EINT4 - 4); | ||
598 | |||
599 | desc_handle_irq(irq, irq_desc + irq); | ||
600 | } | ||
601 | } | ||
602 | |||
603 | #ifdef CONFIG_PM | ||
604 | |||
605 | static struct sleep_save irq_save[] = { | ||
606 | SAVE_ITEM(S3C2410_INTMSK), | ||
607 | SAVE_ITEM(S3C2410_INTSUBMSK), | ||
608 | }; | 41 | }; |
609 | 42 | ||
610 | /* the extint values move between the s3c2410/s3c2440 and the s3c2412 | 43 | static int s3c2410_irq_init(void) |
611 | * so we use an array to hold them, and to calculate the address of | ||
612 | * the register at run-time | ||
613 | */ | ||
614 | |||
615 | static unsigned long save_extint[3]; | ||
616 | static unsigned long save_eintflt[4]; | ||
617 | static unsigned long save_eintmask; | ||
618 | |||
619 | int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) | ||
620 | { | 44 | { |
621 | unsigned int i; | 45 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); |
622 | |||
623 | for (i = 0; i < ARRAY_SIZE(save_extint); i++) | ||
624 | save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); | ||
625 | |||
626 | for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) | ||
627 | save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); | ||
628 | |||
629 | s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); | ||
630 | save_eintmask = __raw_readl(S3C24XX_EINTMASK); | ||
631 | |||
632 | return 0; | ||
633 | } | 46 | } |
634 | 47 | ||
635 | int s3c24xx_irq_resume(struct sys_device *dev) | 48 | arch_initcall(s3c2410_irq_init); |
636 | { | ||
637 | unsigned int i; | ||
638 | |||
639 | for (i = 0; i < ARRAY_SIZE(save_extint); i++) | ||
640 | __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); | ||
641 | |||
642 | for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) | ||
643 | __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); | ||
644 | |||
645 | s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); | ||
646 | __raw_writel(save_eintmask, S3C24XX_EINTMASK); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | #else | ||
652 | #define s3c24xx_irq_suspend NULL | ||
653 | #define s3c24xx_irq_resume NULL | ||
654 | #endif | ||
655 | |||
656 | /* s3c24xx_init_irq | ||
657 | * | ||
658 | * Initialise S3C2410 IRQ system | ||
659 | */ | ||
660 | |||
661 | void __init s3c24xx_init_irq(void) | ||
662 | { | ||
663 | unsigned long pend; | ||
664 | unsigned long last; | ||
665 | int irqno; | ||
666 | int i; | ||
667 | |||
668 | irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); | ||
669 | |||
670 | /* first, clear all interrupts pending... */ | ||
671 | |||
672 | last = 0; | ||
673 | for (i = 0; i < 4; i++) { | ||
674 | pend = __raw_readl(S3C24XX_EINTPEND); | ||
675 | |||
676 | if (pend == 0 || pend == last) | ||
677 | break; | ||
678 | |||
679 | __raw_writel(pend, S3C24XX_EINTPEND); | ||
680 | printk("irq: clearing pending ext status %08x\n", (int)pend); | ||
681 | last = pend; | ||
682 | } | ||
683 | |||
684 | last = 0; | ||
685 | for (i = 0; i < 4; i++) { | ||
686 | pend = __raw_readl(S3C2410_INTPND); | ||
687 | |||
688 | if (pend == 0 || pend == last) | ||
689 | break; | ||
690 | |||
691 | __raw_writel(pend, S3C2410_SRCPND); | ||
692 | __raw_writel(pend, S3C2410_INTPND); | ||
693 | printk("irq: clearing pending status %08x\n", (int)pend); | ||
694 | last = pend; | ||
695 | } | ||
696 | |||
697 | last = 0; | ||
698 | for (i = 0; i < 4; i++) { | ||
699 | pend = __raw_readl(S3C2410_SUBSRCPND); | ||
700 | |||
701 | if (pend == 0 || pend == last) | ||
702 | break; | ||
703 | |||
704 | printk("irq: clearing subpending status %08x\n", (int)pend); | ||
705 | __raw_writel(pend, S3C2410_SUBSRCPND); | ||
706 | last = pend; | ||
707 | } | ||
708 | |||
709 | /* register the main interrupts */ | ||
710 | |||
711 | irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); | ||
712 | |||
713 | for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { | ||
714 | /* set all the s3c2410 internal irqs */ | ||
715 | |||
716 | switch (irqno) { | ||
717 | /* deal with the special IRQs (cascaded) */ | ||
718 | |||
719 | case IRQ_EINT4t7: | ||
720 | case IRQ_EINT8t23: | ||
721 | case IRQ_UART0: | ||
722 | case IRQ_UART1: | ||
723 | case IRQ_UART2: | ||
724 | case IRQ_ADCPARENT: | ||
725 | set_irq_chip(irqno, &s3c_irq_level_chip); | ||
726 | set_irq_handler(irqno, handle_level_irq); | ||
727 | break; | ||
728 | |||
729 | case IRQ_RESERVED6: | ||
730 | case IRQ_RESERVED24: | ||
731 | /* no IRQ here */ | ||
732 | break; | ||
733 | |||
734 | default: | ||
735 | //irqdbf("registering irq %d (s3c irq)\n", irqno); | ||
736 | set_irq_chip(irqno, &s3c_irq_chip); | ||
737 | set_irq_handler(irqno, handle_edge_irq); | ||
738 | set_irq_flags(irqno, IRQF_VALID); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | /* setup the cascade irq handlers */ | ||
743 | |||
744 | set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); | ||
745 | set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); | ||
746 | |||
747 | set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); | ||
748 | set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); | ||
749 | set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); | ||
750 | set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); | ||
751 | |||
752 | /* external interrupts */ | ||
753 | |||
754 | for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { | ||
755 | irqdbf("registering irq %d (ext int)\n", irqno); | ||
756 | set_irq_chip(irqno, &s3c_irq_eint0t4); | ||
757 | set_irq_handler(irqno, handle_edge_irq); | ||
758 | set_irq_flags(irqno, IRQF_VALID); | ||
759 | } | ||
760 | |||
761 | for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { | ||
762 | irqdbf("registering irq %d (extended s3c irq)\n", irqno); | ||
763 | set_irq_chip(irqno, &s3c_irqext_chip); | ||
764 | set_irq_handler(irqno, handle_edge_irq); | ||
765 | set_irq_flags(irqno, IRQF_VALID); | ||
766 | } | ||
767 | |||
768 | /* register the uart interrupts */ | ||
769 | |||
770 | irqdbf("s3c2410: registering external interrupts\n"); | ||
771 | |||
772 | for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { | ||
773 | irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); | ||
774 | set_irq_chip(irqno, &s3c_irq_uart0); | ||
775 | set_irq_handler(irqno, handle_level_irq); | ||
776 | set_irq_flags(irqno, IRQF_VALID); | ||
777 | } | ||
778 | |||
779 | for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { | ||
780 | irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); | ||
781 | set_irq_chip(irqno, &s3c_irq_uart1); | ||
782 | set_irq_handler(irqno, handle_level_irq); | ||
783 | set_irq_flags(irqno, IRQF_VALID); | ||
784 | } | ||
785 | |||
786 | for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { | ||
787 | irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); | ||
788 | set_irq_chip(irqno, &s3c_irq_uart2); | ||
789 | set_irq_handler(irqno, handle_level_irq); | ||
790 | set_irq_flags(irqno, IRQF_VALID); | ||
791 | } | ||
792 | |||
793 | for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { | ||
794 | irqdbf("registering irq %d (s3c adc irq)\n", irqno); | ||
795 | set_irq_chip(irqno, &s3c_irq_adc); | ||
796 | set_irq_handler(irqno, handle_edge_irq); | ||
797 | set_irq_flags(irqno, IRQF_VALID); | ||
798 | } | ||
799 | |||
800 | irqdbf("s3c2410: registered interrupt handlers\n"); | ||
801 | } | ||
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c index 817e2c684410..d54cda1b3006 100644 --- a/arch/arm/mach-s3c2410/mach-amlm5900.c +++ b/arch/arm/mach-s3c2410/mach-amlm5900.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /*********************************************************************** | 1 | /* linux/arch/arm/mach-s3c2410/mach-amlm5900.c |
2 | * | 2 | * |
3 | * linux/arch/arm/mach-s3c2410/mach-amlm5900.c | 3 | * linux/arch/arm/mach-s3c2410/mach-amlm5900.c |
4 | * | 4 | * |
@@ -52,8 +52,8 @@ | |||
52 | #include <asm/arch/regs-lcd.h> | 52 | #include <asm/arch/regs-lcd.h> |
53 | #include <asm/arch/regs-gpio.h> | 53 | #include <asm/arch/regs-gpio.h> |
54 | 54 | ||
55 | #include "devs.h" | 55 | #include <asm/plat-s3c24xx/devs.h> |
56 | #include "cpu.h" | 56 | #include <asm/plat-s3c24xx/cpu.h> |
57 | 57 | ||
58 | #ifdef CONFIG_MTD_PARTITIONS | 58 | #ifdef CONFIG_MTD_PARTITIONS |
59 | 59 | ||
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index b8b76757ec54..7b81296427eb 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c | |||
@@ -50,9 +50,9 @@ | |||
50 | 50 | ||
51 | #include <linux/serial_8250.h> | 51 | #include <linux/serial_8250.h> |
52 | 52 | ||
53 | #include "clock.h" | 53 | #include <asm/plat-s3c24xx/clock.h> |
54 | #include "devs.h" | 54 | #include <asm/plat-s3c24xx/devs.h> |
55 | #include "cpu.h" | 55 | #include <asm/plat-s3c24xx/cpu.h> |
56 | #include "usb-simtec.h" | 56 | #include "usb-simtec.h" |
57 | 57 | ||
58 | #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" | 58 | #define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" |
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index 15b625eae499..5af26e177966 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c | |||
@@ -38,10 +38,10 @@ | |||
38 | #include <asm/arch/h1940-latch.h> | 38 | #include <asm/arch/h1940-latch.h> |
39 | #include <asm/arch/fb.h> | 39 | #include <asm/arch/fb.h> |
40 | 40 | ||
41 | #include "clock.h" | 41 | #include <asm/plat-s3c24xx/clock.h> |
42 | #include "devs.h" | 42 | #include <asm/plat-s3c24xx/devs.h> |
43 | #include "cpu.h" | 43 | #include <asm/plat-s3c24xx/cpu.h> |
44 | #include "pm.h" | 44 | #include <asm/plat-s3c24xx/pm.h> |
45 | 45 | ||
46 | static struct map_desc h1940_iodesc[] __initdata = { | 46 | static struct map_desc h1940_iodesc[] __initdata = { |
47 | [0] = { | 47 | [0] = { |
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 0411e9adb54d..dbac7311f98f 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c | |||
@@ -38,10 +38,10 @@ | |||
38 | #include <asm/arch/regs-gpio.h> | 38 | #include <asm/arch/regs-gpio.h> |
39 | #include <asm/arch/iic.h> | 39 | #include <asm/arch/iic.h> |
40 | 40 | ||
41 | #include "s3c2410.h" | 41 | #include <asm/plat-s3c24xx/s3c2410.h> |
42 | #include "clock.h" | 42 | #include <asm/plat-s3c24xx/clock.h> |
43 | #include "devs.h" | 43 | #include <asm/plat-s3c24xx/devs.h> |
44 | #include "cpu.h" | 44 | #include <asm/plat-s3c24xx/cpu.h> |
45 | 45 | ||
46 | static struct map_desc n30_iodesc[] __initdata = { | 46 | static struct map_desc n30_iodesc[] __initdata = { |
47 | /* nothing here yet */ | 47 | /* nothing here yet */ |
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c index 2c738b375e4d..c78ab75b44f3 100644 --- a/arch/arm/mach-s3c2410/mach-otom.c +++ b/arch/arm/mach-s3c2410/mach-otom.c | |||
@@ -32,10 +32,10 @@ | |||
32 | #include <asm/arch/regs-serial.h> | 32 | #include <asm/arch/regs-serial.h> |
33 | #include <asm/arch/regs-gpio.h> | 33 | #include <asm/arch/regs-gpio.h> |
34 | 34 | ||
35 | #include "s3c2410.h" | 35 | #include <asm/plat-s3c24xx/s3c2410.h> |
36 | #include "clock.h" | 36 | #include <asm/plat-s3c24xx/clock.h> |
37 | #include "devs.h" | 37 | #include <asm/plat-s3c24xx/devs.h> |
38 | #include "cpu.h" | 38 | #include <asm/plat-s3c24xx/cpu.h> |
39 | 39 | ||
40 | static struct map_desc otom11_iodesc[] __initdata = { | 40 | static struct map_desc otom11_iodesc[] __initdata = { |
41 | /* Device area */ | 41 | /* Device area */ |
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 01c0c986d827..57b8a80f33d0 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /*********************************************************************** | 1 | /* linux/arch/arm/mach-s3c2410/mach-smdk2410.c |
2 | * | 2 | * |
3 | * linux/arch/arm/mach-s3c2410/mach-smdk2410.c | 3 | * linux/arch/arm/mach-s3c2410/mach-smdk2410.c |
4 | * | 4 | * |
@@ -49,10 +49,10 @@ | |||
49 | 49 | ||
50 | #include <asm/arch/regs-serial.h> | 50 | #include <asm/arch/regs-serial.h> |
51 | 51 | ||
52 | #include "devs.h" | 52 | #include <asm/plat-s3c24xx/devs.h> |
53 | #include "cpu.h" | 53 | #include <asm/plat-s3c24xx/cpu.h> |
54 | 54 | ||
55 | #include "common-smdk.h" | 55 | #include <asm/plat-s3c24xx/common-smdk.h> |
56 | 56 | ||
57 | static struct map_desc smdk2410_iodesc[] __initdata = { | 57 | static struct map_desc smdk2410_iodesc[] __initdata = { |
58 | /* nothing here yet */ | 58 | /* nothing here yet */ |
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index a382fc095110..c947c75bcbf0 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c | |||
@@ -43,9 +43,9 @@ | |||
43 | #include <asm/arch/regs-gpio.h> | 43 | #include <asm/arch/regs-gpio.h> |
44 | #include <asm/arch/leds-gpio.h> | 44 | #include <asm/arch/leds-gpio.h> |
45 | 45 | ||
46 | #include "clock.h" | 46 | #include <asm/plat-s3c24xx/clock.h> |
47 | #include "devs.h" | 47 | #include <asm/plat-s3c24xx/devs.h> |
48 | #include "cpu.h" | 48 | #include <asm/plat-s3c24xx/cpu.h> |
49 | #include "usb-simtec.h" | 49 | #include "usb-simtec.h" |
50 | 50 | ||
51 | /* macros for virtual address mods for the io space entries */ | 51 | /* macros for virtual address mods for the io space entries */ |
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c index ebf294dd31da..3b3a7db4e0dd 100644 --- a/arch/arm/mach-s3c2410/pm.c +++ b/arch/arm/mach-s3c2410/pm.c | |||
@@ -1,11 +1,9 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/pm.c | 1 | /* linux/arch/arm/mach-s3c2410/pm.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004,2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C24XX Power Manager (Suspend-To-RAM) support | 6 | * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support |
7 | * | ||
8 | * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information | ||
9 | * | 7 | * |
10 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -20,640 +18,139 @@ | |||
20 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 19 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | ||
24 | * Parts based on arch/arm/mach-pxa/pm.c | ||
25 | * | ||
26 | * Thanks to Dimitry Andric for debugging | ||
27 | */ | 21 | */ |
28 | 22 | ||
29 | #include <linux/init.h> | 23 | #include <linux/init.h> |
30 | #include <linux/suspend.h> | 24 | #include <linux/suspend.h> |
31 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
32 | #include <linux/time.h> | 26 | #include <linux/time.h> |
33 | #include <linux/interrupt.h> | 27 | #include <linux/sysdev.h> |
34 | #include <linux/crc32.h> | ||
35 | #include <linux/ioport.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/serial_core.h> | ||
38 | 28 | ||
39 | #include <asm/cacheflush.h> | ||
40 | #include <asm/hardware.h> | 29 | #include <asm/hardware.h> |
41 | #include <asm/io.h> | 30 | #include <asm/io.h> |
42 | 31 | ||
43 | #include <asm/arch/regs-serial.h> | 32 | #include <asm/mach-types.h> |
44 | #include <asm/arch/regs-clock.h> | ||
45 | #include <asm/arch/regs-gpio.h> | ||
46 | #include <asm/arch/regs-mem.h> | ||
47 | #include <asm/arch/regs-irq.h> | ||
48 | |||
49 | #include <asm/mach/time.h> | ||
50 | |||
51 | #include "pm.h" | ||
52 | |||
53 | /* for external use */ | ||
54 | |||
55 | unsigned long s3c_pm_flags; | ||
56 | |||
57 | #define PFX "s3c24xx-pm: " | ||
58 | |||
59 | static struct sleep_save core_save[] = { | ||
60 | SAVE_ITEM(S3C2410_LOCKTIME), | ||
61 | SAVE_ITEM(S3C2410_CLKCON), | ||
62 | |||
63 | /* we restore the timings here, with the proviso that the board | ||
64 | * brings the system up in an slower, or equal frequency setting | ||
65 | * to the original system. | ||
66 | * | ||
67 | * if we cannot guarantee this, then things are going to go very | ||
68 | * wrong here, as we modify the refresh and both pll settings. | ||
69 | */ | ||
70 | |||
71 | SAVE_ITEM(S3C2410_BWSCON), | ||
72 | SAVE_ITEM(S3C2410_BANKCON0), | ||
73 | SAVE_ITEM(S3C2410_BANKCON1), | ||
74 | SAVE_ITEM(S3C2410_BANKCON2), | ||
75 | SAVE_ITEM(S3C2410_BANKCON3), | ||
76 | SAVE_ITEM(S3C2410_BANKCON4), | ||
77 | SAVE_ITEM(S3C2410_BANKCON5), | ||
78 | |||
79 | SAVE_ITEM(S3C2410_CLKDIVN), | ||
80 | SAVE_ITEM(S3C2410_MPLLCON), | ||
81 | SAVE_ITEM(S3C2410_UPLLCON), | ||
82 | SAVE_ITEM(S3C2410_CLKSLOW), | ||
83 | SAVE_ITEM(S3C2410_REFRESH), | ||
84 | }; | ||
85 | |||
86 | static struct sleep_save gpio_save[] = { | ||
87 | SAVE_ITEM(S3C2410_GPACON), | ||
88 | SAVE_ITEM(S3C2410_GPADAT), | ||
89 | |||
90 | SAVE_ITEM(S3C2410_GPBCON), | ||
91 | SAVE_ITEM(S3C2410_GPBDAT), | ||
92 | SAVE_ITEM(S3C2410_GPBUP), | ||
93 | |||
94 | SAVE_ITEM(S3C2410_GPCCON), | ||
95 | SAVE_ITEM(S3C2410_GPCDAT), | ||
96 | SAVE_ITEM(S3C2410_GPCUP), | ||
97 | |||
98 | SAVE_ITEM(S3C2410_GPDCON), | ||
99 | SAVE_ITEM(S3C2410_GPDDAT), | ||
100 | SAVE_ITEM(S3C2410_GPDUP), | ||
101 | |||
102 | SAVE_ITEM(S3C2410_GPECON), | ||
103 | SAVE_ITEM(S3C2410_GPEDAT), | ||
104 | SAVE_ITEM(S3C2410_GPEUP), | ||
105 | |||
106 | SAVE_ITEM(S3C2410_GPFCON), | ||
107 | SAVE_ITEM(S3C2410_GPFDAT), | ||
108 | SAVE_ITEM(S3C2410_GPFUP), | ||
109 | 33 | ||
110 | SAVE_ITEM(S3C2410_GPGCON), | 34 | #include <asm/arch/regs-gpio.h> |
111 | SAVE_ITEM(S3C2410_GPGDAT), | 35 | #include <asm/arch/h1940.h> |
112 | SAVE_ITEM(S3C2410_GPGUP), | ||
113 | |||
114 | SAVE_ITEM(S3C2410_GPHCON), | ||
115 | SAVE_ITEM(S3C2410_GPHDAT), | ||
116 | SAVE_ITEM(S3C2410_GPHUP), | ||
117 | 36 | ||
118 | SAVE_ITEM(S3C2410_DCLKCON), | 37 | #include <asm/plat-s3c24xx/cpu.h> |
119 | }; | 38 | #include <asm/plat-s3c24xx/pm.h> |
120 | 39 | ||
121 | #ifdef CONFIG_S3C2410_PM_DEBUG | 40 | #ifdef CONFIG_S3C2410_PM_DEBUG |
122 | 41 | extern void pm_dbg(const char *fmt, ...); | |
123 | #define SAVE_UART(va) \ | ||
124 | SAVE_ITEM((va) + S3C2410_ULCON), \ | ||
125 | SAVE_ITEM((va) + S3C2410_UCON), \ | ||
126 | SAVE_ITEM((va) + S3C2410_UFCON), \ | ||
127 | SAVE_ITEM((va) + S3C2410_UMCON), \ | ||
128 | SAVE_ITEM((va) + S3C2410_UBRDIV) | ||
129 | |||
130 | static struct sleep_save uart_save[] = { | ||
131 | SAVE_UART(S3C24XX_VA_UART0), | ||
132 | SAVE_UART(S3C24XX_VA_UART1), | ||
133 | #ifndef CONFIG_CPU_S3C2400 | ||
134 | SAVE_UART(S3C24XX_VA_UART2), | ||
135 | #endif | ||
136 | }; | ||
137 | |||
138 | /* debug | ||
139 | * | ||
140 | * we send the debug to printascii() to allow it to be seen if the | ||
141 | * system never wakes up from the sleep | ||
142 | */ | ||
143 | |||
144 | extern void printascii(const char *); | ||
145 | |||
146 | void pm_dbg(const char *fmt, ...) | ||
147 | { | ||
148 | va_list va; | ||
149 | char buff[256]; | ||
150 | |||
151 | va_start(va, fmt); | ||
152 | vsprintf(buff, fmt, va); | ||
153 | va_end(va); | ||
154 | |||
155 | printascii(buff); | ||
156 | } | ||
157 | |||
158 | static void s3c2410_pm_debug_init(void) | ||
159 | { | ||
160 | unsigned long tmp = __raw_readl(S3C2410_CLKCON); | ||
161 | |||
162 | /* re-start uart clocks */ | ||
163 | tmp |= S3C2410_CLKCON_UART0; | ||
164 | tmp |= S3C2410_CLKCON_UART1; | ||
165 | tmp |= S3C2410_CLKCON_UART2; | ||
166 | |||
167 | __raw_writel(tmp, S3C2410_CLKCON); | ||
168 | udelay(10); | ||
169 | } | ||
170 | |||
171 | #define DBG(fmt...) pm_dbg(fmt) | 42 | #define DBG(fmt...) pm_dbg(fmt) |
172 | #else | 43 | #else |
173 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | 44 | #define DBG(fmt...) printk(KERN_DEBUG fmt) |
174 | |||
175 | #define s3c2410_pm_debug_init() do { } while(0) | ||
176 | |||
177 | static struct sleep_save uart_save[] = {}; | ||
178 | #endif | 45 | #endif |
179 | 46 | ||
180 | #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 | 47 | static void s3c2410_pm_prepare(void) |
181 | |||
182 | /* suspend checking code... | ||
183 | * | ||
184 | * this next area does a set of crc checks over all the installed | ||
185 | * memory, so the system can verify if the resume was ok. | ||
186 | * | ||
187 | * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, | ||
188 | * increasing it will mean that the area corrupted will be less easy to spot, | ||
189 | * and reducing the size will cause the CRC save area to grow | ||
190 | */ | ||
191 | |||
192 | #define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) | ||
193 | |||
194 | static u32 crc_size; /* size needed for the crc block */ | ||
195 | static u32 *crcs; /* allocated over suspend/resume */ | ||
196 | |||
197 | typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); | ||
198 | |||
199 | /* s3c2410_pm_run_res | ||
200 | * | ||
201 | * go thorugh the given resource list, and look for system ram | ||
202 | */ | ||
203 | |||
204 | static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) | ||
205 | { | ||
206 | while (ptr != NULL) { | ||
207 | if (ptr->child != NULL) | ||
208 | s3c2410_pm_run_res(ptr->child, fn, arg); | ||
209 | |||
210 | if ((ptr->flags & IORESOURCE_MEM) && | ||
211 | strcmp(ptr->name, "System RAM") == 0) { | ||
212 | DBG("Found system RAM at %08lx..%08lx\n", | ||
213 | ptr->start, ptr->end); | ||
214 | arg = (fn)(ptr, arg); | ||
215 | } | ||
216 | |||
217 | ptr = ptr->sibling; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) | ||
222 | { | ||
223 | s3c2410_pm_run_res(&iomem_resource, fn, arg); | ||
224 | } | ||
225 | |||
226 | static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) | ||
227 | { | ||
228 | u32 size = (u32)(res->end - res->start)+1; | ||
229 | |||
230 | size += CHECK_CHUNKSIZE-1; | ||
231 | size /= CHECK_CHUNKSIZE; | ||
232 | |||
233 | DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); | ||
234 | |||
235 | *val += size * sizeof(u32); | ||
236 | return val; | ||
237 | } | ||
238 | |||
239 | /* s3c2410_pm_prepare_check | ||
240 | * | ||
241 | * prepare the necessary information for creating the CRCs. This | ||
242 | * must be done before the final save, as it will require memory | ||
243 | * allocating, and thus touching bits of the kernel we do not | ||
244 | * know about. | ||
245 | */ | ||
246 | |||
247 | static void s3c2410_pm_check_prepare(void) | ||
248 | { | 48 | { |
249 | crc_size = 0; | 49 | /* ensure at least GSTATUS3 has the resume address */ |
250 | 50 | ||
251 | s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); | 51 | __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); |
252 | 52 | ||
253 | DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); | 53 | DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); |
54 | DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); | ||
254 | 55 | ||
255 | crcs = kmalloc(crc_size+4, GFP_KERNEL); | 56 | if (machine_is_h1940()) { |
256 | if (crcs == NULL) | 57 | void *base = phys_to_virt(H1940_SUSPEND_CHECK); |
257 | printk(KERN_ERR "Cannot allocated CRC save area\n"); | 58 | unsigned long ptr; |
258 | } | 59 | unsigned long calc = 0; |
259 | 60 | ||
260 | static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) | 61 | /* generate check for the bootloader to check on resume */ |
261 | { | ||
262 | unsigned long addr, left; | ||
263 | 62 | ||
264 | for (addr = res->start; addr < res->end; | 63 | for (ptr = 0; ptr < 0x40000; ptr += 0x400) |
265 | addr += CHECK_CHUNKSIZE) { | 64 | calc += __raw_readl(base+ptr); |
266 | left = res->end - addr; | ||
267 | 65 | ||
268 | if (left > CHECK_CHUNKSIZE) | 66 | __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); |
269 | left = CHECK_CHUNKSIZE; | ||
270 | |||
271 | *val = crc32_le(~0, phys_to_virt(addr), left); | ||
272 | val++; | ||
273 | } | 67 | } |
274 | 68 | ||
275 | return val; | 69 | /* the RX3715 uses similar code and the same H1940 and the |
276 | } | 70 | * same offsets for resume and checksum pointers */ |
277 | |||
278 | /* s3c2410_pm_check_store | ||
279 | * | ||
280 | * compute the CRC values for the memory blocks before the final | ||
281 | * sleep. | ||
282 | */ | ||
283 | |||
284 | static void s3c2410_pm_check_store(void) | ||
285 | { | ||
286 | if (crcs != NULL) | ||
287 | s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); | ||
288 | } | ||
289 | |||
290 | /* in_region | ||
291 | * | ||
292 | * return TRUE if the area defined by ptr..ptr+size contatins the | ||
293 | * what..what+whatsz | ||
294 | */ | ||
295 | |||
296 | static inline int in_region(void *ptr, int size, void *what, size_t whatsz) | ||
297 | { | ||
298 | if ((what+whatsz) < ptr) | ||
299 | return 0; | ||
300 | |||
301 | if (what > (ptr+size)) | ||
302 | return 0; | ||
303 | |||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) | ||
308 | { | ||
309 | void *save_at = phys_to_virt(s3c2410_sleep_save_phys); | ||
310 | unsigned long addr; | ||
311 | unsigned long left; | ||
312 | void *ptr; | ||
313 | u32 calc; | ||
314 | |||
315 | for (addr = res->start; addr < res->end; | ||
316 | addr += CHECK_CHUNKSIZE) { | ||
317 | left = res->end - addr; | ||
318 | 71 | ||
319 | if (left > CHECK_CHUNKSIZE) | 72 | if (machine_is_rx3715()) { |
320 | left = CHECK_CHUNKSIZE; | 73 | void *base = phys_to_virt(H1940_SUSPEND_CHECK); |
74 | unsigned long ptr; | ||
75 | unsigned long calc = 0; | ||
321 | 76 | ||
322 | ptr = phys_to_virt(addr); | 77 | /* generate check for the bootloader to check on resume */ |
323 | 78 | ||
324 | if (in_region(ptr, left, crcs, crc_size)) { | 79 | for (ptr = 0; ptr < 0x40000; ptr += 0x4) |
325 | DBG("skipping %08lx, has crc block in\n", addr); | 80 | calc += __raw_readl(base+ptr); |
326 | goto skip_check; | ||
327 | } | ||
328 | 81 | ||
329 | if (in_region(ptr, left, save_at, 32*4 )) { | 82 | __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); |
330 | DBG("skipping %08lx, has save block in\n", addr); | ||
331 | goto skip_check; | ||
332 | } | ||
333 | |||
334 | /* calculate and check the checksum */ | ||
335 | |||
336 | calc = crc32_le(~0, ptr, left); | ||
337 | if (calc != *val) { | ||
338 | printk(KERN_ERR PFX "Restore CRC error at " | ||
339 | "%08lx (%08x vs %08x)\n", addr, calc, *val); | ||
340 | |||
341 | DBG("Restore CRC error at %08lx (%08x vs %08x)\n", | ||
342 | addr, calc, *val); | ||
343 | } | ||
344 | |||
345 | skip_check: | ||
346 | val++; | ||
347 | } | 83 | } |
348 | 84 | ||
349 | return val; | 85 | if ( machine_is_aml_m5900() ) |
350 | } | 86 | s3c2410_gpio_setpin(S3C2410_GPF2, 1); |
351 | 87 | ||
352 | /* s3c2410_pm_check_restore | ||
353 | * | ||
354 | * check the CRCs after the restore event and free the memory used | ||
355 | * to hold them | ||
356 | */ | ||
357 | |||
358 | static void s3c2410_pm_check_restore(void) | ||
359 | { | ||
360 | if (crcs != NULL) { | ||
361 | s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); | ||
362 | kfree(crcs); | ||
363 | crcs = NULL; | ||
364 | } | ||
365 | } | 88 | } |
366 | 89 | ||
367 | #else | 90 | static int s3c2410_pm_resume(struct sys_device *dev) |
368 | |||
369 | #define s3c2410_pm_check_prepare() do { } while(0) | ||
370 | #define s3c2410_pm_check_restore() do { } while(0) | ||
371 | #define s3c2410_pm_check_store() do { } while(0) | ||
372 | #endif | ||
373 | |||
374 | /* helper functions to save and restore register state */ | ||
375 | |||
376 | void s3c2410_pm_do_save(struct sleep_save *ptr, int count) | ||
377 | { | 91 | { |
378 | for (; count > 0; count--, ptr++) { | 92 | unsigned long tmp; |
379 | ptr->val = __raw_readl(ptr->reg); | ||
380 | DBG("saved %p value %08lx\n", ptr->reg, ptr->val); | ||
381 | } | ||
382 | } | ||
383 | 93 | ||
384 | /* s3c2410_pm_do_restore | 94 | /* unset the return-from-sleep flag, to ensure reset */ |
385 | * | ||
386 | * restore the system from the given list of saved registers | ||
387 | * | ||
388 | * Note, we do not use DBG() in here, as the system may not have | ||
389 | * restore the UARTs state yet | ||
390 | */ | ||
391 | 95 | ||
392 | void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) | 96 | tmp = __raw_readl(S3C2410_GSTATUS2); |
393 | { | 97 | tmp &= S3C2410_GSTATUS2_OFFRESET; |
394 | for (; count > 0; count--, ptr++) { | 98 | __raw_writel(tmp, S3C2410_GSTATUS2); |
395 | printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", | ||
396 | ptr->reg, ptr->val, __raw_readl(ptr->reg)); | ||
397 | |||
398 | __raw_writel(ptr->val, ptr->reg); | ||
399 | } | ||
400 | } | ||
401 | 99 | ||
402 | /* s3c2410_pm_do_restore_core | 100 | if ( machine_is_aml_m5900() ) |
403 | * | 101 | s3c2410_gpio_setpin(S3C2410_GPF2, 0); |
404 | * similar to s3c2410_pm_do_restore_core | ||
405 | * | ||
406 | * WARNING: Do not put any debug in here that may effect memory or use | ||
407 | * peripherals, as things may be changing! | ||
408 | */ | ||
409 | 102 | ||
410 | static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) | 103 | return 0; |
411 | { | ||
412 | for (; count > 0; count--, ptr++) { | ||
413 | __raw_writel(ptr->val, ptr->reg); | ||
414 | } | ||
415 | } | 104 | } |
416 | 105 | ||
417 | /* s3c2410_pm_show_resume_irqs | 106 | static int s3c2410_pm_add(struct sys_device *dev) |
418 | * | ||
419 | * print any IRQs asserted at resume time (ie, we woke from) | ||
420 | */ | ||
421 | |||
422 | static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, | ||
423 | unsigned long mask) | ||
424 | { | 107 | { |
425 | int i; | 108 | pm_cpu_prep = s3c2410_pm_prepare; |
109 | pm_cpu_sleep = s3c2410_cpu_suspend; | ||
426 | 110 | ||
427 | which &= ~mask; | 111 | return 0; |
428 | |||
429 | for (i = 0; i <= 31; i++) { | ||
430 | if ((which) & (1L<<i)) { | ||
431 | DBG("IRQ %d asserted at resume\n", start+i); | ||
432 | } | ||
433 | } | ||
434 | } | 112 | } |
435 | 113 | ||
436 | /* s3c2410_pm_check_resume_pin | 114 | #if defined(CONFIG_CPU_S3C2410) |
437 | * | 115 | static struct sysdev_driver s3c2410_pm_driver = { |
438 | * check to see if the pin is configured correctly for sleep mode, and | 116 | .add = s3c2410_pm_add, |
439 | * make any necessary adjustments if it is not | 117 | .resume = s3c2410_pm_resume, |
440 | */ | 118 | }; |
441 | |||
442 | static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) | ||
443 | { | ||
444 | unsigned long irqstate; | ||
445 | unsigned long pinstate; | ||
446 | int irq = s3c2410_gpio_getirq(pin); | ||
447 | |||
448 | if (irqoffs < 4) | ||
449 | irqstate = s3c_irqwake_intmask & (1L<<irqoffs); | ||
450 | else | ||
451 | irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); | ||
452 | |||
453 | pinstate = s3c2410_gpio_getcfg(pin); | ||
454 | |||
455 | if (!irqstate) { | ||
456 | if (pinstate == S3C2410_GPIO_IRQ) | ||
457 | DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); | ||
458 | } else { | ||
459 | if (pinstate == S3C2410_GPIO_IRQ) { | ||
460 | DBG("Disabling IRQ %d (pin %d)\n", irq, pin); | ||
461 | s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT); | ||
462 | } | ||
463 | } | ||
464 | } | ||
465 | 119 | ||
466 | /* s3c2410_pm_configure_extint | 120 | /* register ourselves */ |
467 | * | ||
468 | * configure all external interrupt pins | ||
469 | */ | ||
470 | 121 | ||
471 | static void s3c2410_pm_configure_extint(void) | 122 | static int __init s3c2410_pm_drvinit(void) |
472 | { | 123 | { |
473 | int pin; | 124 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver); |
474 | |||
475 | /* for each of the external interrupts (EINT0..EINT15) we | ||
476 | * need to check wether it is an external interrupt source, | ||
477 | * and then configure it as an input if it is not | ||
478 | */ | ||
479 | |||
480 | for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { | ||
481 | s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); | ||
482 | } | ||
483 | |||
484 | for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { | ||
485 | s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); | ||
486 | } | ||
487 | } | 125 | } |
488 | 126 | ||
489 | void (*pm_cpu_prep)(void); | 127 | arch_initcall(s3c2410_pm_drvinit); |
490 | void (*pm_cpu_sleep)(void); | 128 | #endif |
491 | |||
492 | #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) | ||
493 | |||
494 | /* s3c2410_pm_enter | ||
495 | * | ||
496 | * central control for sleep/resume process | ||
497 | */ | ||
498 | |||
499 | static int s3c2410_pm_enter(suspend_state_t state) | ||
500 | { | ||
501 | unsigned long regs_save[16]; | ||
502 | |||
503 | /* ensure the debug is initialised (if enabled) */ | ||
504 | |||
505 | s3c2410_pm_debug_init(); | ||
506 | |||
507 | DBG("s3c2410_pm_enter(%d)\n", state); | ||
508 | |||
509 | if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { | ||
510 | printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | |||
514 | if (state != PM_SUSPEND_MEM) { | ||
515 | printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | |||
519 | /* check if we have anything to wake-up with... bad things seem | ||
520 | * to happen if you suspend with no wakeup (system will often | ||
521 | * require a full power-cycle) | ||
522 | */ | ||
523 | |||
524 | if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && | ||
525 | !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { | ||
526 | printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); | ||
527 | printk(KERN_ERR PFX "Aborting sleep\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | |||
531 | /* prepare check area if configured */ | ||
532 | |||
533 | s3c2410_pm_check_prepare(); | ||
534 | |||
535 | /* store the physical address of the register recovery block */ | ||
536 | |||
537 | s3c2410_sleep_save_phys = virt_to_phys(regs_save); | ||
538 | |||
539 | DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); | ||
540 | |||
541 | /* save all necessary core registers not covered by the drivers */ | ||
542 | |||
543 | s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); | ||
544 | s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); | ||
545 | s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); | ||
546 | |||
547 | /* set the irq configuration for wake */ | ||
548 | |||
549 | s3c2410_pm_configure_extint(); | ||
550 | |||
551 | DBG("sleep: irq wakeup masks: %08lx,%08lx\n", | ||
552 | s3c_irqwake_intmask, s3c_irqwake_eintmask); | ||
553 | |||
554 | __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); | ||
555 | __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); | ||
556 | |||
557 | /* ack any outstanding external interrupts before we go to sleep */ | ||
558 | |||
559 | __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); | ||
560 | __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); | ||
561 | __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); | ||
562 | |||
563 | /* call cpu specific preperation */ | ||
564 | |||
565 | pm_cpu_prep(); | ||
566 | |||
567 | /* flush cache back to ram */ | ||
568 | |||
569 | flush_cache_all(); | ||
570 | |||
571 | s3c2410_pm_check_store(); | ||
572 | |||
573 | /* send the cpu to sleep... */ | ||
574 | |||
575 | __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ | ||
576 | |||
577 | /* s3c2410_cpu_save will also act as our return point from when | ||
578 | * we resume as it saves its own register state, so use the return | ||
579 | * code to differentiate return from save and return from sleep */ | ||
580 | |||
581 | if (s3c2410_cpu_save(regs_save) == 0) { | ||
582 | flush_cache_all(); | ||
583 | pm_cpu_sleep(); | ||
584 | } | ||
585 | |||
586 | /* restore the cpu state */ | ||
587 | |||
588 | cpu_init(); | ||
589 | |||
590 | /* restore the system state */ | ||
591 | |||
592 | s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); | ||
593 | s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); | ||
594 | s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); | ||
595 | |||
596 | s3c2410_pm_debug_init(); | ||
597 | |||
598 | /* check what irq (if any) restored the system */ | ||
599 | |||
600 | DBG("post sleep: IRQs 0x%08x, 0x%08x\n", | ||
601 | __raw_readl(S3C2410_SRCPND), | ||
602 | __raw_readl(S3C2410_EINTPEND)); | ||
603 | |||
604 | s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), | ||
605 | s3c_irqwake_intmask); | ||
606 | |||
607 | s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), | ||
608 | s3c_irqwake_eintmask); | ||
609 | |||
610 | DBG("post sleep, preparing to return\n"); | ||
611 | |||
612 | s3c2410_pm_check_restore(); | ||
613 | |||
614 | /* ok, let's return from sleep */ | ||
615 | 129 | ||
616 | DBG("S3C2410 PM Resume (post-restore)\n"); | 130 | #if defined(CONFIG_CPU_S3C2440) |
617 | return 0; | 131 | static struct sysdev_driver s3c2440_pm_driver = { |
618 | } | 132 | .add = s3c2410_pm_add, |
133 | .resume = s3c2410_pm_resume, | ||
134 | }; | ||
619 | 135 | ||
620 | /* | 136 | static int __init s3c2440_pm_drvinit(void) |
621 | * Called after processes are frozen, but before we shut down devices. | ||
622 | */ | ||
623 | static int s3c2410_pm_prepare(suspend_state_t state) | ||
624 | { | 137 | { |
625 | return 0; | 138 | return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver); |
626 | } | 139 | } |
627 | 140 | ||
628 | /* | 141 | arch_initcall(s3c2440_pm_drvinit); |
629 | * Called after devices are re-setup, but before processes are thawed. | 142 | #endif |
630 | */ | ||
631 | static int s3c2410_pm_finish(suspend_state_t state) | ||
632 | { | ||
633 | return 0; | ||
634 | } | ||
635 | 143 | ||
636 | /* | 144 | #if defined(CONFIG_CPU_S3C2442) |
637 | * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. | 145 | static struct sysdev_driver s3c2442_pm_driver = { |
638 | */ | 146 | .add = s3c2410_pm_add, |
639 | static struct pm_ops s3c2410_pm_ops = { | 147 | .resume = s3c2410_pm_resume, |
640 | .pm_disk_mode = PM_DISK_FIRMWARE, | ||
641 | .prepare = s3c2410_pm_prepare, | ||
642 | .enter = s3c2410_pm_enter, | ||
643 | .finish = s3c2410_pm_finish, | ||
644 | }; | 148 | }; |
645 | 149 | ||
646 | /* s3c2410_pm_init | 150 | static int __init s3c2442_pm_drvinit(void) |
647 | * | ||
648 | * Attach the power management functions. This should be called | ||
649 | * from the board specific initialisation if the board supports | ||
650 | * it. | ||
651 | */ | ||
652 | |||
653 | int __init s3c2410_pm_init(void) | ||
654 | { | 151 | { |
655 | printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); | 152 | return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver); |
656 | |||
657 | pm_set_ops(&s3c2410_pm_ops); | ||
658 | return 0; | ||
659 | } | 153 | } |
154 | |||
155 | arch_initcall(s3c2442_pm_drvinit); | ||
156 | #endif | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c deleted file mode 100644 index 992cc6af230e..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-clock.c +++ /dev/null | |||
@@ -1,276 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-clock.c | ||
2 | * | ||
3 | * Copyright (c) 2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410,S3C2440,S3C2442 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-serial.h> | ||
41 | #include <asm/arch/regs-clock.h> | ||
42 | #include <asm/arch/regs-gpio.h> | ||
43 | |||
44 | #include "s3c2410.h" | ||
45 | #include "clock.h" | ||
46 | #include "cpu.h" | ||
47 | |||
48 | int s3c2410_clkcon_enable(struct clk *clk, int enable) | ||
49 | { | ||
50 | unsigned int clocks = clk->ctrlbit; | ||
51 | unsigned long clkcon; | ||
52 | |||
53 | clkcon = __raw_readl(S3C2410_CLKCON); | ||
54 | |||
55 | if (enable) | ||
56 | clkcon |= clocks; | ||
57 | else | ||
58 | clkcon &= ~clocks; | ||
59 | |||
60 | /* ensure none of the special function bits set */ | ||
61 | clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); | ||
62 | |||
63 | __raw_writel(clkcon, S3C2410_CLKCON); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int s3c2410_upll_enable(struct clk *clk, int enable) | ||
69 | { | ||
70 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
71 | unsigned long orig = clkslow; | ||
72 | |||
73 | if (enable) | ||
74 | clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF; | ||
75 | else | ||
76 | clkslow |= S3C2410_CLKSLOW_UCLK_OFF; | ||
77 | |||
78 | __raw_writel(clkslow, S3C2410_CLKSLOW); | ||
79 | |||
80 | /* if we started the UPLL, then allow to settle */ | ||
81 | |||
82 | if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) | ||
83 | udelay(200); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* standard clock definitions */ | ||
89 | |||
90 | static struct clk init_clocks_disable[] = { | ||
91 | { | ||
92 | .name = "nand", | ||
93 | .id = -1, | ||
94 | .parent = &clk_h, | ||
95 | .enable = s3c2410_clkcon_enable, | ||
96 | .ctrlbit = S3C2410_CLKCON_NAND, | ||
97 | }, { | ||
98 | .name = "sdi", | ||
99 | .id = -1, | ||
100 | .parent = &clk_p, | ||
101 | .enable = s3c2410_clkcon_enable, | ||
102 | .ctrlbit = S3C2410_CLKCON_SDI, | ||
103 | }, { | ||
104 | .name = "adc", | ||
105 | .id = -1, | ||
106 | .parent = &clk_p, | ||
107 | .enable = s3c2410_clkcon_enable, | ||
108 | .ctrlbit = S3C2410_CLKCON_ADC, | ||
109 | }, { | ||
110 | .name = "i2c", | ||
111 | .id = -1, | ||
112 | .parent = &clk_p, | ||
113 | .enable = s3c2410_clkcon_enable, | ||
114 | .ctrlbit = S3C2410_CLKCON_IIC, | ||
115 | }, { | ||
116 | .name = "iis", | ||
117 | .id = -1, | ||
118 | .parent = &clk_p, | ||
119 | .enable = s3c2410_clkcon_enable, | ||
120 | .ctrlbit = S3C2410_CLKCON_IIS, | ||
121 | }, { | ||
122 | .name = "spi", | ||
123 | .id = -1, | ||
124 | .parent = &clk_p, | ||
125 | .enable = s3c2410_clkcon_enable, | ||
126 | .ctrlbit = S3C2410_CLKCON_SPI, | ||
127 | } | ||
128 | }; | ||
129 | |||
130 | static struct clk init_clocks[] = { | ||
131 | { | ||
132 | .name = "lcd", | ||
133 | .id = -1, | ||
134 | .parent = &clk_h, | ||
135 | .enable = s3c2410_clkcon_enable, | ||
136 | .ctrlbit = S3C2410_CLKCON_LCDC, | ||
137 | }, { | ||
138 | .name = "gpio", | ||
139 | .id = -1, | ||
140 | .parent = &clk_p, | ||
141 | .enable = s3c2410_clkcon_enable, | ||
142 | .ctrlbit = S3C2410_CLKCON_GPIO, | ||
143 | }, { | ||
144 | .name = "usb-host", | ||
145 | .id = -1, | ||
146 | .parent = &clk_h, | ||
147 | .enable = s3c2410_clkcon_enable, | ||
148 | .ctrlbit = S3C2410_CLKCON_USBH, | ||
149 | }, { | ||
150 | .name = "usb-device", | ||
151 | .id = -1, | ||
152 | .parent = &clk_h, | ||
153 | .enable = s3c2410_clkcon_enable, | ||
154 | .ctrlbit = S3C2410_CLKCON_USBD, | ||
155 | }, { | ||
156 | .name = "timers", | ||
157 | .id = -1, | ||
158 | .parent = &clk_p, | ||
159 | .enable = s3c2410_clkcon_enable, | ||
160 | .ctrlbit = S3C2410_CLKCON_PWMT, | ||
161 | }, { | ||
162 | .name = "uart", | ||
163 | .id = 0, | ||
164 | .parent = &clk_p, | ||
165 | .enable = s3c2410_clkcon_enable, | ||
166 | .ctrlbit = S3C2410_CLKCON_UART0, | ||
167 | }, { | ||
168 | .name = "uart", | ||
169 | .id = 1, | ||
170 | .parent = &clk_p, | ||
171 | .enable = s3c2410_clkcon_enable, | ||
172 | .ctrlbit = S3C2410_CLKCON_UART1, | ||
173 | }, { | ||
174 | .name = "uart", | ||
175 | .id = 2, | ||
176 | .parent = &clk_p, | ||
177 | .enable = s3c2410_clkcon_enable, | ||
178 | .ctrlbit = S3C2410_CLKCON_UART2, | ||
179 | }, { | ||
180 | .name = "rtc", | ||
181 | .id = -1, | ||
182 | .parent = &clk_p, | ||
183 | .enable = s3c2410_clkcon_enable, | ||
184 | .ctrlbit = S3C2410_CLKCON_RTC, | ||
185 | }, { | ||
186 | .name = "watchdog", | ||
187 | .id = -1, | ||
188 | .parent = &clk_p, | ||
189 | .ctrlbit = 0, | ||
190 | }, { | ||
191 | .name = "usb-bus-host", | ||
192 | .id = -1, | ||
193 | .parent = &clk_usb_bus, | ||
194 | }, { | ||
195 | .name = "usb-bus-gadget", | ||
196 | .id = -1, | ||
197 | .parent = &clk_usb_bus, | ||
198 | }, | ||
199 | }; | ||
200 | |||
201 | /* s3c2410_baseclk_add() | ||
202 | * | ||
203 | * Add all the clocks used by the s3c2410 or compatible CPUs | ||
204 | * such as the S3C2440 and S3C2442. | ||
205 | * | ||
206 | * We cannot use a system device as we are needed before any | ||
207 | * of the init-calls that initialise the devices are actually | ||
208 | * done. | ||
209 | */ | ||
210 | |||
211 | int __init s3c2410_baseclk_add(void) | ||
212 | { | ||
213 | unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); | ||
214 | unsigned long clkcon = __raw_readl(S3C2410_CLKCON); | ||
215 | struct clk *clkp; | ||
216 | struct clk *xtal; | ||
217 | int ret; | ||
218 | int ptr; | ||
219 | |||
220 | clk_upll.enable = s3c2410_upll_enable; | ||
221 | |||
222 | if (s3c24xx_register_clock(&clk_usb_bus) < 0) | ||
223 | printk(KERN_ERR "failed to register usb bus clock\n"); | ||
224 | |||
225 | /* register clocks from clock array */ | ||
226 | |||
227 | clkp = init_clocks; | ||
228 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { | ||
229 | /* ensure that we note the clock state */ | ||
230 | |||
231 | clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0; | ||
232 | |||
233 | ret = s3c24xx_register_clock(clkp); | ||
234 | if (ret < 0) { | ||
235 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
236 | clkp->name, ret); | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* We must be careful disabling the clocks we are not intending to | ||
241 | * be using at boot time, as subsytems such as the LCD which do | ||
242 | * their own DMA requests to the bus can cause the system to lockup | ||
243 | * if they where in the middle of requesting bus access. | ||
244 | * | ||
245 | * Disabling the LCD clock if the LCD is active is very dangerous, | ||
246 | * and therefore the bootloader should be careful to not enable | ||
247 | * the LCD clock if it is not needed. | ||
248 | */ | ||
249 | |||
250 | /* install (and disable) the clocks we do not need immediately */ | ||
251 | |||
252 | clkp = init_clocks_disable; | ||
253 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | ||
254 | |||
255 | ret = s3c24xx_register_clock(clkp); | ||
256 | if (ret < 0) { | ||
257 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | ||
258 | clkp->name, ret); | ||
259 | } | ||
260 | |||
261 | s3c2410_clkcon_enable(clkp, 0); | ||
262 | } | ||
263 | |||
264 | /* show the clock-slow value */ | ||
265 | |||
266 | xtal = clk_get(NULL, "xtal"); | ||
267 | |||
268 | printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n", | ||
269 | print_mhz(clk_get_rate(xtal) / | ||
270 | ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))), | ||
271 | (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast", | ||
272 | (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on", | ||
273 | (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on"); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c deleted file mode 100644 index e67ba3911f11..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-dma.c +++ /dev/null | |||
@@ -1,161 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-dma.c | ||
2 | * | ||
3 | * Copyright (c) 2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 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 "dma.h" | ||
23 | |||
24 | #include "cpu.h" | ||
25 | |||
26 | #include <asm/arch/regs-serial.h> | ||
27 | #include <asm/arch/regs-gpio.h> | ||
28 | #include <asm/arch/regs-ac97.h> | ||
29 | #include <asm/arch/regs-mem.h> | ||
30 | #include <asm/arch/regs-lcd.h> | ||
31 | #include <asm/arch/regs-sdi.h> | ||
32 | #include <asm/arch/regs-iis.h> | ||
33 | #include <asm/arch/regs-spi.h> | ||
34 | |||
35 | static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { | ||
36 | [DMACH_XD0] = { | ||
37 | .name = "xdreq0", | ||
38 | .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, | ||
39 | }, | ||
40 | [DMACH_XD1] = { | ||
41 | .name = "xdreq1", | ||
42 | .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, | ||
43 | }, | ||
44 | [DMACH_SDI] = { | ||
45 | .name = "sdi", | ||
46 | .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, | ||
47 | .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, | ||
48 | .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, | ||
49 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
50 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
51 | }, | ||
52 | [DMACH_SPI0] = { | ||
53 | .name = "spi0", | ||
54 | .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, | ||
55 | .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, | ||
56 | .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, | ||
57 | }, | ||
58 | [DMACH_SPI1] = { | ||
59 | .name = "spi1", | ||
60 | .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, | ||
61 | .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT, | ||
62 | .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT, | ||
63 | }, | ||
64 | [DMACH_UART0] = { | ||
65 | .name = "uart0", | ||
66 | .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, | ||
67 | .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, | ||
68 | .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, | ||
69 | }, | ||
70 | [DMACH_UART1] = { | ||
71 | .name = "uart1", | ||
72 | .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, | ||
73 | .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, | ||
74 | .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, | ||
75 | }, | ||
76 | [DMACH_UART2] = { | ||
77 | .name = "uart2", | ||
78 | .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, | ||
79 | .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, | ||
80 | .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, | ||
81 | }, | ||
82 | [DMACH_TIMER] = { | ||
83 | .name = "timer", | ||
84 | .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, | ||
85 | .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, | ||
86 | .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, | ||
87 | }, | ||
88 | [DMACH_I2S_IN] = { | ||
89 | .name = "i2s-sdi", | ||
90 | .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, | ||
91 | .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, | ||
92 | .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
93 | }, | ||
94 | [DMACH_I2S_OUT] = { | ||
95 | .name = "i2s-sdo", | ||
96 | .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, | ||
97 | .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO, | ||
98 | }, | ||
99 | [DMACH_USB_EP1] = { | ||
100 | .name = "usb-ep1", | ||
101 | .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, | ||
102 | }, | ||
103 | [DMACH_USB_EP2] = { | ||
104 | .name = "usb-ep2", | ||
105 | .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, | ||
106 | }, | ||
107 | [DMACH_USB_EP3] = { | ||
108 | .name = "usb-ep3", | ||
109 | .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, | ||
110 | }, | ||
111 | [DMACH_USB_EP4] = { | ||
112 | .name = "usb-ep4", | ||
113 | .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, | ||
114 | }, | ||
115 | }; | ||
116 | |||
117 | static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, | ||
118 | struct s3c24xx_dma_map *map) | ||
119 | { | ||
120 | chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; | ||
121 | } | ||
122 | |||
123 | static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { | ||
124 | .select = s3c2410_dma_select, | ||
125 | .dcon_mask = 7 << 24, | ||
126 | .map = s3c2410_dma_mappings, | ||
127 | .map_size = ARRAY_SIZE(s3c2410_dma_mappings), | ||
128 | }; | ||
129 | |||
130 | static int s3c2410_dma_add(struct sys_device *sysdev) | ||
131 | { | ||
132 | return s3c24xx_dma_init_map(&s3c2410_dma_sel); | ||
133 | } | ||
134 | |||
135 | #if defined(CONFIG_CPU_S3C2410) | ||
136 | static struct sysdev_driver s3c2410_dma_driver = { | ||
137 | .add = s3c2410_dma_add, | ||
138 | }; | ||
139 | |||
140 | static int __init s3c2410_dma_init(void) | ||
141 | { | ||
142 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver); | ||
143 | } | ||
144 | |||
145 | arch_initcall(s3c2410_dma_init); | ||
146 | #endif | ||
147 | |||
148 | #if defined(CONFIG_CPU_S3C2442) | ||
149 | /* S3C2442 DMA contains the same selection table as the S3C2410 */ | ||
150 | static struct sysdev_driver s3c2442_dma_driver = { | ||
151 | .add = s3c2410_dma_add, | ||
152 | }; | ||
153 | |||
154 | static int __init s3c2442_dma_init(void) | ||
155 | { | ||
156 | return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver); | ||
157 | } | ||
158 | |||
159 | arch_initcall(s3c2442_dma_init); | ||
160 | #endif | ||
161 | |||
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c deleted file mode 100644 index ec3a276cc3cf..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-gpio.c +++ /dev/null | |||
@@ -1,71 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c | ||
2 | * | ||
3 | * Copyright (c) 2004-2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 GPIO 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/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/ioport.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/io.h> | ||
32 | |||
33 | #include <asm/arch/regs-gpio.h> | ||
34 | |||
35 | int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, | ||
36 | unsigned int config) | ||
37 | { | ||
38 | void __iomem *reg = S3C24XX_EINFLT0; | ||
39 | unsigned long flags; | ||
40 | unsigned long val; | ||
41 | |||
42 | if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15) | ||
43 | return -1; | ||
44 | |||
45 | config &= 0xff; | ||
46 | |||
47 | pin -= S3C2410_GPG8; | ||
48 | reg += pin & ~3; | ||
49 | |||
50 | local_irq_save(flags); | ||
51 | |||
52 | /* update filter width and clock source */ | ||
53 | |||
54 | val = __raw_readl(reg); | ||
55 | val &= ~(0xff << ((pin & 3) * 8)); | ||
56 | val |= config << ((pin & 3) * 8); | ||
57 | __raw_writel(val, reg); | ||
58 | |||
59 | /* update filter enable */ | ||
60 | |||
61 | val = __raw_readl(S3C24XX_EXTINT2); | ||
62 | val &= ~(1 << ((pin * 4) + 3)); | ||
63 | val |= on << ((pin * 4) + 3); | ||
64 | __raw_writel(val, S3C24XX_EXTINT2); | ||
65 | |||
66 | local_irq_restore(flags); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | EXPORT_SYMBOL(s3c2410_gpio_irqfilter); | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410-irq.c b/arch/arm/mach-s3c2410/s3c2410-irq.c deleted file mode 100644 index c796c9c76e78..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-irq.c +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-irq.c | ||
2 | * | ||
3 | * Copyright (c) 2006 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 "cpu.h" | ||
30 | #include "pm.h" | ||
31 | |||
32 | static int s3c2410_irq_add(struct sys_device *sysdev) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static struct sysdev_driver s3c2410_irq_driver = { | ||
38 | .add = s3c2410_irq_add, | ||
39 | .suspend = s3c24xx_irq_suspend, | ||
40 | .resume = s3c24xx_irq_resume, | ||
41 | }; | ||
42 | |||
43 | static int s3c2410_irq_init(void) | ||
44 | { | ||
45 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver); | ||
46 | } | ||
47 | |||
48 | arch_initcall(s3c2410_irq_init); | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c deleted file mode 100644 index 8bb6e5e21f59..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-pm.c +++ /dev/null | |||
@@ -1,156 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-pm.c | ||
2 | * | ||
3 | * Copyright (c) 2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) 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/suspend.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/time.h> | ||
27 | #include <linux/sysdev.h> | ||
28 | |||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/io.h> | ||
31 | |||
32 | #include <asm/mach-types.h> | ||
33 | |||
34 | #include <asm/arch/regs-gpio.h> | ||
35 | #include <asm/arch/h1940.h> | ||
36 | |||
37 | #include "cpu.h" | ||
38 | #include "pm.h" | ||
39 | |||
40 | #ifdef CONFIG_S3C2410_PM_DEBUG | ||
41 | extern void pm_dbg(const char *fmt, ...); | ||
42 | #define DBG(fmt...) pm_dbg(fmt) | ||
43 | #else | ||
44 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | ||
45 | #endif | ||
46 | |||
47 | static void s3c2410_pm_prepare(void) | ||
48 | { | ||
49 | /* ensure at least GSTATUS3 has the resume address */ | ||
50 | |||
51 | __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3); | ||
52 | |||
53 | DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); | ||
54 | DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); | ||
55 | |||
56 | if (machine_is_h1940()) { | ||
57 | void *base = phys_to_virt(H1940_SUSPEND_CHECK); | ||
58 | unsigned long ptr; | ||
59 | unsigned long calc = 0; | ||
60 | |||
61 | /* generate check for the bootloader to check on resume */ | ||
62 | |||
63 | for (ptr = 0; ptr < 0x40000; ptr += 0x400) | ||
64 | calc += __raw_readl(base+ptr); | ||
65 | |||
66 | __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); | ||
67 | } | ||
68 | |||
69 | /* the RX3715 uses similar code and the same H1940 and the | ||
70 | * same offsets for resume and checksum pointers */ | ||
71 | |||
72 | if (machine_is_rx3715()) { | ||
73 | void *base = phys_to_virt(H1940_SUSPEND_CHECK); | ||
74 | unsigned long ptr; | ||
75 | unsigned long calc = 0; | ||
76 | |||
77 | /* generate check for the bootloader to check on resume */ | ||
78 | |||
79 | for (ptr = 0; ptr < 0x40000; ptr += 0x4) | ||
80 | calc += __raw_readl(base+ptr); | ||
81 | |||
82 | __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); | ||
83 | } | ||
84 | |||
85 | if ( machine_is_aml_m5900() ) | ||
86 | s3c2410_gpio_setpin(S3C2410_GPF2, 1); | ||
87 | |||
88 | } | ||
89 | |||
90 | static int s3c2410_pm_resume(struct sys_device *dev) | ||
91 | { | ||
92 | unsigned long tmp; | ||
93 | |||
94 | /* unset the return-from-sleep flag, to ensure reset */ | ||
95 | |||
96 | tmp = __raw_readl(S3C2410_GSTATUS2); | ||
97 | tmp &= S3C2410_GSTATUS2_OFFRESET; | ||
98 | __raw_writel(tmp, S3C2410_GSTATUS2); | ||
99 | |||
100 | if ( machine_is_aml_m5900() ) | ||
101 | s3c2410_gpio_setpin(S3C2410_GPF2, 0); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int s3c2410_pm_add(struct sys_device *dev) | ||
107 | { | ||
108 | pm_cpu_prep = s3c2410_pm_prepare; | ||
109 | pm_cpu_sleep = s3c2410_cpu_suspend; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | #if defined(CONFIG_CPU_S3C2410) | ||
115 | static struct sysdev_driver s3c2410_pm_driver = { | ||
116 | .add = s3c2410_pm_add, | ||
117 | .resume = s3c2410_pm_resume, | ||
118 | }; | ||
119 | |||
120 | /* register ourselves */ | ||
121 | |||
122 | static int __init s3c2410_pm_drvinit(void) | ||
123 | { | ||
124 | return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver); | ||
125 | } | ||
126 | |||
127 | arch_initcall(s3c2410_pm_drvinit); | ||
128 | #endif | ||
129 | |||
130 | #if defined(CONFIG_CPU_S3C2440) | ||
131 | static struct sysdev_driver s3c2440_pm_driver = { | ||
132 | .add = s3c2410_pm_add, | ||
133 | .resume = s3c2410_pm_resume, | ||
134 | }; | ||
135 | |||
136 | static int __init s3c2440_pm_drvinit(void) | ||
137 | { | ||
138 | return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver); | ||
139 | } | ||
140 | |||
141 | arch_initcall(s3c2440_pm_drvinit); | ||
142 | #endif | ||
143 | |||
144 | #if defined(CONFIG_CPU_S3C2442) | ||
145 | static struct sysdev_driver s3c2442_pm_driver = { | ||
146 | .add = s3c2410_pm_add, | ||
147 | .resume = s3c2410_pm_resume, | ||
148 | }; | ||
149 | |||
150 | static int __init s3c2442_pm_drvinit(void) | ||
151 | { | ||
152 | return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver); | ||
153 | } | ||
154 | |||
155 | arch_initcall(s3c2442_pm_drvinit); | ||
156 | #endif | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S deleted file mode 100644 index 9179a1024588..000000000000 --- a/arch/arm/mach-s3c2410/s3c2410-sleep.S +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S | ||
2 | * | ||
3 | * Copyright (c) 2004 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 Power Manager (Suspend-To-RAM) support | ||
7 | * | ||
8 | * Based on PXA/SA1100 sleep code by: | ||
9 | * Nicolas Pitre, (c) 2002 Monta Vista Software Inc | ||
10 | * Cliff Brake, (c) 2001 | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/linkage.h> | ||
28 | #include <asm/assembler.h> | ||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/arch/map.h> | ||
31 | |||
32 | #include <asm/arch/regs-gpio.h> | ||
33 | #include <asm/arch/regs-clock.h> | ||
34 | #include <asm/arch/regs-mem.h> | ||
35 | #include <asm/arch/regs-serial.h> | ||
36 | |||
37 | /* s3c2410_cpu_suspend | ||
38 | * | ||
39 | * put the cpu into sleep mode | ||
40 | */ | ||
41 | |||
42 | ENTRY(s3c2410_cpu_suspend) | ||
43 | @@ prepare cpu to sleep | ||
44 | |||
45 | ldr r4, =S3C2410_REFRESH | ||
46 | ldr r5, =S3C24XX_MISCCR | ||
47 | ldr r6, =S3C2410_CLKCON | ||
48 | ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) | ||
49 | ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) | ||
50 | ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) | ||
51 | |||
52 | orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command | ||
53 | orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals | ||
54 | orr r9, r9, #S3C2410_CLKCON_POWER @ power down command | ||
55 | |||
56 | teq pc, #0 @ first as a trial-run to load cache | ||
57 | bl s3c2410_do_sleep | ||
58 | teq r0, r0 @ now do it for real | ||
59 | b s3c2410_do_sleep @ | ||
60 | |||
61 | @@ align next bit of code to cache line | ||
62 | .align 8 | ||
63 | s3c2410_do_sleep: | ||
64 | streq r7, [ r4 ] @ SDRAM sleep command | ||
65 | streq r8, [ r5 ] @ SDRAM power-down config | ||
66 | streq r9, [ r6 ] @ CPU sleep | ||
67 | 1: beq 1b | ||
68 | mov pc, r14 | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index 4cdc0d70c19f..d96fdcf2d2e3 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c | |||
@@ -31,10 +31,10 @@ | |||
31 | #include <asm/arch/regs-clock.h> | 31 | #include <asm/arch/regs-clock.h> |
32 | #include <asm/arch/regs-serial.h> | 32 | #include <asm/arch/regs-serial.h> |
33 | 33 | ||
34 | #include "s3c2410.h" | 34 | #include <asm/plat-s3c24xx/s3c2410.h> |
35 | #include "cpu.h" | 35 | #include <asm/plat-s3c24xx/cpu.h> |
36 | #include "devs.h" | 36 | #include <asm/plat-s3c24xx/devs.h> |
37 | #include "clock.h" | 37 | #include <asm/plat-s3c24xx/clock.h> |
38 | 38 | ||
39 | /* Initial IO mappings */ | 39 | /* Initial IO mappings */ |
40 | 40 | ||
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S index 2018c2e1dcc5..9179a1024588 100644 --- a/arch/arm/mach-s3c2410/sleep.S +++ b/arch/arm/mach-s3c2410/sleep.S | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/sleep.S | 1 | /* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -34,126 +34,35 @@ | |||
34 | #include <asm/arch/regs-mem.h> | 34 | #include <asm/arch/regs-mem.h> |
35 | #include <asm/arch/regs-serial.h> | 35 | #include <asm/arch/regs-serial.h> |
36 | 36 | ||
37 | /* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not | 37 | /* s3c2410_cpu_suspend |
38 | * reset the UART configuration, only enable if you really need this! | ||
39 | */ | ||
40 | //#define CONFIG_DEBUG_RESUME | ||
41 | |||
42 | .text | ||
43 | |||
44 | /* s3c2410_cpu_save | ||
45 | * | ||
46 | * save enough of the CPU state to allow us to re-start | ||
47 | * pm.c code. as we store items like the sp/lr, we will | ||
48 | * end up returning from this function when the cpu resumes | ||
49 | * so the return value is set to mark this. | ||
50 | * | ||
51 | * This arangement means we avoid having to flush the cache | ||
52 | * from this code. | ||
53 | * | ||
54 | * entry: | ||
55 | * r0 = pointer to save block | ||
56 | * | ||
57 | * exit: | ||
58 | * r0 = 0 => we stored everything | ||
59 | * 1 => resumed from sleep | ||
60 | */ | ||
61 | |||
62 | ENTRY(s3c2410_cpu_save) | ||
63 | stmfd sp!, { r4 - r12, lr } | ||
64 | |||
65 | @@ store co-processor registers | ||
66 | |||
67 | mrc p15, 0, r4, c15, c1, 0 @ CP access register | ||
68 | mrc p15, 0, r5, c13, c0, 0 @ PID | ||
69 | mrc p15, 0, r6, c3, c0, 0 @ Domain ID | ||
70 | mrc p15, 0, r7, c2, c0, 0 @ translation table base address | ||
71 | mrc p15, 0, r8, c1, c0, 0 @ control register | ||
72 | |||
73 | stmia r0, { r4 - r13 } | ||
74 | |||
75 | mov r0, #0 | ||
76 | ldmfd sp, { r4 - r12, pc } | ||
77 | |||
78 | @@ return to the caller, after having the MMU | ||
79 | @@ turned on, this restores the last bits from the | ||
80 | @@ stack | ||
81 | resume_with_mmu: | ||
82 | mov r0, #1 | ||
83 | ldmfd sp!, { r4 - r12, pc } | ||
84 | |||
85 | .ltorg | ||
86 | |||
87 | @@ the next bits sit in the .data segment, even though they | ||
88 | @@ happen to be code... the s3c2410_sleep_save_phys needs to be | ||
89 | @@ accessed by the resume code before it can restore the MMU. | ||
90 | @@ This means that the variable has to be close enough for the | ||
91 | @@ code to read it... since the .text segment needs to be RO, | ||
92 | @@ the data segment can be the only place to put this code. | ||
93 | |||
94 | .data | ||
95 | |||
96 | .global s3c2410_sleep_save_phys | ||
97 | s3c2410_sleep_save_phys: | ||
98 | .word 0 | ||
99 | |||
100 | /* s3c2410_cpu_resume | ||
101 | * | 38 | * |
102 | * resume code entry for bootloader to call | 39 | * put the cpu into sleep mode |
103 | * | ||
104 | * we must put this code here in the data segment as we have no | ||
105 | * other way of restoring the stack pointer after sleep, and we | ||
106 | * must not write to the code segment (code is read-only) | ||
107 | */ | 40 | */ |
108 | 41 | ||
109 | ENTRY(s3c2410_cpu_resume) | 42 | ENTRY(s3c2410_cpu_suspend) |
110 | mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE | 43 | @@ prepare cpu to sleep |
111 | msr cpsr_c, r0 | 44 | |
112 | 45 | ldr r4, =S3C2410_REFRESH | |
113 | @@ load UART to allow us to print the two characters for | 46 | ldr r5, =S3C24XX_MISCCR |
114 | @@ resume debug | 47 | ldr r6, =S3C2410_CLKCON |
115 | 48 | ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB) | |
116 | mov r2, #S3C24XX_PA_UART & 0xff000000 | 49 | ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB) |
117 | orr r2, r2, #S3C24XX_PA_UART & 0xff000 | 50 | ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB) |
118 | 51 | ||
119 | #if 0 | 52 | orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command |
120 | /* SMDK2440 LED set */ | 53 | orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals |
121 | mov r14, #S3C24XX_PA_GPIO | 54 | orr r9, r9, #S3C2410_CLKCON_POWER @ power down command |
122 | ldr r12, [ r14, #0x54 ] | 55 | |
123 | bic r12, r12, #3<<4 | 56 | teq pc, #0 @ first as a trial-run to load cache |
124 | orr r12, r12, #1<<7 | 57 | bl s3c2410_do_sleep |
125 | str r12, [ r14, #0x54 ] | 58 | teq r0, r0 @ now do it for real |
126 | #endif | 59 | b s3c2410_do_sleep @ |
127 | 60 | ||
128 | #ifdef CONFIG_DEBUG_RESUME | 61 | @@ align next bit of code to cache line |
129 | mov r3, #'L' | 62 | .align 8 |
130 | strb r3, [ r2, #S3C2410_UTXH ] | 63 | s3c2410_do_sleep: |
131 | 1001: | 64 | streq r7, [ r4 ] @ SDRAM sleep command |
132 | ldrb r14, [ r3, #S3C2410_UTRSTAT ] | 65 | streq r8, [ r5 ] @ SDRAM power-down config |
133 | tst r14, #S3C2410_UTRSTAT_TXE | 66 | streq r9, [ r6 ] @ CPU sleep |
134 | beq 1001b | 67 | 1: beq 1b |
135 | #endif /* CONFIG_DEBUG_RESUME */ | 68 | mov pc, r14 |
136 | |||
137 | mov r1, #0 | ||
138 | mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs | ||
139 | mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches | ||
140 | |||
141 | ldr r0, s3c2410_sleep_save_phys @ address of restore block | ||
142 | ldmia r0, { r4 - r13 } | ||
143 | |||
144 | mcr p15, 0, r4, c15, c1, 0 @ CP access register | ||
145 | mcr p15, 0, r5, c13, c0, 0 @ PID | ||
146 | mcr p15, 0, r6, c3, c0, 0 @ Domain ID | ||
147 | mcr p15, 0, r7, c2, c0, 0 @ translation table base | ||
148 | |||
149 | #ifdef CONFIG_DEBUG_RESUME | ||
150 | mov r3, #'R' | ||
151 | strb r3, [ r2, #S3C2410_UTXH ] | ||
152 | #endif | ||
153 | |||
154 | ldr r2, =resume_with_mmu | ||
155 | mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc | ||
156 | nop @ second-to-last before mmu | ||
157 | mov pc, r2 @ go back to virtual address | ||
158 | |||
159 | .ltorg | ||
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c index 22b0e1cdd4bf..bcd562ac1d3d 100644 --- a/arch/arm/mach-s3c2410/usb-simtec.c +++ b/arch/arm/mach-s3c2410/usb-simtec.c | |||
@@ -35,7 +35,7 @@ | |||
35 | #include <asm/io.h> | 35 | #include <asm/io.h> |
36 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
37 | 37 | ||
38 | #include "devs.h" | 38 | #include <asm/plat-s3c24xx/devs.h> |
39 | #include "usb-simtec.h" | 39 | #include "usb-simtec.h" |
40 | 40 | ||
41 | /* control power and monitor over-current events on various Simtec | 41 | /* control power and monitor over-current events on various Simtec |
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig new file mode 100644 index 000000000000..6d629de84cdb --- /dev/null +++ b/arch/arm/mach-s3c2412/Kconfig | |||
@@ -0,0 +1,58 @@ | |||
1 | # arch/arm/mach-s3c2412/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | config CPU_S3C2412 | ||
8 | bool | ||
9 | depends on ARCH_S3C2410 | ||
10 | select S3C2412_PM if PM | ||
11 | select S3C2412_DMA if S3C2410_DMA | ||
12 | help | ||
13 | Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line | ||
14 | |||
15 | config CPU_S3C2412_ONLY | ||
16 | bool | ||
17 | depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \ | ||
18 | !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412 | ||
19 | default y if CPU_S3C2412 | ||
20 | |||
21 | config S3C2412_DMA | ||
22 | bool | ||
23 | depends on CPU_S3C2412 | ||
24 | help | ||
25 | Internal config node for S3C2412 DMA support | ||
26 | |||
27 | config S3C2412_PM | ||
28 | bool | ||
29 | help | ||
30 | Internal config node to apply S3C2412 power management | ||
31 | |||
32 | |||
33 | menu "S3C2412 Machines" | ||
34 | |||
35 | config MACH_SMDK2413 | ||
36 | bool "SMDK2413" | ||
37 | select CPU_S3C2412 | ||
38 | select MACH_S3C2413 | ||
39 | select MACH_SMDK | ||
40 | help | ||
41 | Say Y here if you are using an SMDK2413 | ||
42 | |||
43 | config MACH_S3C2413 | ||
44 | bool | ||
45 | help | ||
46 | Internal node for S3C2413 version of SMDK2413, so that | ||
47 | machine_is_s3c2413() will work when MACH_SMDK2413 is | ||
48 | selected | ||
49 | |||
50 | config MACH_VSTMS | ||
51 | bool "VMSTMS" | ||
52 | select CPU_S3C2412 | ||
53 | help | ||
54 | Say Y here if you are using an VSTMS board | ||
55 | |||
56 | |||
57 | endmenu | ||
58 | |||
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile new file mode 100644 index 000000000000..f8e011691b31 --- /dev/null +++ b/arch/arm/mach-s3c2412/Makefile | |||
@@ -0,0 +1,21 @@ | |||
1 | # arch/arm/mach-s3c2412/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_S3C2412) += s3c2412.o | ||
13 | obj-$(CONFIG_CPU_S3C2412) += irq.o | ||
14 | obj-$(CONFIG_CPU_S3C2412) += clock.o | ||
15 | obj-$(CONFIG_S3C2412_DMA) += dma.o | ||
16 | obj-$(CONFIG_S3C2412_PM) += pm.o | ||
17 | |||
18 | # Machine support | ||
19 | |||
20 | obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o | ||
21 | obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o | ||
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2412/clock.c index 8f94ad83901d..6a8e4448770b 100644 --- a/arch/arm/mach-s3c2410/s3c2412-clock.c +++ b/arch/arm/mach-s3c2412/clock.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2412-clock.c | 1 | /* linux/arch/arm/mach-s3c2412/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -41,9 +41,9 @@ | |||
41 | #include <asm/arch/regs-clock.h> | 41 | #include <asm/arch/regs-clock.h> |
42 | #include <asm/arch/regs-gpio.h> | 42 | #include <asm/arch/regs-gpio.h> |
43 | 43 | ||
44 | #include "s3c2412.h" | 44 | #include <asm/plat-s3c24xx/s3c2412.h> |
45 | #include "clock.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
46 | #include "cpu.h" | 46 | #include <asm/plat-s3c24xx/cpu.h> |
47 | 47 | ||
48 | /* We currently have to assume that the system is running | 48 | /* We currently have to assume that the system is running |
49 | * from the XTPll input, and that all ***REFCLKs are being | 49 | * from the XTPll input, and that all ***REFCLKs are being |
diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2412/dma.c index 138f726ac6bf..28b598287fae 100644 --- a/arch/arm/mach-s3c2410/s3c2412-dma.c +++ b/arch/arm/mach-s3c2412/dma.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2412-dma.c | 1 | /* linux/arch/arm/mach-s3c2412/dma.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -21,8 +21,8 @@ | |||
21 | #include <asm/arch/dma.h> | 21 | #include <asm/arch/dma.h> |
22 | #include <asm/io.h> | 22 | #include <asm/io.h> |
23 | 23 | ||
24 | #include "dma.h" | 24 | #include <asm/plat-s3c24xx/dma.h> |
25 | #include "cpu.h" | 25 | #include <asm/plat-s3c24xx/cpu.h> |
26 | 26 | ||
27 | #include <asm/arch/regs-serial.h> | 27 | #include <asm/arch/regs-serial.h> |
28 | #include <asm/arch/regs-gpio.h> | 28 | #include <asm/arch/regs-gpio.h> |
diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2412/irq.c index ffcc30b23a80..e89dbdcb1b7b 100644 --- a/arch/arm/mach-s3c2410/s3c2412-irq.c +++ b/arch/arm/mach-s3c2412/irq.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2412/s3c2412-irq.c | 1 | /* linux/arch/arm/mach-s3c2412/irq.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -35,9 +35,9 @@ | |||
35 | #include <asm/arch/regs-irq.h> | 35 | #include <asm/arch/regs-irq.h> |
36 | #include <asm/arch/regs-gpio.h> | 36 | #include <asm/arch/regs-gpio.h> |
37 | 37 | ||
38 | #include "cpu.h" | 38 | #include <asm/plat-s3c24xx/cpu.h> |
39 | #include "irq.h" | 39 | #include <asm/plat-s3c24xx/irq.h> |
40 | #include "pm.h" | 40 | #include <asm/plat-s3c24xx/pm.h> |
41 | 41 | ||
42 | /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by | 42 | /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by |
43 | * having them turn up in both the INT* and the EINT* registers. Whilst | 43 | * having them turn up in both the INT* and the EINT* registers. Whilst |
diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c index 4f89abd7a6df..32b15617ef2a 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2413.c +++ b/arch/arm/mach-s3c2412/mach-smdk2413.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-smdk2413.c | 1 | /* linux/arch/arm/mach-s3c2412/mach-smdk2413.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -39,13 +39,13 @@ | |||
39 | #include <asm/arch/idle.h> | 39 | #include <asm/arch/idle.h> |
40 | #include <asm/arch/fb.h> | 40 | #include <asm/arch/fb.h> |
41 | 41 | ||
42 | #include "s3c2410.h" | 42 | #include <asm/plat-s3c24xx/s3c2410.h> |
43 | #include "s3c2412.h" | 43 | #include <asm/plat-s3c24xx/s3c2412.h> |
44 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/clock.h> |
45 | #include "devs.h" | 45 | #include <asm/plat-s3c24xx/devs.h> |
46 | #include "cpu.h" | 46 | #include <asm/plat-s3c24xx/cpu.h> |
47 | 47 | ||
48 | #include "common-smdk.h" | 48 | #include <asm/plat-s3c24xx/common-smdk.h> |
49 | 49 | ||
50 | static struct map_desc smdk2413_iodesc[] __initdata = { | 50 | static struct map_desc smdk2413_iodesc[] __initdata = { |
51 | }; | 51 | }; |
diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c index 0360e1055bcd..f1afb707ff16 100644 --- a/arch/arm/mach-s3c2410/mach-vstms.c +++ b/arch/arm/mach-s3c2412/mach-vstms.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-vstms.c | 1 | /* linux/arch/arm/mach-s3c2412/mach-vstms.c |
2 | * | 2 | * |
3 | * (C) 2006 Thomas Gleixner <tglx@linutronix.de> | 3 | * (C) 2006 Thomas Gleixner <tglx@linutronix.de> |
4 | * | 4 | * |
@@ -43,11 +43,11 @@ | |||
43 | 43 | ||
44 | #include <asm/arch/nand.h> | 44 | #include <asm/arch/nand.h> |
45 | 45 | ||
46 | #include "s3c2410.h" | 46 | #include <asm/plat-s3c24xx/s3c2410.h> |
47 | #include "s3c2412.h" | 47 | #include <asm/plat-s3c24xx/s3c2412.h> |
48 | #include "clock.h" | 48 | #include <asm/plat-s3c24xx/clock.h> |
49 | #include "devs.h" | 49 | #include <asm/plat-s3c24xx/devs.h> |
50 | #include "cpu.h" | 50 | #include <asm/plat-s3c24xx/cpu.h> |
51 | 51 | ||
52 | 52 | ||
53 | static struct map_desc vstms_iodesc[] __initdata = { | 53 | static struct map_desc vstms_iodesc[] __initdata = { |
diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2412/pm.c index 19b63322d259..8988dac388a9 100644 --- a/arch/arm/mach-s3c2410/s3c2412-pm.c +++ b/arch/arm/mach-s3c2412/pm.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2412-pm.c | 1 | /* linux/arch/arm/mach-s3c2412/pm.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -28,10 +28,10 @@ | |||
28 | #include <asm/arch/regs-gpio.h> | 28 | #include <asm/arch/regs-gpio.h> |
29 | #include <asm/arch/regs-dsc.h> | 29 | #include <asm/arch/regs-dsc.h> |
30 | 30 | ||
31 | #include "cpu.h" | 31 | #include <asm/plat-s3c24xx/cpu.h> |
32 | #include "pm.h" | 32 | #include <asm/plat-s3c24xx/pm.h> |
33 | 33 | ||
34 | #include "s3c2412.h" | 34 | #include <asm/plat-s3c24xx/s3c2412.h> |
35 | 35 | ||
36 | static void s3c2412_cpu_suspend(void) | 36 | static void s3c2412_cpu_suspend(void) |
37 | { | 37 | { |
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index 2f651a811ecd..aafe0bc593f1 100644 --- a/arch/arm/mach-s3c2410/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2412.c | 1 | /* linux/arch/arm/mach-s3c2412/s3c2412.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -38,11 +38,11 @@ | |||
38 | #include <asm/arch/regs-gpioj.h> | 38 | #include <asm/arch/regs-gpioj.h> |
39 | #include <asm/arch/regs-dsc.h> | 39 | #include <asm/arch/regs-dsc.h> |
40 | 40 | ||
41 | #include "s3c2412.h" | 41 | #include <asm/plat-s3c24xx/s3c2412.h> |
42 | #include "cpu.h" | 42 | #include <asm/plat-s3c24xx/cpu.h> |
43 | #include "devs.h" | 43 | #include <asm/plat-s3c24xx/devs.h> |
44 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/clock.h> |
45 | #include "pm.h" | 45 | #include <asm/plat-s3c24xx/pm.h> |
46 | 46 | ||
47 | #ifndef CONFIG_CPU_S3C2412_ONLY | 47 | #ifndef CONFIG_CPU_S3C2412_ONLY |
48 | void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; | 48 | void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; |
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig new file mode 100644 index 000000000000..e3bfda098c0f --- /dev/null +++ b/arch/arm/mach-s3c2440/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | # arch/arm/mach-s3c2440/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | config CPU_S3C2440 | ||
8 | bool | ||
9 | depends on ARCH_S3C2410 | ||
10 | select S3C2410_CLOCK | ||
11 | select S3C2410_PM if PM | ||
12 | select S3C2410_GPIO | ||
13 | select S3C2440_DMA if S3C2410_DMA | ||
14 | select CPU_S3C244X | ||
15 | help | ||
16 | Support for S3C2440 Samsung Mobile CPU based systems. | ||
17 | |||
18 | config S3C2440_DMA | ||
19 | bool | ||
20 | depends on ARCH_S3C2410 && CPU_S3C24405B | ||
21 | help | ||
22 | Support for S3C2440 specific DMA code5A | ||
23 | |||
24 | |||
25 | menu "S3C2440 Machines" | ||
26 | |||
27 | config MACH_ANUBIS | ||
28 | bool "Simtec Electronics ANUBIS" | ||
29 | select CPU_S3C2440 | ||
30 | select PM_SIMTEC if PM | ||
31 | help | ||
32 | Say Y here if you are using the Simtec Electronics ANUBIS | ||
33 | development system | ||
34 | |||
35 | config MACH_OSIRIS | ||
36 | bool "Simtec IM2440D20 (OSIRIS) module" | ||
37 | select CPU_S3C2440 | ||
38 | select PM_SIMTEC if PM | ||
39 | help | ||
40 | Say Y here if you are using the Simtec IM2440D20 module, also | ||
41 | known as the Osiris. | ||
42 | |||
43 | config MACH_RX3715 | ||
44 | bool "HP iPAQ rx3715" | ||
45 | select CPU_S3C2440 | ||
46 | select PM_H1940 if PM | ||
47 | help | ||
48 | Say Y here if you are using the HP iPAQ rx3715. | ||
49 | |||
50 | config ARCH_S3C2440 | ||
51 | bool "SMDK2440" | ||
52 | select CPU_S3C2440 | ||
53 | select MACH_SMDK | ||
54 | help | ||
55 | Say Y here if you are using the SMDK2440. | ||
56 | |||
57 | config MACH_NEXCODER_2440 | ||
58 | bool "NexVision NEXCODER 2440 Light Board" | ||
59 | select CPU_S3C2440 | ||
60 | help | ||
61 | Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board | ||
62 | |||
63 | config SMDK2440_CPU2440 | ||
64 | bool "SMDK2440 with S3C2440 CPU module" | ||
65 | depends on ARCH_S3C2440 | ||
66 | default y if ARCH_S3C2440 | ||
67 | select CPU_S3C2440 | ||
68 | |||
69 | |||
70 | endmenu | ||
71 | |||
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile new file mode 100644 index 000000000000..c81ed6248dcb --- /dev/null +++ b/arch/arm/mach-s3c2440/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # arch/arm/mach-s3c2440/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_S3C2440) += s3c2440.o dsc.o | ||
13 | obj-$(CONFIG_CPU_S3C2440) += irq.o | ||
14 | obj-$(CONFIG_CPU_S3C2440) += clock.o | ||
15 | obj-$(CONFIG_S3C2440_DMA) += dma.o | ||
16 | |||
17 | # Machine support | ||
18 | |||
19 | obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o | ||
20 | obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o | ||
21 | obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o | ||
22 | obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o | ||
23 | obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o | ||
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2440/clock.c index ba13c1d079d1..79e2ea4adaf3 100644 --- a/arch/arm/mach-s3c2410/s3c2440-clock.c +++ b/arch/arm/mach-s3c2440/clock.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2440-clock.c | 1 | /* linux/arch/arm/mach-s3c2440/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * http://armlinux.simtec.co.uk/ | 4 | * http://armlinux.simtec.co.uk/ |
@@ -41,8 +41,8 @@ | |||
41 | 41 | ||
42 | #include <asm/arch/regs-clock.h> | 42 | #include <asm/arch/regs-clock.h> |
43 | 43 | ||
44 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/clock.h> |
45 | #include "cpu.h" | 45 | #include <asm/plat-s3c24xx/cpu.h> |
46 | 46 | ||
47 | /* S3C2440 extended clock support */ | 47 | /* S3C2440 extended clock support */ |
48 | 48 | ||
diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2440/dma.c index 47b861b9443d..8e51137620f2 100644 --- a/arch/arm/mach-s3c2410/s3c2440-dma.c +++ b/arch/arm/mach-s3c2440/dma.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2440-dma.c | 1 | /* linux/arch/arm/mach-s3c2440/dma.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -19,9 +19,9 @@ | |||
19 | 19 | ||
20 | #include <asm/dma.h> | 20 | #include <asm/dma.h> |
21 | #include <asm/arch/dma.h> | 21 | #include <asm/arch/dma.h> |
22 | #include "dma.h" | 22 | #include <asm/plat-s3c24xx/dma.h> |
23 | 23 | ||
24 | #include "cpu.h" | 24 | #include <asm/plat-s3c24xx/cpu.h> |
25 | 25 | ||
26 | #include <asm/arch/regs-serial.h> | 26 | #include <asm/arch/regs-serial.h> |
27 | #include <asm/arch/regs-gpio.h> | 27 | #include <asm/arch/regs-gpio.h> |
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2440/dsc.c index c92ea66ba45e..2995ff5681bb 100644 --- a/arch/arm/mach-s3c2410/s3c2440-dsc.c +++ b/arch/arm/mach-s3c2440/dsc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c | 1 | /* linux/arch/arm/mach-s3c2440/dsc.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -27,8 +27,8 @@ | |||
27 | #include <asm/arch/regs-gpio.h> | 27 | #include <asm/arch/regs-gpio.h> |
28 | #include <asm/arch/regs-dsc.h> | 28 | #include <asm/arch/regs-dsc.h> |
29 | 29 | ||
30 | #include "cpu.h" | 30 | #include <asm/plat-s3c24xx/cpu.h> |
31 | #include "s3c2440.h" | 31 | #include <asm/plat-s3c24xx/s3c2440.h> |
32 | 32 | ||
33 | int s3c2440_set_dsc(unsigned int pin, unsigned int value) | 33 | int s3c2440_set_dsc(unsigned int pin, unsigned int value) |
34 | { | 34 | { |
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2440/irq.c index 1ba19b27ab05..1069d13d8c57 100644 --- a/arch/arm/mach-s3c2410/s3c2440-irq.c +++ b/arch/arm/mach-s3c2440/irq.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2440-irq.c | 1 | /* linux/arch/arm/mach-s3c2440/irq.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2003,2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -35,9 +35,9 @@ | |||
35 | #include <asm/arch/regs-irq.h> | 35 | #include <asm/arch/regs-irq.h> |
36 | #include <asm/arch/regs-gpio.h> | 36 | #include <asm/arch/regs-gpio.h> |
37 | 37 | ||
38 | #include "cpu.h" | 38 | #include <asm/plat-s3c24xx/cpu.h> |
39 | #include "pm.h" | 39 | #include <asm/plat-s3c24xx/pm.h> |
40 | #include "irq.h" | 40 | #include <asm/plat-s3c24xx/irq.h> |
41 | 41 | ||
42 | /* WDT/AC97 */ | 42 | /* WDT/AC97 */ |
43 | 43 | ||
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c index 0fad0c2fe07b..3f0288eb1ed5 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2440/mach-anubis.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-anubis.c | 1 | /* linux/arch/arm/mach-s3c2440/mach-anubis.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003-2005 Simtec Electronics | 3 | * Copyright (c) 2003-2005 Simtec Electronics |
4 | * http://armlinux.simtec.co.uk/ | 4 | * http://armlinux.simtec.co.uk/ |
@@ -42,9 +42,9 @@ | |||
42 | #include <linux/mtd/nand_ecc.h> | 42 | #include <linux/mtd/nand_ecc.h> |
43 | #include <linux/mtd/partitions.h> | 43 | #include <linux/mtd/partitions.h> |
44 | 44 | ||
45 | #include "clock.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
46 | #include "devs.h" | 46 | #include <asm/plat-s3c24xx/devs.h> |
47 | #include "cpu.h" | 47 | #include <asm/plat-s3c24xx/cpu.h> |
48 | 48 | ||
49 | #define COPYRIGHT ", (c) 2005 Simtec Electronics" | 49 | #define COPYRIGHT ", (c) 2005 Simtec Electronics" |
50 | 50 | ||
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c index d6dfdad8c90b..6d551d88330b 100644 --- a/arch/arm/mach-s3c2410/mach-nexcoder.c +++ b/arch/arm/mach-s3c2440/mach-nexcoder.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-nexcoder.c | 1 | /* linux/arch/arm/mach-s3c2440/mach-nexcoder.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Nex Vision | 3 | * Copyright (c) 2004 Nex Vision |
4 | * Guillaume GOURAT <guillaume.gourat@nexvision.tv> | 4 | * Guillaume GOURAT <guillaume.gourat@nexvision.tv> |
@@ -38,11 +38,11 @@ | |||
38 | #include <asm/arch/regs-gpio.h> | 38 | #include <asm/arch/regs-gpio.h> |
39 | #include <asm/arch/regs-serial.h> | 39 | #include <asm/arch/regs-serial.h> |
40 | 40 | ||
41 | #include "s3c2410.h" | 41 | #include <asm/plat-s3c24xx/s3c2410.h> |
42 | #include "s3c2440.h" | 42 | #include <asm/plat-s3c24xx/s3c2440.h> |
43 | #include "clock.h" | 43 | #include <asm/plat-s3c24xx/clock.h> |
44 | #include "devs.h" | 44 | #include <asm/plat-s3c24xx/devs.h> |
45 | #include "cpu.h" | 45 | #include <asm/plat-s3c24xx/cpu.h> |
46 | 46 | ||
47 | static struct map_desc nexcoder_iodesc[] __initdata = { | 47 | static struct map_desc nexcoder_iodesc[] __initdata = { |
48 | /* nothing here yet */ | 48 | /* nothing here yet */ |
diff --git a/arch/arm/mach-s3c2410/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 37b40850c9b9..2ed8e51f20c8 100644 --- a/arch/arm/mach-s3c2410/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-osiris.c | 1 | /* linux/arch/arm/mach-s3c2440/mach-osiris.c |
2 | * | 2 | * |
3 | * Copyright (c) 2005 Simtec Electronics | 3 | * Copyright (c) 2005 Simtec Electronics |
4 | * http://armlinux.simtec.co.uk/ | 4 | * http://armlinux.simtec.co.uk/ |
@@ -41,9 +41,9 @@ | |||
41 | #include <linux/mtd/nand_ecc.h> | 41 | #include <linux/mtd/nand_ecc.h> |
42 | #include <linux/mtd/partitions.h> | 42 | #include <linux/mtd/partitions.h> |
43 | 43 | ||
44 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/clock.h> |
45 | #include "devs.h" | 45 | #include <asm/plat-s3c24xx/devs.h> |
46 | #include "cpu.h" | 46 | #include <asm/plat-s3c24xx/cpu.h> |
47 | 47 | ||
48 | /* onboard perihpheral map */ | 48 | /* onboard perihpheral map */ |
49 | 49 | ||
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c index ecbcdf79d739..1d4e19bd9206 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2440/mach-rx3715.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-rx3715.c | 1 | /* linux/arch/arm/mach-s3c2440/mach-rx3715.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2003,2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -46,10 +46,10 @@ | |||
46 | #include <asm/arch/nand.h> | 46 | #include <asm/arch/nand.h> |
47 | #include <asm/arch/fb.h> | 47 | #include <asm/arch/fb.h> |
48 | 48 | ||
49 | #include "clock.h" | 49 | #include <asm/plat-s3c24xx/clock.h> |
50 | #include "devs.h" | 50 | #include <asm/plat-s3c24xx/devs.h> |
51 | #include "cpu.h" | 51 | #include <asm/plat-s3c24xx/cpu.h> |
52 | #include "pm.h" | 52 | #include <asm/plat-s3c24xx/pm.h> |
53 | 53 | ||
54 | static struct map_desc rx3715_iodesc[] __initdata = { | 54 | static struct map_desc rx3715_iodesc[] __initdata = { |
55 | /* dump ISA space somewhere unused */ | 55 | /* dump ISA space somewhere unused */ |
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c index 2b61f4ed1da4..270e42b9b5c1 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2440/mach-smdk2440.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/mach-smdk2440.c | 1 | /* linux/arch/arm/mach-s3c2440/mach-smdk2440.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004,2005 Simtec Electronics | 3 | * Copyright (c) 2004,2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -40,13 +40,13 @@ | |||
40 | #include <asm/arch/idle.h> | 40 | #include <asm/arch/idle.h> |
41 | #include <asm/arch/fb.h> | 41 | #include <asm/arch/fb.h> |
42 | 42 | ||
43 | #include "s3c2410.h" | 43 | #include <asm/plat-s3c24xx/s3c2410.h> |
44 | #include "s3c2440.h" | 44 | #include <asm/plat-s3c24xx/s3c2440.h> |
45 | #include "clock.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
46 | #include "devs.h" | 46 | #include <asm/plat-s3c24xx/devs.h> |
47 | #include "cpu.h" | 47 | #include <asm/plat-s3c24xx/cpu.h> |
48 | 48 | ||
49 | #include "common-smdk.h" | 49 | #include <asm/plat-s3c24xx/common-smdk.h> |
50 | 50 | ||
51 | static struct map_desc smdk2440_iodesc[] __initdata = { | 51 | static struct map_desc smdk2440_iodesc[] __initdata = { |
52 | /* ISA IO Space map (memory space selected by A24) */ | 52 | /* ISA IO Space map (memory space selected by A24) */ |
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c index 344eb27cca48..90e1da61fbc3 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2440/s3c2440.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2440.c | 1 | /* linux/arch/arm/mach-s3c2440/s3c2440.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2006 Simtec Electronics | 3 | * Copyright (c) 2004-2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -29,9 +29,9 @@ | |||
29 | #include <asm/io.h> | 29 | #include <asm/io.h> |
30 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
31 | 31 | ||
32 | #include "s3c2440.h" | 32 | #include <asm/plat-s3c24xx/s3c2440.h> |
33 | #include "devs.h" | 33 | #include <asm/plat-s3c24xx/devs.h> |
34 | #include "cpu.h" | 34 | #include <asm/plat-s3c24xx/cpu.h> |
35 | 35 | ||
36 | static struct sys_device s3c2440_sysdev = { | 36 | static struct sys_device s3c2440_sysdev = { |
37 | .cls = &s3c2440_sysclass, | 37 | .cls = &s3c2440_sysclass, |
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig new file mode 100644 index 000000000000..bf8d87abfab3 --- /dev/null +++ b/arch/arm/mach-s3c2442/Kconfig | |||
@@ -0,0 +1,27 @@ | |||
1 | # arch/arm/mach-s3c2442/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | config CPU_S3C2442 | ||
8 | bool | ||
9 | depends on ARCH_S3C2420 | ||
10 | select S3C2410_CLOCK | ||
11 | select S3C2410_GPIO | ||
12 | select S3C2410_PM if PM | ||
13 | select CPU_S3C244X | ||
14 | help | ||
15 | Support for S3C2442 Samsung Mobile CPU based systems. | ||
16 | |||
17 | |||
18 | menu "S3C2442 Machines" | ||
19 | |||
20 | config SMDK2440_CPU2442 | ||
21 | bool "SMDM2440 with S3C2442 CPU module" | ||
22 | depends on ARCH_S3C2440 | ||
23 | select CPU_S3C2442 | ||
24 | |||
25 | |||
26 | endmenu | ||
27 | |||
diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile new file mode 100644 index 000000000000..2a909c6c5798 --- /dev/null +++ b/arch/arm/mach-s3c2442/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | # arch/arm/mach-s3c2442/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_S3C2442) += s3c2442.o | ||
13 | obj-$(CONFIG_CPU_S3C2442) += clock.o | ||
14 | |||
15 | # Machine support | ||
16 | |||
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2442/clock.c index 4e292ca7c9be..5b9e830ac4d3 100644 --- a/arch/arm/mach-s3c2410/s3c2442-clock.c +++ b/arch/arm/mach-s3c2442/clock.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2442-clock.c | 1 | /* linux/arch/arm/mach-s3c2442/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * http://armlinux.simtec.co.uk/ | 4 | * http://armlinux.simtec.co.uk/ |
@@ -41,8 +41,8 @@ | |||
41 | 41 | ||
42 | #include <asm/arch/regs-clock.h> | 42 | #include <asm/arch/regs-clock.h> |
43 | 43 | ||
44 | #include "clock.h" | 44 | #include <asm/plat-s3c24xx/clock.h> |
45 | #include "cpu.h" | 45 | #include <asm/plat-s3c24xx/cpu.h> |
46 | 46 | ||
47 | /* S3C2442 extended clock support */ | 47 | /* S3C2442 extended clock support */ |
48 | 48 | ||
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c index 428732ee68c4..fbf8264249da 100644 --- a/arch/arm/mach-s3c2410/s3c2442.c +++ b/arch/arm/mach-s3c2442/s3c2442.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c2442.c | 1 | /* linux/arch/arm/mach-s3c2442/s3c2442.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/serial_core.h> | 19 | #include <linux/serial_core.h> |
20 | #include <linux/sysdev.h> | 20 | #include <linux/sysdev.h> |
21 | 21 | ||
22 | #include "s3c2442.h" | 22 | #include <asm/plat-s3c24xx/s3c2442.h> |
23 | #include "cpu.h" | 23 | #include <asm/plat-s3c24xx/cpu.h> |
24 | 24 | ||
25 | static struct sys_device s3c2442_sysdev = { | 25 | static struct sys_device s3c2442_sysdev = { |
26 | .cls = &s3c2442_sysclass, | 26 | .cls = &s3c2442_sysclass, |
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig new file mode 100644 index 000000000000..97813645b5ee --- /dev/null +++ b/arch/arm/plat-s3c24xx/Kconfig | |||
@@ -0,0 +1,96 @@ | |||
1 | # arch/arm/plat-s3c24xx/Kconfig | ||
2 | # | ||
3 | # Copyright 2007 Simtec Electronics | ||
4 | # | ||
5 | # Licensed under GPLv2 | ||
6 | |||
7 | config PLAT_S3C24XX | ||
8 | bool | ||
9 | depends on ARCH_S3C2410 | ||
10 | default y | ||
11 | help | ||
12 | Base platform code for any Samsung S3C device | ||
13 | |||
14 | config CPU_S3C244X | ||
15 | bool | ||
16 | depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) | ||
17 | help | ||
18 | Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems. | ||
19 | |||
20 | config PM_SIMTEC | ||
21 | bool | ||
22 | help | ||
23 | Common power management code for systems that are | ||
24 | compatible with the Simtec style of power management | ||
25 | |||
26 | config S3C2410_BOOT_WATCHDOG | ||
27 | bool "S3C2410 Initialisation watchdog" | ||
28 | depends on ARCH_S3C2410 && S3C2410_WATCHDOG | ||
29 | help | ||
30 | Say y to enable the watchdog during the kernel decompression | ||
31 | stage. If the kernel fails to uncompress, then the watchdog | ||
32 | will trigger a reset and the system should restart. | ||
33 | |||
34 | config S3C2410_BOOT_ERROR_RESET | ||
35 | bool "S3C2410 Reboot on decompression error" | ||
36 | depends on ARCH_S3C2410 | ||
37 | help | ||
38 | Say y here to use the watchdog to reset the system if the | ||
39 | kernel decompressor detects an error during decompression. | ||
40 | |||
41 | config S3C2410_PM_DEBUG | ||
42 | bool "S3C2410 PM Suspend debug" | ||
43 | depends on ARCH_S3C2410 && PM | ||
44 | help | ||
45 | Say Y here if you want verbose debugging from the PM Suspend and | ||
46 | Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt> | ||
47 | for more information. | ||
48 | |||
49 | config S3C2410_PM_CHECK | ||
50 | bool "S3C2410 PM Suspend Memory CRC" | ||
51 | depends on ARCH_S3C2410 && PM && CRC32 | ||
52 | help | ||
53 | Enable the PM code's memory area checksum over sleep. This option | ||
54 | will generate CRCs of all blocks of memory, and store them before | ||
55 | going to sleep. The blocks are then checked on resume for any | ||
56 | errors. | ||
57 | |||
58 | config S3C2410_PM_CHECK_CHUNKSIZE | ||
59 | int "S3C2410 PM Suspend CRC Chunksize (KiB)" | ||
60 | depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK | ||
61 | default 64 | ||
62 | help | ||
63 | Set the chunksize in Kilobytes of the CRC for checking memory | ||
64 | corruption over suspend and resume. A smaller value will mean that | ||
65 | the CRC data block will take more memory, but wil identify any | ||
66 | faults with better precision. | ||
67 | |||
68 | config S3C2410_LOWLEVEL_UART_PORT | ||
69 | int "S3C2410 UART to use for low-level messages" | ||
70 | default 0 | ||
71 | help | ||
72 | Choice of which UART port to use for the low-level messages, | ||
73 | such as the `Uncompressing...` at start time. The value of | ||
74 | this configuration should be between zero and two. The port | ||
75 | must have been initialised by the boot-loader before use. | ||
76 | |||
77 | config S3C2410_DMA | ||
78 | bool "S3C2410 DMA support" | ||
79 | depends on ARCH_S3C2410 | ||
80 | help | ||
81 | S3C2410 DMA support. This is needed for drivers like sound which | ||
82 | use the S3C2410's DMA system to move data to and from the | ||
83 | peripheral blocks. | ||
84 | |||
85 | config S3C2410_DMA_DEBUG | ||
86 | bool "S3C2410 DMA support debug" | ||
87 | depends on ARCH_S3C2410 && S3C2410_DMA | ||
88 | help | ||
89 | Enable debugging output for the DMA code. This option sends info | ||
90 | to the kernel log, at priority KERN_DEBUG. | ||
91 | |||
92 | config MACH_SMDK | ||
93 | bool | ||
94 | help | ||
95 | Common machine code for SMDK2410 and SMDK2440 | ||
96 | |||
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile new file mode 100644 index 000000000000..8e5ccaa1f03c --- /dev/null +++ b/arch/arm/plat-s3c24xx/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | # arch/arm/plat-s3c24xx/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 | |||
13 | # Core files | ||
14 | |||
15 | obj-y += cpu.o | ||
16 | obj-y += irq.o | ||
17 | obj-y += devs.o | ||
18 | obj-y += gpio.o | ||
19 | obj-y += time.o | ||
20 | obj-y += clock.o | ||
21 | |||
22 | # Architecture dependant builds | ||
23 | |||
24 | obj-$(CONFIG_CPU_S3C244X) += s3c244x.o | ||
25 | obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o | ||
26 | obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o | ||
27 | obj-$(CONFIG_PM) += pm.o | ||
28 | obj-$(CONFIG_PM) += sleep.o | ||
29 | obj-$(CONFIG_S3C2410_DMA) += dma.o | ||
30 | obj-$(CONFIG_MACH_SMDK) += common-smdk.o | ||
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c new file mode 100644 index 000000000000..d3dc03a7383a --- /dev/null +++ b/arch/arm/plat-s3c24xx/clock.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/clock.c | ||
2 | * | ||
3 | * Copyright (c) 2004-2005 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C24XX Core clock control support | ||
7 | * | ||
8 | * Based on, and code from linux/arch/arm/mach-versatile/clock.c | ||
9 | ** | ||
10 | ** Copyright (C) 2004 ARM Limited. | ||
11 | ** Written by Deep Blue Solutions Limited. | ||
12 | * | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/err.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/sysdev.h> | ||
37 | #include <linux/interrupt.h> | ||
38 | #include <linux/ioport.h> | ||
39 | #include <linux/clk.h> | ||
40 | #include <linux/mutex.h> | ||
41 | #include <linux/delay.h> | ||
42 | |||
43 | #include <asm/hardware.h> | ||
44 | #include <asm/irq.h> | ||
45 | #include <asm/io.h> | ||
46 | |||
47 | #include <asm/arch/regs-clock.h> | ||
48 | #include <asm/arch/regs-gpio.h> | ||
49 | |||
50 | #include <asm/plat-s3c24xx/clock.h> | ||
51 | #include <asm/plat-s3c24xx/cpu.h> | ||
52 | |||
53 | /* clock information */ | ||
54 | |||
55 | static LIST_HEAD(clocks); | ||
56 | |||
57 | DEFINE_MUTEX(clocks_mutex); | ||
58 | |||
59 | /* enable and disable calls for use with the clk struct */ | ||
60 | |||
61 | static int clk_null_enable(struct clk *clk, int enable) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* Clock API calls */ | ||
67 | |||
68 | struct clk *clk_get(struct device *dev, const char *id) | ||
69 | { | ||
70 | struct clk *p; | ||
71 | struct clk *clk = ERR_PTR(-ENOENT); | ||
72 | int idno; | ||
73 | |||
74 | if (dev == NULL || dev->bus != &platform_bus_type) | ||
75 | idno = -1; | ||
76 | else | ||
77 | idno = to_platform_device(dev)->id; | ||
78 | |||
79 | mutex_lock(&clocks_mutex); | ||
80 | |||
81 | list_for_each_entry(p, &clocks, list) { | ||
82 | if (p->id == idno && | ||
83 | strcmp(id, p->name) == 0 && | ||
84 | try_module_get(p->owner)) { | ||
85 | clk = p; | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* check for the case where a device was supplied, but the | ||
91 | * clock that was being searched for is not device specific */ | ||
92 | |||
93 | if (IS_ERR(clk)) { | ||
94 | list_for_each_entry(p, &clocks, list) { | ||
95 | if (p->id == -1 && strcmp(id, p->name) == 0 && | ||
96 | try_module_get(p->owner)) { | ||
97 | clk = p; | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | mutex_unlock(&clocks_mutex); | ||
104 | return clk; | ||
105 | } | ||
106 | |||
107 | void clk_put(struct clk *clk) | ||
108 | { | ||
109 | module_put(clk->owner); | ||
110 | } | ||
111 | |||
112 | int clk_enable(struct clk *clk) | ||
113 | { | ||
114 | if (IS_ERR(clk) || clk == NULL) | ||
115 | return -EINVAL; | ||
116 | |||
117 | clk_enable(clk->parent); | ||
118 | |||
119 | mutex_lock(&clocks_mutex); | ||
120 | |||
121 | if ((clk->usage++) == 0) | ||
122 | (clk->enable)(clk, 1); | ||
123 | |||
124 | mutex_unlock(&clocks_mutex); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | void clk_disable(struct clk *clk) | ||
129 | { | ||
130 | if (IS_ERR(clk) || clk == NULL) | ||
131 | return; | ||
132 | |||
133 | mutex_lock(&clocks_mutex); | ||
134 | |||
135 | if ((--clk->usage) == 0) | ||
136 | (clk->enable)(clk, 0); | ||
137 | |||
138 | mutex_unlock(&clocks_mutex); | ||
139 | clk_disable(clk->parent); | ||
140 | } | ||
141 | |||
142 | |||
143 | unsigned long clk_get_rate(struct clk *clk) | ||
144 | { | ||
145 | if (IS_ERR(clk)) | ||
146 | return 0; | ||
147 | |||
148 | if (clk->rate != 0) | ||
149 | return clk->rate; | ||
150 | |||
151 | if (clk->get_rate != NULL) | ||
152 | return (clk->get_rate)(clk); | ||
153 | |||
154 | if (clk->parent != NULL) | ||
155 | return clk_get_rate(clk->parent); | ||
156 | |||
157 | return clk->rate; | ||
158 | } | ||
159 | |||
160 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
161 | { | ||
162 | if (!IS_ERR(clk) && clk->round_rate) | ||
163 | return (clk->round_rate)(clk, rate); | ||
164 | |||
165 | return rate; | ||
166 | } | ||
167 | |||
168 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
169 | { | ||
170 | int ret; | ||
171 | |||
172 | if (IS_ERR(clk)) | ||
173 | return -EINVAL; | ||
174 | |||
175 | mutex_lock(&clocks_mutex); | ||
176 | ret = (clk->set_rate)(clk, rate); | ||
177 | mutex_unlock(&clocks_mutex); | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | struct clk *clk_get_parent(struct clk *clk) | ||
183 | { | ||
184 | return clk->parent; | ||
185 | } | ||
186 | |||
187 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
188 | { | ||
189 | int ret = 0; | ||
190 | |||
191 | if (IS_ERR(clk)) | ||
192 | return -EINVAL; | ||
193 | |||
194 | mutex_lock(&clocks_mutex); | ||
195 | |||
196 | if (clk->set_parent) | ||
197 | ret = (clk->set_parent)(clk, parent); | ||
198 | |||
199 | mutex_unlock(&clocks_mutex); | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | EXPORT_SYMBOL(clk_get); | ||
205 | EXPORT_SYMBOL(clk_put); | ||
206 | EXPORT_SYMBOL(clk_enable); | ||
207 | EXPORT_SYMBOL(clk_disable); | ||
208 | EXPORT_SYMBOL(clk_get_rate); | ||
209 | EXPORT_SYMBOL(clk_round_rate); | ||
210 | EXPORT_SYMBOL(clk_set_rate); | ||
211 | EXPORT_SYMBOL(clk_get_parent); | ||
212 | EXPORT_SYMBOL(clk_set_parent); | ||
213 | |||
214 | /* base clocks */ | ||
215 | |||
216 | struct clk clk_xtal = { | ||
217 | .name = "xtal", | ||
218 | .id = -1, | ||
219 | .rate = 0, | ||
220 | .parent = NULL, | ||
221 | .ctrlbit = 0, | ||
222 | }; | ||
223 | |||
224 | struct clk clk_mpll = { | ||
225 | .name = "mpll", | ||
226 | .id = -1, | ||
227 | }; | ||
228 | |||
229 | struct clk clk_upll = { | ||
230 | .name = "upll", | ||
231 | .id = -1, | ||
232 | .parent = NULL, | ||
233 | .ctrlbit = 0, | ||
234 | }; | ||
235 | |||
236 | struct clk clk_f = { | ||
237 | .name = "fclk", | ||
238 | .id = -1, | ||
239 | .rate = 0, | ||
240 | .parent = &clk_mpll, | ||
241 | .ctrlbit = 0, | ||
242 | }; | ||
243 | |||
244 | struct clk clk_h = { | ||
245 | .name = "hclk", | ||
246 | .id = -1, | ||
247 | .rate = 0, | ||
248 | .parent = NULL, | ||
249 | .ctrlbit = 0, | ||
250 | }; | ||
251 | |||
252 | struct clk clk_p = { | ||
253 | .name = "pclk", | ||
254 | .id = -1, | ||
255 | .rate = 0, | ||
256 | .parent = NULL, | ||
257 | .ctrlbit = 0, | ||
258 | }; | ||
259 | |||
260 | struct clk clk_usb_bus = { | ||
261 | .name = "usb-bus", | ||
262 | .id = -1, | ||
263 | .rate = 0, | ||
264 | .parent = &clk_upll, | ||
265 | }; | ||
266 | |||
267 | /* clocks that could be registered by external code */ | ||
268 | |||
269 | static int s3c24xx_dclk_enable(struct clk *clk, int enable) | ||
270 | { | ||
271 | unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
272 | |||
273 | if (enable) | ||
274 | dclkcon |= clk->ctrlbit; | ||
275 | else | ||
276 | dclkcon &= ~clk->ctrlbit; | ||
277 | |||
278 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) | ||
284 | { | ||
285 | unsigned long dclkcon; | ||
286 | unsigned int uclk; | ||
287 | |||
288 | if (parent == &clk_upll) | ||
289 | uclk = 1; | ||
290 | else if (parent == &clk_p) | ||
291 | uclk = 0; | ||
292 | else | ||
293 | return -EINVAL; | ||
294 | |||
295 | clk->parent = parent; | ||
296 | |||
297 | dclkcon = __raw_readl(S3C24XX_DCLKCON); | ||
298 | |||
299 | if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { | ||
300 | if (uclk) | ||
301 | dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK; | ||
302 | else | ||
303 | dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK; | ||
304 | } else { | ||
305 | if (uclk) | ||
306 | dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK; | ||
307 | else | ||
308 | dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; | ||
309 | } | ||
310 | |||
311 | __raw_writel(dclkcon, S3C24XX_DCLKCON); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | |||
317 | static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) | ||
318 | { | ||
319 | unsigned long mask; | ||
320 | unsigned long source; | ||
321 | |||
322 | /* calculate the MISCCR setting for the clock */ | ||
323 | |||
324 | if (parent == &clk_xtal) | ||
325 | source = S3C2410_MISCCR_CLK0_MPLL; | ||
326 | else if (parent == &clk_upll) | ||
327 | source = S3C2410_MISCCR_CLK0_UPLL; | ||
328 | else if (parent == &clk_f) | ||
329 | source = S3C2410_MISCCR_CLK0_FCLK; | ||
330 | else if (parent == &clk_h) | ||
331 | source = S3C2410_MISCCR_CLK0_HCLK; | ||
332 | else if (parent == &clk_p) | ||
333 | source = S3C2410_MISCCR_CLK0_PCLK; | ||
334 | else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) | ||
335 | source = S3C2410_MISCCR_CLK0_DCLK0; | ||
336 | else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) | ||
337 | source = S3C2410_MISCCR_CLK0_DCLK0; | ||
338 | else | ||
339 | return -EINVAL; | ||
340 | |||
341 | clk->parent = parent; | ||
342 | |||
343 | if (clk == &s3c24xx_dclk0) | ||
344 | mask = S3C2410_MISCCR_CLK0_MASK; | ||
345 | else { | ||
346 | source <<= 4; | ||
347 | mask = S3C2410_MISCCR_CLK1_MASK; | ||
348 | } | ||
349 | |||
350 | s3c2410_modify_misccr(mask, source); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /* external clock definitions */ | ||
355 | |||
356 | struct clk s3c24xx_dclk0 = { | ||
357 | .name = "dclk0", | ||
358 | .id = -1, | ||
359 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
360 | .enable = s3c24xx_dclk_enable, | ||
361 | .set_parent = s3c24xx_dclk_setparent, | ||
362 | }; | ||
363 | |||
364 | struct clk s3c24xx_dclk1 = { | ||
365 | .name = "dclk1", | ||
366 | .id = -1, | ||
367 | .ctrlbit = S3C2410_DCLKCON_DCLK0EN, | ||
368 | .enable = s3c24xx_dclk_enable, | ||
369 | .set_parent = s3c24xx_dclk_setparent, | ||
370 | }; | ||
371 | |||
372 | struct clk s3c24xx_clkout0 = { | ||
373 | .name = "clkout0", | ||
374 | .id = -1, | ||
375 | .set_parent = s3c24xx_clkout_setparent, | ||
376 | }; | ||
377 | |||
378 | struct clk s3c24xx_clkout1 = { | ||
379 | .name = "clkout1", | ||
380 | .id = -1, | ||
381 | .set_parent = s3c24xx_clkout_setparent, | ||
382 | }; | ||
383 | |||
384 | struct clk s3c24xx_uclk = { | ||
385 | .name = "uclk", | ||
386 | .id = -1, | ||
387 | }; | ||
388 | |||
389 | /* initialise the clock system */ | ||
390 | |||
391 | int s3c24xx_register_clock(struct clk *clk) | ||
392 | { | ||
393 | clk->owner = THIS_MODULE; | ||
394 | |||
395 | if (clk->enable == NULL) | ||
396 | clk->enable = clk_null_enable; | ||
397 | |||
398 | /* add to the list of available clocks */ | ||
399 | |||
400 | mutex_lock(&clocks_mutex); | ||
401 | list_add(&clk->list, &clocks); | ||
402 | mutex_unlock(&clocks_mutex); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* initalise all the clocks */ | ||
408 | |||
409 | int __init s3c24xx_setup_clocks(unsigned long xtal, | ||
410 | unsigned long fclk, | ||
411 | unsigned long hclk, | ||
412 | unsigned long pclk) | ||
413 | { | ||
414 | printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); | ||
415 | |||
416 | /* initialise the main system clocks */ | ||
417 | |||
418 | clk_xtal.rate = xtal; | ||
419 | clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); | ||
420 | |||
421 | clk_mpll.rate = fclk; | ||
422 | clk_h.rate = hclk; | ||
423 | clk_p.rate = pclk; | ||
424 | clk_f.rate = fclk; | ||
425 | |||
426 | /* assume uart clocks are correctly setup */ | ||
427 | |||
428 | /* register our clocks */ | ||
429 | |||
430 | if (s3c24xx_register_clock(&clk_xtal) < 0) | ||
431 | printk(KERN_ERR "failed to register master xtal\n"); | ||
432 | |||
433 | if (s3c24xx_register_clock(&clk_mpll) < 0) | ||
434 | printk(KERN_ERR "failed to register mpll clock\n"); | ||
435 | |||
436 | if (s3c24xx_register_clock(&clk_upll) < 0) | ||
437 | printk(KERN_ERR "failed to register upll clock\n"); | ||
438 | |||
439 | if (s3c24xx_register_clock(&clk_f) < 0) | ||
440 | printk(KERN_ERR "failed to register cpu fclk\n"); | ||
441 | |||
442 | if (s3c24xx_register_clock(&clk_h) < 0) | ||
443 | printk(KERN_ERR "failed to register cpu hclk\n"); | ||
444 | |||
445 | if (s3c24xx_register_clock(&clk_p) < 0) | ||
446 | printk(KERN_ERR "failed to register cpu pclk\n"); | ||
447 | |||
448 | return 0; | ||
449 | } | ||
diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c index a40eaa656177..908efa7d745f 100644 --- a/arch/arm/mach-s3c2410/common-smdk.c +++ b/arch/arm/plat-s3c24xx/common-smdk.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/common-smdk.c | 1 | /* linux/arch/arm/plat-s3c24xx/common-smdk.c |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -38,9 +38,9 @@ | |||
38 | 38 | ||
39 | #include <asm/arch/nand.h> | 39 | #include <asm/arch/nand.h> |
40 | 40 | ||
41 | #include "common-smdk.h" | 41 | #include <asm/plat-s3c24xx/common-smdk.h> |
42 | #include "devs.h" | 42 | #include <asm/plat-s3c24xx/devs.h> |
43 | #include "pm.h" | 43 | #include <asm/plat-s3c24xx/pm.h> |
44 | 44 | ||
45 | /* LED devices */ | 45 | /* LED devices */ |
46 | 46 | ||
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/plat-s3c24xx/cpu.c index ae1f5bb63f7a..2fbb74969379 100644 --- a/arch/arm/mach-s3c2410/cpu.c +++ b/arch/arm/plat-s3c24xx/cpu.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/cpu.c | 1 | /* linux/arch/arm/plat-s3c24xx/cpu.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * http://www.simtec.co.uk/products/SWLINUX/ | 4 | * http://www.simtec.co.uk/products/SWLINUX/ |
@@ -40,15 +40,15 @@ | |||
40 | #include <asm/arch/regs-gpio.h> | 40 | #include <asm/arch/regs-gpio.h> |
41 | #include <asm/arch/regs-serial.h> | 41 | #include <asm/arch/regs-serial.h> |
42 | 42 | ||
43 | #include "cpu.h" | 43 | #include <asm/plat-s3c24xx/cpu.h> |
44 | #include "devs.h" | 44 | #include <asm/plat-s3c24xx/devs.h> |
45 | #include "clock.h" | 45 | #include <asm/plat-s3c24xx/clock.h> |
46 | #include "s3c2400.h" | 46 | #include <asm/plat-s3c24xx/s3c2400.h> |
47 | #include "s3c2410.h" | 47 | #include <asm/plat-s3c24xx/s3c2410.h> |
48 | #include "s3c2412.h" | 48 | #include <asm/plat-s3c24xx/s3c2412.h> |
49 | #include "s3c244x.h" | 49 | #include "s3c244x.h" |
50 | #include "s3c2440.h" | 50 | #include <asm/plat-s3c24xx/s3c2440.h> |
51 | #include "s3c2442.h" | 51 | #include <asm/plat-s3c24xx/s3c2442.h> |
52 | 52 | ||
53 | struct cpu_table { | 53 | struct cpu_table { |
54 | unsigned long idcode; | 54 | unsigned long idcode; |
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/plat-s3c24xx/devs.c index faccde2092d2..6d46c4e2a4f7 100644 --- a/arch/arm/mach-s3c2410/devs.c +++ b/arch/arm/plat-s3c24xx/devs.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/devs.c | 1 | /* linux/arch/arm/plat-s3c24xx/devs.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -30,8 +30,8 @@ | |||
30 | 30 | ||
31 | #include <asm/arch/regs-serial.h> | 31 | #include <asm/arch/regs-serial.h> |
32 | 32 | ||
33 | #include "devs.h" | 33 | #include <asm/plat-s3c24xx/devs.h> |
34 | #include "cpu.h" | 34 | #include <asm/plat-s3c24xx/cpu.h> |
35 | 35 | ||
36 | /* Serial port registrations */ | 36 | /* Serial port registrations */ |
37 | 37 | ||
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c new file mode 100644 index 000000000000..c784e1f816bb --- /dev/null +++ b/arch/arm/plat-s3c24xx/dma.c | |||
@@ -0,0 +1,1441 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/dma.c | ||
2 | * | ||
3 | * Copyright (c) 2003-2005,2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 DMA core | ||
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 | |||
16 | #ifdef CONFIG_S3C2410_DMA_DEBUG | ||
17 | #define DEBUG | ||
18 | #endif | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <asm/system.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/hardware.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/dma.h> | ||
35 | |||
36 | #include <asm/mach/dma.h> | ||
37 | #include <asm/arch/map.h> | ||
38 | |||
39 | #include <asm/plat-s3c24xx/dma.h> | ||
40 | |||
41 | /* io map for dma */ | ||
42 | static void __iomem *dma_base; | ||
43 | static struct kmem_cache *dma_kmem; | ||
44 | |||
45 | struct s3c24xx_dma_selection dma_sel; | ||
46 | |||
47 | /* dma channel state information */ | ||
48 | struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; | ||
49 | |||
50 | /* debugging functions */ | ||
51 | |||
52 | #define BUF_MAGIC (0xcafebabe) | ||
53 | |||
54 | #define dmawarn(fmt...) printk(KERN_DEBUG fmt) | ||
55 | |||
56 | #define dma_regaddr(chan, reg) ((chan)->regs + (reg)) | ||
57 | |||
58 | #if 1 | ||
59 | #define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) | ||
60 | #else | ||
61 | static inline void | ||
62 | dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) | ||
63 | { | ||
64 | pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); | ||
65 | writel(val, dma_regaddr(chan, reg)); | ||
66 | } | ||
67 | #endif | ||
68 | |||
69 | #define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) | ||
70 | |||
71 | /* captured register state for debug */ | ||
72 | |||
73 | struct s3c2410_dma_regstate { | ||
74 | unsigned long dcsrc; | ||
75 | unsigned long disrc; | ||
76 | unsigned long dstat; | ||
77 | unsigned long dcon; | ||
78 | unsigned long dmsktrig; | ||
79 | }; | ||
80 | |||
81 | #ifdef CONFIG_S3C2410_DMA_DEBUG | ||
82 | |||
83 | /* dmadbg_showregs | ||
84 | * | ||
85 | * simple debug routine to print the current state of the dma registers | ||
86 | */ | ||
87 | |||
88 | static void | ||
89 | dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) | ||
90 | { | ||
91 | regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC); | ||
92 | regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC); | ||
93 | regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT); | ||
94 | regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
95 | regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, | ||
100 | struct s3c2410_dma_regstate *regs) | ||
101 | { | ||
102 | printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", | ||
103 | chan->number, fname, line, | ||
104 | regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, | ||
105 | regs->dcon); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) | ||
110 | { | ||
111 | struct s3c2410_dma_regstate state; | ||
112 | |||
113 | dmadbg_capture(chan, &state); | ||
114 | |||
115 | printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", | ||
116 | chan->number, fname, line, chan->load_state, | ||
117 | chan->curr, chan->next, chan->end); | ||
118 | |||
119 | dmadbg_dumpregs(fname, line, chan, &state); | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) | ||
124 | { | ||
125 | struct s3c2410_dma_regstate state; | ||
126 | |||
127 | dmadbg_capture(chan, &state); | ||
128 | dmadbg_dumpregs(fname, line, chan, &state); | ||
129 | } | ||
130 | |||
131 | #define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan)) | ||
132 | #define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan)) | ||
133 | #else | ||
134 | #define dbg_showregs(chan) do { } while(0) | ||
135 | #define dbg_showchan(chan) do { } while(0) | ||
136 | #endif /* CONFIG_S3C2410_DMA_DEBUG */ | ||
137 | |||
138 | static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX]; | ||
139 | |||
140 | /* lookup_dma_channel | ||
141 | * | ||
142 | * change the dma channel number given into a real dma channel id | ||
143 | */ | ||
144 | |||
145 | static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel) | ||
146 | { | ||
147 | if (channel & DMACH_LOW_LEVEL) | ||
148 | return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL]; | ||
149 | else | ||
150 | return dma_chan_map[channel]; | ||
151 | } | ||
152 | |||
153 | /* s3c2410_dma_stats_timeout | ||
154 | * | ||
155 | * Update DMA stats from timeout info | ||
156 | */ | ||
157 | |||
158 | static void | ||
159 | s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) | ||
160 | { | ||
161 | if (stats == NULL) | ||
162 | return; | ||
163 | |||
164 | if (val > stats->timeout_longest) | ||
165 | stats->timeout_longest = val; | ||
166 | if (val < stats->timeout_shortest) | ||
167 | stats->timeout_shortest = val; | ||
168 | |||
169 | stats->timeout_avg += val; | ||
170 | } | ||
171 | |||
172 | /* s3c2410_dma_waitforload | ||
173 | * | ||
174 | * wait for the DMA engine to load a buffer, and update the state accordingly | ||
175 | */ | ||
176 | |||
177 | static int | ||
178 | s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) | ||
179 | { | ||
180 | int timeout = chan->load_timeout; | ||
181 | int took; | ||
182 | |||
183 | if (chan->load_state != S3C2410_DMALOAD_1LOADED) { | ||
184 | printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | if (chan->stats != NULL) | ||
189 | chan->stats->loads++; | ||
190 | |||
191 | while (--timeout > 0) { | ||
192 | if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { | ||
193 | took = chan->load_timeout - timeout; | ||
194 | |||
195 | s3c2410_dma_stats_timeout(chan->stats, took); | ||
196 | |||
197 | switch (chan->load_state) { | ||
198 | case S3C2410_DMALOAD_1LOADED: | ||
199 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
200 | break; | ||
201 | |||
202 | default: | ||
203 | printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); | ||
204 | } | ||
205 | |||
206 | return 1; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if (chan->stats != NULL) { | ||
211 | chan->stats->timeout_failed++; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | |||
218 | |||
219 | /* s3c2410_dma_loadbuffer | ||
220 | * | ||
221 | * load a buffer, and update the channel state | ||
222 | */ | ||
223 | |||
224 | static inline int | ||
225 | s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, | ||
226 | struct s3c2410_dma_buf *buf) | ||
227 | { | ||
228 | unsigned long reload; | ||
229 | |||
230 | pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", | ||
231 | buf, (unsigned long)buf->data, buf->size); | ||
232 | |||
233 | if (buf == NULL) { | ||
234 | dmawarn("buffer is NULL\n"); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | /* check the state of the channel before we do anything */ | ||
239 | |||
240 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
241 | dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); | ||
242 | } | ||
243 | |||
244 | if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { | ||
245 | dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); | ||
246 | } | ||
247 | |||
248 | /* it would seem sensible if we are the last buffer to not bother | ||
249 | * with the auto-reload bit, so that the DMA engine will not try | ||
250 | * and load another transfer after this one has finished... | ||
251 | */ | ||
252 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
253 | pr_debug("load_state is none, checking for noreload (next=%p)\n", | ||
254 | buf->next); | ||
255 | reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; | ||
256 | } else { | ||
257 | //pr_debug("load_state is %d => autoreload\n", chan->load_state); | ||
258 | reload = S3C2410_DCON_AUTORELOAD; | ||
259 | } | ||
260 | |||
261 | if ((buf->data & 0xf0000000) != 0x30000000) { | ||
262 | dmawarn("dmaload: buffer is %p\n", (void *)buf->data); | ||
263 | } | ||
264 | |||
265 | writel(buf->data, chan->addr_reg); | ||
266 | |||
267 | dma_wrreg(chan, S3C2410_DMA_DCON, | ||
268 | chan->dcon | reload | (buf->size/chan->xfer_unit)); | ||
269 | |||
270 | chan->next = buf->next; | ||
271 | |||
272 | /* update the state of the channel */ | ||
273 | |||
274 | switch (chan->load_state) { | ||
275 | case S3C2410_DMALOAD_NONE: | ||
276 | chan->load_state = S3C2410_DMALOAD_1LOADED; | ||
277 | break; | ||
278 | |||
279 | case S3C2410_DMALOAD_1RUNNING: | ||
280 | chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; | ||
281 | break; | ||
282 | |||
283 | default: | ||
284 | dmawarn("dmaload: unknown state %d in loadbuffer\n", | ||
285 | chan->load_state); | ||
286 | break; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* s3c2410_dma_call_op | ||
293 | * | ||
294 | * small routine to call the op routine with the given op if it has been | ||
295 | * registered | ||
296 | */ | ||
297 | |||
298 | static void | ||
299 | s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) | ||
300 | { | ||
301 | if (chan->op_fn != NULL) { | ||
302 | (chan->op_fn)(chan, op); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* s3c2410_dma_buffdone | ||
307 | * | ||
308 | * small wrapper to check if callback routine needs to be called, and | ||
309 | * if so, call it | ||
310 | */ | ||
311 | |||
312 | static inline void | ||
313 | s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, | ||
314 | enum s3c2410_dma_buffresult result) | ||
315 | { | ||
316 | #if 0 | ||
317 | pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", | ||
318 | chan->callback_fn, buf, buf->id, buf->size, result); | ||
319 | #endif | ||
320 | |||
321 | if (chan->callback_fn != NULL) { | ||
322 | (chan->callback_fn)(chan, buf->id, buf->size, result); | ||
323 | } | ||
324 | } | ||
325 | |||
326 | /* s3c2410_dma_start | ||
327 | * | ||
328 | * start a dma channel going | ||
329 | */ | ||
330 | |||
331 | static int s3c2410_dma_start(struct s3c2410_dma_chan *chan) | ||
332 | { | ||
333 | unsigned long tmp; | ||
334 | unsigned long flags; | ||
335 | |||
336 | pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); | ||
337 | |||
338 | local_irq_save(flags); | ||
339 | |||
340 | if (chan->state == S3C2410_DMA_RUNNING) { | ||
341 | pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); | ||
342 | local_irq_restore(flags); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | chan->state = S3C2410_DMA_RUNNING; | ||
347 | |||
348 | /* check wether there is anything to load, and if not, see | ||
349 | * if we can find anything to load | ||
350 | */ | ||
351 | |||
352 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
353 | if (chan->next == NULL) { | ||
354 | printk(KERN_ERR "dma%d: channel has nothing loaded\n", | ||
355 | chan->number); | ||
356 | chan->state = S3C2410_DMA_IDLE; | ||
357 | local_irq_restore(flags); | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
362 | } | ||
363 | |||
364 | dbg_showchan(chan); | ||
365 | |||
366 | /* enable the channel */ | ||
367 | |||
368 | if (!chan->irq_enabled) { | ||
369 | enable_irq(chan->irq); | ||
370 | chan->irq_enabled = 1; | ||
371 | } | ||
372 | |||
373 | /* start the channel going */ | ||
374 | |||
375 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
376 | tmp &= ~S3C2410_DMASKTRIG_STOP; | ||
377 | tmp |= S3C2410_DMASKTRIG_ON; | ||
378 | dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); | ||
379 | |||
380 | pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); | ||
381 | |||
382 | #if 0 | ||
383 | /* the dma buffer loads should take care of clearing the AUTO | ||
384 | * reloading feature */ | ||
385 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
386 | tmp &= ~S3C2410_DCON_NORELOAD; | ||
387 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
388 | #endif | ||
389 | |||
390 | s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); | ||
391 | |||
392 | dbg_showchan(chan); | ||
393 | |||
394 | /* if we've only loaded one buffer onto the channel, then chec | ||
395 | * to see if we have another, and if so, try and load it so when | ||
396 | * the first buffer is finished, the new one will be loaded onto | ||
397 | * the channel */ | ||
398 | |||
399 | if (chan->next != NULL) { | ||
400 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
401 | |||
402 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
403 | pr_debug("%s: buff not yet loaded, no more todo\n", | ||
404 | __FUNCTION__); | ||
405 | } else { | ||
406 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
407 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
408 | } | ||
409 | |||
410 | } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { | ||
411 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | |||
416 | local_irq_restore(flags); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /* s3c2410_dma_canload | ||
422 | * | ||
423 | * work out if we can queue another buffer into the DMA engine | ||
424 | */ | ||
425 | |||
426 | static int | ||
427 | s3c2410_dma_canload(struct s3c2410_dma_chan *chan) | ||
428 | { | ||
429 | if (chan->load_state == S3C2410_DMALOAD_NONE || | ||
430 | chan->load_state == S3C2410_DMALOAD_1RUNNING) | ||
431 | return 1; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* s3c2410_dma_enqueue | ||
437 | * | ||
438 | * queue an given buffer for dma transfer. | ||
439 | * | ||
440 | * id the device driver's id information for this buffer | ||
441 | * data the physical address of the buffer data | ||
442 | * size the size of the buffer in bytes | ||
443 | * | ||
444 | * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART | ||
445 | * is checked, and if set, the channel is started. If this flag isn't set, | ||
446 | * then an error will be returned. | ||
447 | * | ||
448 | * It is possible to queue more than one DMA buffer onto a channel at | ||
449 | * once, and the code will deal with the re-loading of the next buffer | ||
450 | * when necessary. | ||
451 | */ | ||
452 | |||
453 | int s3c2410_dma_enqueue(unsigned int channel, void *id, | ||
454 | dma_addr_t data, int size) | ||
455 | { | ||
456 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
457 | struct s3c2410_dma_buf *buf; | ||
458 | unsigned long flags; | ||
459 | |||
460 | if (chan == NULL) | ||
461 | return -EINVAL; | ||
462 | |||
463 | pr_debug("%s: id=%p, data=%08x, size=%d\n", | ||
464 | __FUNCTION__, id, (unsigned int)data, size); | ||
465 | |||
466 | buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); | ||
467 | if (buf == NULL) { | ||
468 | pr_debug("%s: out of memory (%ld alloc)\n", | ||
469 | __FUNCTION__, (long)sizeof(*buf)); | ||
470 | return -ENOMEM; | ||
471 | } | ||
472 | |||
473 | //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf); | ||
474 | //dbg_showchan(chan); | ||
475 | |||
476 | buf->next = NULL; | ||
477 | buf->data = buf->ptr = data; | ||
478 | buf->size = size; | ||
479 | buf->id = id; | ||
480 | buf->magic = BUF_MAGIC; | ||
481 | |||
482 | local_irq_save(flags); | ||
483 | |||
484 | if (chan->curr == NULL) { | ||
485 | /* we've got nothing loaded... */ | ||
486 | pr_debug("%s: buffer %p queued onto empty channel\n", | ||
487 | __FUNCTION__, buf); | ||
488 | |||
489 | chan->curr = buf; | ||
490 | chan->end = buf; | ||
491 | chan->next = NULL; | ||
492 | } else { | ||
493 | pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", | ||
494 | chan->number, __FUNCTION__, buf); | ||
495 | |||
496 | if (chan->end == NULL) | ||
497 | pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", | ||
498 | chan->number, __FUNCTION__, chan); | ||
499 | |||
500 | chan->end->next = buf; | ||
501 | chan->end = buf; | ||
502 | } | ||
503 | |||
504 | /* if necessary, update the next buffer field */ | ||
505 | if (chan->next == NULL) | ||
506 | chan->next = buf; | ||
507 | |||
508 | /* check to see if we can load a buffer */ | ||
509 | if (chan->state == S3C2410_DMA_RUNNING) { | ||
510 | if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { | ||
511 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
512 | printk(KERN_ERR "dma%d: loadbuffer:" | ||
513 | "timeout loading buffer\n", | ||
514 | chan->number); | ||
515 | dbg_showchan(chan); | ||
516 | local_irq_restore(flags); | ||
517 | return -EINVAL; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | while (s3c2410_dma_canload(chan) && chan->next != NULL) { | ||
522 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
523 | } | ||
524 | } else if (chan->state == S3C2410_DMA_IDLE) { | ||
525 | if (chan->flags & S3C2410_DMAF_AUTOSTART) { | ||
526 | s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | local_irq_restore(flags); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | EXPORT_SYMBOL(s3c2410_dma_enqueue); | ||
535 | |||
536 | static inline void | ||
537 | s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) | ||
538 | { | ||
539 | int magicok = (buf->magic == BUF_MAGIC); | ||
540 | |||
541 | buf->magic = -1; | ||
542 | |||
543 | if (magicok) { | ||
544 | kmem_cache_free(dma_kmem, buf); | ||
545 | } else { | ||
546 | printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* s3c2410_dma_lastxfer | ||
551 | * | ||
552 | * called when the system is out of buffers, to ensure that the channel | ||
553 | * is prepared for shutdown. | ||
554 | */ | ||
555 | |||
556 | static inline void | ||
557 | s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) | ||
558 | { | ||
559 | #if 0 | ||
560 | pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", | ||
561 | chan->number, chan->load_state); | ||
562 | #endif | ||
563 | |||
564 | switch (chan->load_state) { | ||
565 | case S3C2410_DMALOAD_NONE: | ||
566 | break; | ||
567 | |||
568 | case S3C2410_DMALOAD_1LOADED: | ||
569 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
570 | /* flag error? */ | ||
571 | printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", | ||
572 | chan->number, __FUNCTION__); | ||
573 | return; | ||
574 | } | ||
575 | break; | ||
576 | |||
577 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
578 | /* I belive in this case we do not have anything to do | ||
579 | * until the next buffer comes along, and we turn off the | ||
580 | * reload */ | ||
581 | return; | ||
582 | |||
583 | default: | ||
584 | pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", | ||
585 | chan->number, chan->load_state); | ||
586 | return; | ||
587 | |||
588 | } | ||
589 | |||
590 | /* hopefully this'll shut the damned thing up after the transfer... */ | ||
591 | dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); | ||
592 | } | ||
593 | |||
594 | |||
595 | #define dmadbg2(x...) | ||
596 | |||
597 | static irqreturn_t | ||
598 | s3c2410_dma_irq(int irq, void *devpw) | ||
599 | { | ||
600 | struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; | ||
601 | struct s3c2410_dma_buf *buf; | ||
602 | |||
603 | buf = chan->curr; | ||
604 | |||
605 | dbg_showchan(chan); | ||
606 | |||
607 | /* modify the channel state */ | ||
608 | |||
609 | switch (chan->load_state) { | ||
610 | case S3C2410_DMALOAD_1RUNNING: | ||
611 | /* TODO - if we are running only one buffer, we probably | ||
612 | * want to reload here, and then worry about the buffer | ||
613 | * callback */ | ||
614 | |||
615 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
616 | break; | ||
617 | |||
618 | case S3C2410_DMALOAD_1LOADED: | ||
619 | /* iirc, we should go back to NONE loaded here, we | ||
620 | * had a buffer, and it was never verified as being | ||
621 | * loaded. | ||
622 | */ | ||
623 | |||
624 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
625 | break; | ||
626 | |||
627 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
628 | /* we'll worry about checking to see if another buffer is | ||
629 | * ready after we've called back the owner. This should | ||
630 | * ensure we do not wait around too long for the DMA | ||
631 | * engine to start the next transfer | ||
632 | */ | ||
633 | |||
634 | chan->load_state = S3C2410_DMALOAD_1LOADED; | ||
635 | break; | ||
636 | |||
637 | case S3C2410_DMALOAD_NONE: | ||
638 | printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", | ||
639 | chan->number); | ||
640 | break; | ||
641 | |||
642 | default: | ||
643 | printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", | ||
644 | chan->number, chan->load_state); | ||
645 | break; | ||
646 | } | ||
647 | |||
648 | if (buf != NULL) { | ||
649 | /* update the chain to make sure that if we load any more | ||
650 | * buffers when we call the callback function, things should | ||
651 | * work properly */ | ||
652 | |||
653 | chan->curr = buf->next; | ||
654 | buf->next = NULL; | ||
655 | |||
656 | if (buf->magic != BUF_MAGIC) { | ||
657 | printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", | ||
658 | chan->number, __FUNCTION__, buf); | ||
659 | return IRQ_HANDLED; | ||
660 | } | ||
661 | |||
662 | s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); | ||
663 | |||
664 | /* free resouces */ | ||
665 | s3c2410_dma_freebuf(buf); | ||
666 | } else { | ||
667 | } | ||
668 | |||
669 | /* only reload if the channel is still running... our buffer done | ||
670 | * routine may have altered the state by requesting the dma channel | ||
671 | * to stop or shutdown... */ | ||
672 | |||
673 | /* todo: check that when the channel is shut-down from inside this | ||
674 | * function, we cope with unsetting reload, etc */ | ||
675 | |||
676 | if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { | ||
677 | unsigned long flags; | ||
678 | |||
679 | switch (chan->load_state) { | ||
680 | case S3C2410_DMALOAD_1RUNNING: | ||
681 | /* don't need to do anything for this state */ | ||
682 | break; | ||
683 | |||
684 | case S3C2410_DMALOAD_NONE: | ||
685 | /* can load buffer immediately */ | ||
686 | break; | ||
687 | |||
688 | case S3C2410_DMALOAD_1LOADED: | ||
689 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
690 | /* flag error? */ | ||
691 | printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", | ||
692 | chan->number, __FUNCTION__); | ||
693 | return IRQ_HANDLED; | ||
694 | } | ||
695 | |||
696 | break; | ||
697 | |||
698 | case S3C2410_DMALOAD_1LOADED_1RUNNING: | ||
699 | goto no_load; | ||
700 | |||
701 | default: | ||
702 | printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", | ||
703 | chan->number, chan->load_state); | ||
704 | return IRQ_HANDLED; | ||
705 | } | ||
706 | |||
707 | local_irq_save(flags); | ||
708 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
709 | local_irq_restore(flags); | ||
710 | } else { | ||
711 | s3c2410_dma_lastxfer(chan); | ||
712 | |||
713 | /* see if we can stop this channel.. */ | ||
714 | if (chan->load_state == S3C2410_DMALOAD_NONE) { | ||
715 | pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", | ||
716 | chan->number, jiffies); | ||
717 | s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, | ||
718 | S3C2410_DMAOP_STOP); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | no_load: | ||
723 | return IRQ_HANDLED; | ||
724 | } | ||
725 | |||
726 | static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); | ||
727 | |||
728 | /* s3c2410_request_dma | ||
729 | * | ||
730 | * get control of an dma channel | ||
731 | */ | ||
732 | |||
733 | int s3c2410_dma_request(unsigned int channel, | ||
734 | struct s3c2410_dma_client *client, | ||
735 | void *dev) | ||
736 | { | ||
737 | struct s3c2410_dma_chan *chan; | ||
738 | unsigned long flags; | ||
739 | int err; | ||
740 | |||
741 | pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", | ||
742 | channel, client->name, dev); | ||
743 | |||
744 | local_irq_save(flags); | ||
745 | |||
746 | chan = s3c2410_dma_map_channel(channel); | ||
747 | if (chan == NULL) { | ||
748 | local_irq_restore(flags); | ||
749 | return -EBUSY; | ||
750 | } | ||
751 | |||
752 | dbg_showchan(chan); | ||
753 | |||
754 | chan->client = client; | ||
755 | chan->in_use = 1; | ||
756 | |||
757 | if (!chan->irq_claimed) { | ||
758 | pr_debug("dma%d: %s : requesting irq %d\n", | ||
759 | channel, __FUNCTION__, chan->irq); | ||
760 | |||
761 | chan->irq_claimed = 1; | ||
762 | local_irq_restore(flags); | ||
763 | |||
764 | err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED, | ||
765 | client->name, (void *)chan); | ||
766 | |||
767 | local_irq_save(flags); | ||
768 | |||
769 | if (err) { | ||
770 | chan->in_use = 0; | ||
771 | chan->irq_claimed = 0; | ||
772 | local_irq_restore(flags); | ||
773 | |||
774 | printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", | ||
775 | client->name, chan->irq, chan->number); | ||
776 | return err; | ||
777 | } | ||
778 | |||
779 | chan->irq_enabled = 1; | ||
780 | } | ||
781 | |||
782 | local_irq_restore(flags); | ||
783 | |||
784 | /* need to setup */ | ||
785 | |||
786 | pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | EXPORT_SYMBOL(s3c2410_dma_request); | ||
792 | |||
793 | /* s3c2410_dma_free | ||
794 | * | ||
795 | * release the given channel back to the system, will stop and flush | ||
796 | * any outstanding transfers, and ensure the channel is ready for the | ||
797 | * next claimant. | ||
798 | * | ||
799 | * Note, although a warning is currently printed if the freeing client | ||
800 | * info is not the same as the registrant's client info, the free is still | ||
801 | * allowed to go through. | ||
802 | */ | ||
803 | |||
804 | int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) | ||
805 | { | ||
806 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
807 | unsigned long flags; | ||
808 | |||
809 | if (chan == NULL) | ||
810 | return -EINVAL; | ||
811 | |||
812 | local_irq_save(flags); | ||
813 | |||
814 | if (chan->client != client) { | ||
815 | printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", | ||
816 | channel, chan->client, client); | ||
817 | } | ||
818 | |||
819 | /* sort out stopping and freeing the channel */ | ||
820 | |||
821 | if (chan->state != S3C2410_DMA_IDLE) { | ||
822 | pr_debug("%s: need to stop dma channel %p\n", | ||
823 | __FUNCTION__, chan); | ||
824 | |||
825 | /* possibly flush the channel */ | ||
826 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); | ||
827 | } | ||
828 | |||
829 | chan->client = NULL; | ||
830 | chan->in_use = 0; | ||
831 | |||
832 | if (chan->irq_claimed) | ||
833 | free_irq(chan->irq, (void *)chan); | ||
834 | |||
835 | chan->irq_claimed = 0; | ||
836 | |||
837 | if (!(channel & DMACH_LOW_LEVEL)) | ||
838 | dma_chan_map[channel] = NULL; | ||
839 | |||
840 | local_irq_restore(flags); | ||
841 | |||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | EXPORT_SYMBOL(s3c2410_dma_free); | ||
846 | |||
847 | static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) | ||
848 | { | ||
849 | unsigned long flags; | ||
850 | unsigned long tmp; | ||
851 | |||
852 | pr_debug("%s:\n", __FUNCTION__); | ||
853 | |||
854 | dbg_showchan(chan); | ||
855 | |||
856 | local_irq_save(flags); | ||
857 | |||
858 | s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP); | ||
859 | |||
860 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
861 | tmp |= S3C2410_DMASKTRIG_STOP; | ||
862 | //tmp &= ~S3C2410_DMASKTRIG_ON; | ||
863 | dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); | ||
864 | |||
865 | #if 0 | ||
866 | /* should also clear interrupts, according to WinCE BSP */ | ||
867 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
868 | tmp |= S3C2410_DCON_NORELOAD; | ||
869 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
870 | #endif | ||
871 | |||
872 | /* should stop do this, or should we wait for flush? */ | ||
873 | chan->state = S3C2410_DMA_IDLE; | ||
874 | chan->load_state = S3C2410_DMALOAD_NONE; | ||
875 | |||
876 | local_irq_restore(flags); | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) | ||
882 | { | ||
883 | unsigned long tmp; | ||
884 | unsigned int timeout = 0x10000; | ||
885 | |||
886 | while (timeout-- > 0) { | ||
887 | tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); | ||
888 | |||
889 | if (!(tmp & S3C2410_DMASKTRIG_ON)) | ||
890 | return; | ||
891 | } | ||
892 | |||
893 | pr_debug("dma%d: failed to stop?\n", chan->number); | ||
894 | } | ||
895 | |||
896 | |||
897 | /* s3c2410_dma_flush | ||
898 | * | ||
899 | * stop the channel, and remove all current and pending transfers | ||
900 | */ | ||
901 | |||
902 | static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) | ||
903 | { | ||
904 | struct s3c2410_dma_buf *buf, *next; | ||
905 | unsigned long flags; | ||
906 | |||
907 | pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number); | ||
908 | |||
909 | dbg_showchan(chan); | ||
910 | |||
911 | local_irq_save(flags); | ||
912 | |||
913 | if (chan->state != S3C2410_DMA_IDLE) { | ||
914 | pr_debug("%s: stopping channel...\n", __FUNCTION__ ); | ||
915 | s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); | ||
916 | } | ||
917 | |||
918 | buf = chan->curr; | ||
919 | if (buf == NULL) | ||
920 | buf = chan->next; | ||
921 | |||
922 | chan->curr = chan->next = chan->end = NULL; | ||
923 | |||
924 | if (buf != NULL) { | ||
925 | for ( ; buf != NULL; buf = next) { | ||
926 | next = buf->next; | ||
927 | |||
928 | pr_debug("%s: free buffer %p, next %p\n", | ||
929 | __FUNCTION__, buf, buf->next); | ||
930 | |||
931 | s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); | ||
932 | s3c2410_dma_freebuf(buf); | ||
933 | } | ||
934 | } | ||
935 | |||
936 | dbg_showregs(chan); | ||
937 | |||
938 | s3c2410_dma_waitforstop(chan); | ||
939 | |||
940 | #if 0 | ||
941 | /* should also clear interrupts, according to WinCE BSP */ | ||
942 | { | ||
943 | unsigned long tmp; | ||
944 | |||
945 | tmp = dma_rdreg(chan, S3C2410_DMA_DCON); | ||
946 | tmp |= S3C2410_DCON_NORELOAD; | ||
947 | dma_wrreg(chan, S3C2410_DMA_DCON, tmp); | ||
948 | } | ||
949 | #endif | ||
950 | |||
951 | dbg_showregs(chan); | ||
952 | |||
953 | local_irq_restore(flags); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | int | ||
959 | s3c2410_dma_started(struct s3c2410_dma_chan *chan) | ||
960 | { | ||
961 | unsigned long flags; | ||
962 | |||
963 | local_irq_save(flags); | ||
964 | |||
965 | dbg_showchan(chan); | ||
966 | |||
967 | /* if we've only loaded one buffer onto the channel, then chec | ||
968 | * to see if we have another, and if so, try and load it so when | ||
969 | * the first buffer is finished, the new one will be loaded onto | ||
970 | * the channel */ | ||
971 | |||
972 | if (chan->next != NULL) { | ||
973 | if (chan->load_state == S3C2410_DMALOAD_1LOADED) { | ||
974 | |||
975 | if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { | ||
976 | pr_debug("%s: buff not yet loaded, no more todo\n", | ||
977 | __FUNCTION__); | ||
978 | } else { | ||
979 | chan->load_state = S3C2410_DMALOAD_1RUNNING; | ||
980 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
981 | } | ||
982 | |||
983 | } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { | ||
984 | s3c2410_dma_loadbuffer(chan, chan->next); | ||
985 | } | ||
986 | } | ||
987 | |||
988 | |||
989 | local_irq_restore(flags); | ||
990 | |||
991 | return 0; | ||
992 | |||
993 | } | ||
994 | |||
995 | int | ||
996 | s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op) | ||
997 | { | ||
998 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
999 | |||
1000 | if (chan == NULL) | ||
1001 | return -EINVAL; | ||
1002 | |||
1003 | switch (op) { | ||
1004 | case S3C2410_DMAOP_START: | ||
1005 | return s3c2410_dma_start(chan); | ||
1006 | |||
1007 | case S3C2410_DMAOP_STOP: | ||
1008 | return s3c2410_dma_dostop(chan); | ||
1009 | |||
1010 | case S3C2410_DMAOP_PAUSE: | ||
1011 | case S3C2410_DMAOP_RESUME: | ||
1012 | return -ENOENT; | ||
1013 | |||
1014 | case S3C2410_DMAOP_FLUSH: | ||
1015 | return s3c2410_dma_flush(chan); | ||
1016 | |||
1017 | case S3C2410_DMAOP_STARTED: | ||
1018 | return s3c2410_dma_started(chan); | ||
1019 | |||
1020 | case S3C2410_DMAOP_TIMEOUT: | ||
1021 | return 0; | ||
1022 | |||
1023 | } | ||
1024 | |||
1025 | return -ENOENT; /* unknown, don't bother */ | ||
1026 | } | ||
1027 | |||
1028 | EXPORT_SYMBOL(s3c2410_dma_ctrl); | ||
1029 | |||
1030 | /* DMA configuration for each channel | ||
1031 | * | ||
1032 | * DISRCC -> source of the DMA (AHB,APB) | ||
1033 | * DISRC -> source address of the DMA | ||
1034 | * DIDSTC -> destination of the DMA (AHB,APD) | ||
1035 | * DIDST -> destination address of the DMA | ||
1036 | */ | ||
1037 | |||
1038 | /* s3c2410_dma_config | ||
1039 | * | ||
1040 | * xfersize: size of unit in bytes (1,2,4) | ||
1041 | * dcon: base value of the DCONx register | ||
1042 | */ | ||
1043 | |||
1044 | int s3c2410_dma_config(dmach_t channel, | ||
1045 | int xferunit, | ||
1046 | int dcon) | ||
1047 | { | ||
1048 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1049 | |||
1050 | pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", | ||
1051 | __FUNCTION__, channel, xferunit, dcon); | ||
1052 | |||
1053 | if (chan == NULL) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon); | ||
1057 | |||
1058 | dcon |= chan->dcon & dma_sel.dcon_mask; | ||
1059 | |||
1060 | pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon); | ||
1061 | |||
1062 | switch (xferunit) { | ||
1063 | case 1: | ||
1064 | dcon |= S3C2410_DCON_BYTE; | ||
1065 | break; | ||
1066 | |||
1067 | case 2: | ||
1068 | dcon |= S3C2410_DCON_HALFWORD; | ||
1069 | break; | ||
1070 | |||
1071 | case 4: | ||
1072 | dcon |= S3C2410_DCON_WORD; | ||
1073 | break; | ||
1074 | |||
1075 | default: | ||
1076 | pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit); | ||
1077 | return -EINVAL; | ||
1078 | } | ||
1079 | |||
1080 | dcon |= S3C2410_DCON_HWTRIG; | ||
1081 | dcon |= S3C2410_DCON_INTREQ; | ||
1082 | |||
1083 | pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon); | ||
1084 | |||
1085 | chan->dcon = dcon; | ||
1086 | chan->xfer_unit = xferunit; | ||
1087 | |||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | EXPORT_SYMBOL(s3c2410_dma_config); | ||
1092 | |||
1093 | int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) | ||
1094 | { | ||
1095 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1096 | |||
1097 | if (chan == NULL) | ||
1098 | return -EINVAL; | ||
1099 | |||
1100 | pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); | ||
1101 | |||
1102 | chan->flags = flags; | ||
1103 | |||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | EXPORT_SYMBOL(s3c2410_dma_setflags); | ||
1108 | |||
1109 | |||
1110 | /* do we need to protect the settings of the fields from | ||
1111 | * irq? | ||
1112 | */ | ||
1113 | |||
1114 | int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) | ||
1115 | { | ||
1116 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1117 | |||
1118 | if (chan == NULL) | ||
1119 | return -EINVAL; | ||
1120 | |||
1121 | pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); | ||
1122 | |||
1123 | chan->op_fn = rtn; | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | EXPORT_SYMBOL(s3c2410_dma_set_opfn); | ||
1129 | |||
1130 | int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) | ||
1131 | { | ||
1132 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1133 | |||
1134 | if (chan == NULL) | ||
1135 | return -EINVAL; | ||
1136 | |||
1137 | pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); | ||
1138 | |||
1139 | chan->callback_fn = rtn; | ||
1140 | |||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn); | ||
1145 | |||
1146 | /* s3c2410_dma_devconfig | ||
1147 | * | ||
1148 | * configure the dma source/destination hardware type and address | ||
1149 | * | ||
1150 | * source: S3C2410_DMASRC_HW: source is hardware | ||
1151 | * S3C2410_DMASRC_MEM: source is memory | ||
1152 | * | ||
1153 | * hwcfg: the value for xxxSTCn register, | ||
1154 | * bit 0: 0=increment pointer, 1=leave pointer | ||
1155 | * bit 1: 0=soucre is AHB, 1=soucre is APB | ||
1156 | * | ||
1157 | * devaddr: physical address of the source | ||
1158 | */ | ||
1159 | |||
1160 | int s3c2410_dma_devconfig(int channel, | ||
1161 | enum s3c2410_dmasrc source, | ||
1162 | int hwcfg, | ||
1163 | unsigned long devaddr) | ||
1164 | { | ||
1165 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1166 | |||
1167 | if (chan == NULL) | ||
1168 | return -EINVAL; | ||
1169 | |||
1170 | pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", | ||
1171 | __FUNCTION__, (int)source, hwcfg, devaddr); | ||
1172 | |||
1173 | chan->source = source; | ||
1174 | chan->dev_addr = devaddr; | ||
1175 | |||
1176 | switch (source) { | ||
1177 | case S3C2410_DMASRC_HW: | ||
1178 | /* source is hardware */ | ||
1179 | pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", | ||
1180 | __FUNCTION__, devaddr, hwcfg); | ||
1181 | dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); | ||
1182 | dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr); | ||
1183 | dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); | ||
1184 | |||
1185 | chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); | ||
1186 | return 0; | ||
1187 | |||
1188 | case S3C2410_DMASRC_MEM: | ||
1189 | /* source is memory */ | ||
1190 | pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n", | ||
1191 | __FUNCTION__, devaddr, hwcfg); | ||
1192 | dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); | ||
1193 | dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr); | ||
1194 | dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); | ||
1195 | |||
1196 | chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); | ||
1201 | return -EINVAL; | ||
1202 | } | ||
1203 | |||
1204 | EXPORT_SYMBOL(s3c2410_dma_devconfig); | ||
1205 | |||
1206 | /* s3c2410_dma_getposition | ||
1207 | * | ||
1208 | * returns the current transfer points for the dma source and destination | ||
1209 | */ | ||
1210 | |||
1211 | int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst) | ||
1212 | { | ||
1213 | struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); | ||
1214 | |||
1215 | if (chan == NULL) | ||
1216 | return -EINVAL; | ||
1217 | |||
1218 | if (src != NULL) | ||
1219 | *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); | ||
1220 | |||
1221 | if (dst != NULL) | ||
1222 | *dst = dma_rdreg(chan, S3C2410_DMA_DCDST); | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | EXPORT_SYMBOL(s3c2410_dma_getposition); | ||
1228 | |||
1229 | |||
1230 | /* system device class */ | ||
1231 | |||
1232 | #ifdef CONFIG_PM | ||
1233 | |||
1234 | static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state) | ||
1235 | { | ||
1236 | struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev); | ||
1237 | |||
1238 | printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); | ||
1239 | |||
1240 | if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { | ||
1241 | /* the dma channel is still working, which is probably | ||
1242 | * a bad thing to do over suspend/resume. We stop the | ||
1243 | * channel and assume that the client is either going to | ||
1244 | * retry after resume, or that it is broken. | ||
1245 | */ | ||
1246 | |||
1247 | printk(KERN_INFO "dma: stopping channel %d due to suspend\n", | ||
1248 | cp->number); | ||
1249 | |||
1250 | s3c2410_dma_dostop(cp); | ||
1251 | } | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | static int s3c2410_dma_resume(struct sys_device *dev) | ||
1257 | { | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | #else | ||
1262 | #define s3c2410_dma_suspend NULL | ||
1263 | #define s3c2410_dma_resume NULL | ||
1264 | #endif /* CONFIG_PM */ | ||
1265 | |||
1266 | struct sysdev_class dma_sysclass = { | ||
1267 | set_kset_name("s3c24xx-dma"), | ||
1268 | .suspend = s3c2410_dma_suspend, | ||
1269 | .resume = s3c2410_dma_resume, | ||
1270 | }; | ||
1271 | |||
1272 | /* kmem cache implementation */ | ||
1273 | |||
1274 | static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f) | ||
1275 | { | ||
1276 | memset(p, 0, sizeof(struct s3c2410_dma_buf)); | ||
1277 | } | ||
1278 | |||
1279 | /* initialisation code */ | ||
1280 | |||
1281 | static int __init s3c2410_init_dma(void) | ||
1282 | { | ||
1283 | struct s3c2410_dma_chan *cp; | ||
1284 | int channel; | ||
1285 | int ret; | ||
1286 | |||
1287 | printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n"); | ||
1288 | |||
1289 | dma_base = ioremap(S3C24XX_PA_DMA, 0x200); | ||
1290 | if (dma_base == NULL) { | ||
1291 | printk(KERN_ERR "dma failed to remap register block\n"); | ||
1292 | return -ENOMEM; | ||
1293 | } | ||
1294 | |||
1295 | printk("Registering sysclass\n"); | ||
1296 | |||
1297 | ret = sysdev_class_register(&dma_sysclass); | ||
1298 | if (ret != 0) { | ||
1299 | printk(KERN_ERR "dma sysclass registration failed\n"); | ||
1300 | goto err; | ||
1301 | } | ||
1302 | |||
1303 | dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0, | ||
1304 | SLAB_HWCACHE_ALIGN, | ||
1305 | s3c2410_dma_cache_ctor, NULL); | ||
1306 | |||
1307 | if (dma_kmem == NULL) { | ||
1308 | printk(KERN_ERR "dma failed to make kmem cache\n"); | ||
1309 | ret = -ENOMEM; | ||
1310 | goto err; | ||
1311 | } | ||
1312 | |||
1313 | for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { | ||
1314 | cp = &s3c2410_chans[channel]; | ||
1315 | |||
1316 | memset(cp, 0, sizeof(struct s3c2410_dma_chan)); | ||
1317 | |||
1318 | /* dma channel irqs are in order.. */ | ||
1319 | cp->number = channel; | ||
1320 | cp->irq = channel + IRQ_DMA0; | ||
1321 | cp->regs = dma_base + (channel*0x40); | ||
1322 | |||
1323 | /* point current stats somewhere */ | ||
1324 | cp->stats = &cp->stats_store; | ||
1325 | cp->stats_store.timeout_shortest = LONG_MAX; | ||
1326 | |||
1327 | /* basic channel configuration */ | ||
1328 | |||
1329 | cp->load_timeout = 1<<18; | ||
1330 | |||
1331 | /* register system device */ | ||
1332 | |||
1333 | cp->dev.cls = &dma_sysclass; | ||
1334 | cp->dev.id = channel; | ||
1335 | ret = sysdev_register(&cp->dev); | ||
1336 | |||
1337 | printk("DMA channel %d at %p, irq %d\n", | ||
1338 | cp->number, cp->regs, cp->irq); | ||
1339 | } | ||
1340 | |||
1341 | return 0; | ||
1342 | |||
1343 | err: | ||
1344 | kmem_cache_destroy(dma_kmem); | ||
1345 | iounmap(dma_base); | ||
1346 | dma_base = NULL; | ||
1347 | return ret; | ||
1348 | } | ||
1349 | |||
1350 | core_initcall(s3c2410_init_dma); | ||
1351 | |||
1352 | static inline int is_channel_valid(unsigned int channel) | ||
1353 | { | ||
1354 | return (channel & DMA_CH_VALID); | ||
1355 | } | ||
1356 | |||
1357 | /* s3c2410_dma_map_channel() | ||
1358 | * | ||
1359 | * turn the virtual channel number into a real, and un-used hardware | ||
1360 | * channel. | ||
1361 | * | ||
1362 | * currently this code uses first-free channel from the specified harware | ||
1363 | * map, not taking into account anything that the board setup code may | ||
1364 | * have to say about the likely peripheral set to be in use. | ||
1365 | */ | ||
1366 | |||
1367 | struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) | ||
1368 | { | ||
1369 | struct s3c24xx_dma_map *ch_map; | ||
1370 | struct s3c2410_dma_chan *dmach; | ||
1371 | int ch; | ||
1372 | |||
1373 | if (dma_sel.map == NULL || channel > dma_sel.map_size) | ||
1374 | return NULL; | ||
1375 | |||
1376 | ch_map = dma_sel.map + channel; | ||
1377 | |||
1378 | for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) { | ||
1379 | if (!is_channel_valid(ch_map->channels[ch])) | ||
1380 | continue; | ||
1381 | |||
1382 | if (s3c2410_chans[ch].in_use == 0) { | ||
1383 | printk("mapped channel %d to %d\n", channel, ch); | ||
1384 | break; | ||
1385 | } | ||
1386 | } | ||
1387 | |||
1388 | if (ch >= S3C2410_DMA_CHANNELS) | ||
1389 | return NULL; | ||
1390 | |||
1391 | /* update our channel mapping */ | ||
1392 | |||
1393 | dmach = &s3c2410_chans[ch]; | ||
1394 | dma_chan_map[channel] = dmach; | ||
1395 | |||
1396 | /* select the channel */ | ||
1397 | |||
1398 | (dma_sel.select)(dmach, ch_map); | ||
1399 | |||
1400 | return dmach; | ||
1401 | } | ||
1402 | |||
1403 | static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch) | ||
1404 | { | ||
1405 | /* show the channel configuration */ | ||
1406 | |||
1407 | printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name, | ||
1408 | (is_channel_valid(map->channels[0]) ? '0' : '-'), | ||
1409 | (is_channel_valid(map->channels[1]) ? '1' : '-'), | ||
1410 | (is_channel_valid(map->channels[2]) ? '2' : '-'), | ||
1411 | (is_channel_valid(map->channels[3]) ? '3' : '-')); | ||
1412 | } | ||
1413 | |||
1414 | static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) | ||
1415 | { | ||
1416 | if (1) | ||
1417 | s3c24xx_dma_show_ch(map, ch); | ||
1418 | |||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) | ||
1423 | { | ||
1424 | struct s3c24xx_dma_map *nmap; | ||
1425 | size_t map_sz = sizeof(*nmap) * sel->map_size; | ||
1426 | int ptr; | ||
1427 | |||
1428 | nmap = kmalloc(map_sz, GFP_KERNEL); | ||
1429 | if (nmap == NULL) | ||
1430 | return -ENOMEM; | ||
1431 | |||
1432 | memcpy(nmap, sel->map, map_sz); | ||
1433 | memcpy(&dma_sel, sel, sizeof(*sel)); | ||
1434 | |||
1435 | dma_sel.map = nmap; | ||
1436 | |||
1437 | for (ptr = 0; ptr < sel->map_size; ptr++) | ||
1438 | s3c24xx_dma_check_entry(nmap+ptr, ptr); | ||
1439 | |||
1440 | return 0; | ||
1441 | } | ||
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c new file mode 100644 index 000000000000..ec3a09c4d181 --- /dev/null +++ b/arch/arm/plat-s3c24xx/gpio.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/gpio.c | ||
2 | * | ||
3 | * Copyright (c) 2004-2005 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C24XX GPIO 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 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/ioport.h> | ||
29 | |||
30 | #include <asm/hardware.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include <asm/arch/regs-gpio.h> | ||
35 | |||
36 | void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) | ||
37 | { | ||
38 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
39 | unsigned long mask; | ||
40 | unsigned long con; | ||
41 | unsigned long flags; | ||
42 | |||
43 | if (pin < S3C2410_GPIO_BANKB) { | ||
44 | mask = 1 << S3C2410_GPIO_OFFSET(pin); | ||
45 | } else { | ||
46 | mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; | ||
47 | } | ||
48 | |||
49 | switch (function) { | ||
50 | case S3C2410_GPIO_LEAVE: | ||
51 | mask = 0; | ||
52 | function = 0; | ||
53 | break; | ||
54 | |||
55 | case S3C2410_GPIO_INPUT: | ||
56 | case S3C2410_GPIO_OUTPUT: | ||
57 | case S3C2410_GPIO_SFN2: | ||
58 | case S3C2410_GPIO_SFN3: | ||
59 | if (pin < S3C2410_GPIO_BANKB) { | ||
60 | function -= 1; | ||
61 | function &= 1; | ||
62 | function <<= S3C2410_GPIO_OFFSET(pin); | ||
63 | } else { | ||
64 | function &= 3; | ||
65 | function <<= S3C2410_GPIO_OFFSET(pin)*2; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /* modify the specified register wwith IRQs off */ | ||
70 | |||
71 | local_irq_save(flags); | ||
72 | |||
73 | con = __raw_readl(base + 0x00); | ||
74 | con &= ~mask; | ||
75 | con |= function; | ||
76 | |||
77 | __raw_writel(con, base + 0x00); | ||
78 | |||
79 | local_irq_restore(flags); | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL(s3c2410_gpio_cfgpin); | ||
83 | |||
84 | unsigned int s3c2410_gpio_getcfg(unsigned int pin) | ||
85 | { | ||
86 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
87 | unsigned long val = __raw_readl(base); | ||
88 | |||
89 | if (pin < S3C2410_GPIO_BANKB) { | ||
90 | val >>= S3C2410_GPIO_OFFSET(pin); | ||
91 | val &= 1; | ||
92 | val += 1; | ||
93 | } else { | ||
94 | val >>= S3C2410_GPIO_OFFSET(pin)*2; | ||
95 | val &= 3; | ||
96 | } | ||
97 | |||
98 | return val | S3C2410_GPIO_INPUT; | ||
99 | } | ||
100 | |||
101 | EXPORT_SYMBOL(s3c2410_gpio_getcfg); | ||
102 | |||
103 | void s3c2410_gpio_pullup(unsigned int pin, unsigned int to) | ||
104 | { | ||
105 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
106 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
107 | unsigned long flags; | ||
108 | unsigned long up; | ||
109 | |||
110 | if (pin < S3C2410_GPIO_BANKB) | ||
111 | return; | ||
112 | |||
113 | local_irq_save(flags); | ||
114 | |||
115 | up = __raw_readl(base + 0x08); | ||
116 | up &= ~(1L << offs); | ||
117 | up |= to << offs; | ||
118 | __raw_writel(up, base + 0x08); | ||
119 | |||
120 | local_irq_restore(flags); | ||
121 | } | ||
122 | |||
123 | EXPORT_SYMBOL(s3c2410_gpio_pullup); | ||
124 | |||
125 | void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) | ||
126 | { | ||
127 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
128 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
129 | unsigned long flags; | ||
130 | unsigned long dat; | ||
131 | |||
132 | local_irq_save(flags); | ||
133 | |||
134 | dat = __raw_readl(base + 0x04); | ||
135 | dat &= ~(1 << offs); | ||
136 | dat |= to << offs; | ||
137 | __raw_writel(dat, base + 0x04); | ||
138 | |||
139 | local_irq_restore(flags); | ||
140 | } | ||
141 | |||
142 | EXPORT_SYMBOL(s3c2410_gpio_setpin); | ||
143 | |||
144 | unsigned int s3c2410_gpio_getpin(unsigned int pin) | ||
145 | { | ||
146 | void __iomem *base = S3C24XX_GPIO_BASE(pin); | ||
147 | unsigned long offs = S3C2410_GPIO_OFFSET(pin); | ||
148 | |||
149 | return __raw_readl(base + 0x04) & (1<< offs); | ||
150 | } | ||
151 | |||
152 | EXPORT_SYMBOL(s3c2410_gpio_getpin); | ||
153 | |||
154 | unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) | ||
155 | { | ||
156 | unsigned long flags; | ||
157 | unsigned long misccr; | ||
158 | |||
159 | local_irq_save(flags); | ||
160 | misccr = __raw_readl(S3C24XX_MISCCR); | ||
161 | misccr &= ~clear; | ||
162 | misccr ^= change; | ||
163 | __raw_writel(misccr, S3C24XX_MISCCR); | ||
164 | local_irq_restore(flags); | ||
165 | |||
166 | return misccr; | ||
167 | } | ||
168 | |||
169 | EXPORT_SYMBOL(s3c2410_modify_misccr); | ||
170 | |||
171 | int s3c2410_gpio_getirq(unsigned int pin) | ||
172 | { | ||
173 | if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15) | ||
174 | return -1; /* not valid interrupts */ | ||
175 | |||
176 | if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) | ||
177 | return -1; /* not valid pin */ | ||
178 | |||
179 | if (pin < S3C2410_GPF4) | ||
180 | return (pin - S3C2410_GPF0) + IRQ_EINT0; | ||
181 | |||
182 | if (pin < S3C2410_GPG0) | ||
183 | return (pin - S3C2410_GPF4) + IRQ_EINT4; | ||
184 | |||
185 | return (pin - S3C2410_GPG0) + IRQ_EINT8; | ||
186 | } | ||
187 | |||
188 | EXPORT_SYMBOL(s3c2410_gpio_getirq); | ||
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c new file mode 100644 index 000000000000..ce186398e3fd --- /dev/null +++ b/arch/arm/plat-s3c24xx/irq.c | |||
@@ -0,0 +1,801 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/irq.c | ||
2 | * | ||
3 | * Copyright (c) 2003,2004 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 | * Changelog: | ||
21 | * | ||
22 | * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk> | ||
23 | * Fixed compile warnings | ||
24 | * | ||
25 | * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn> | ||
26 | * Fixed s3c_extirq_type | ||
27 | * | ||
28 | * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> | ||
29 | * Addition of ADC/TC demux | ||
30 | * | ||
31 | * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de> | ||
32 | * Fix for set_irq_type() on low EINT numbers | ||
33 | * | ||
34 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
35 | * Tidy up KF's patch and sort out new release | ||
36 | * | ||
37 | * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk> | ||
38 | * Add support for power management controls | ||
39 | * | ||
40 | * 04-Nov-2004 Ben Dooks | ||
41 | * Fix standard IRQ wake for EINT0..4 and RTC | ||
42 | * | ||
43 | * 22-Feb-2005 Ben Dooks | ||
44 | * Fixed edge-triggering on ADC IRQ | ||
45 | * | ||
46 | * 28-Jun-2005 Ben Dooks | ||
47 | * Mark IRQ_LCD valid | ||
48 | * | ||
49 | * 25-Jul-2005 Ben Dooks | ||
50 | * Split the S3C2440 IRQ code to seperate file | ||
51 | */ | ||
52 | |||
53 | #include <linux/init.h> | ||
54 | #include <linux/module.h> | ||
55 | #include <linux/interrupt.h> | ||
56 | #include <linux/ioport.h> | ||
57 | #include <linux/ptrace.h> | ||
58 | #include <linux/sysdev.h> | ||
59 | |||
60 | #include <asm/hardware.h> | ||
61 | #include <asm/irq.h> | ||
62 | #include <asm/io.h> | ||
63 | |||
64 | #include <asm/mach/irq.h> | ||
65 | |||
66 | #include <asm/arch/regs-irq.h> | ||
67 | #include <asm/arch/regs-gpio.h> | ||
68 | |||
69 | #include <asm/plat-s3c24xx/cpu.h> | ||
70 | #include <asm/plat-s3c24xx/pm.h> | ||
71 | #include <asm/plat-s3c24xx/irq.h> | ||
72 | |||
73 | /* wakeup irq control */ | ||
74 | |||
75 | #ifdef CONFIG_PM | ||
76 | |||
77 | /* state for IRQs over sleep */ | ||
78 | |||
79 | /* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources | ||
80 | * | ||
81 | * set bit to 1 in allow bitfield to enable the wakeup settings on it | ||
82 | */ | ||
83 | |||
84 | unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL; | ||
85 | unsigned long s3c_irqwake_intmask = 0xffffffffL; | ||
86 | unsigned long s3c_irqwake_eintallow = 0x0000fff0L; | ||
87 | unsigned long s3c_irqwake_eintmask = 0xffffffffL; | ||
88 | |||
89 | int | ||
90 | s3c_irq_wake(unsigned int irqno, unsigned int state) | ||
91 | { | ||
92 | unsigned long irqbit = 1 << (irqno - IRQ_EINT0); | ||
93 | |||
94 | if (!(s3c_irqwake_intallow & irqbit)) | ||
95 | return -ENOENT; | ||
96 | |||
97 | printk(KERN_INFO "wake %s for irq %d\n", | ||
98 | state ? "enabled" : "disabled", irqno); | ||
99 | |||
100 | if (!state) | ||
101 | s3c_irqwake_intmask |= irqbit; | ||
102 | else | ||
103 | s3c_irqwake_intmask &= ~irqbit; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | s3c_irqext_wake(unsigned int irqno, unsigned int state) | ||
110 | { | ||
111 | unsigned long bit = 1L << (irqno - EXTINT_OFF); | ||
112 | |||
113 | if (!(s3c_irqwake_eintallow & bit)) | ||
114 | return -ENOENT; | ||
115 | |||
116 | printk(KERN_INFO "wake %s for irq %d\n", | ||
117 | state ? "enabled" : "disabled", irqno); | ||
118 | |||
119 | if (!state) | ||
120 | s3c_irqwake_eintmask |= bit; | ||
121 | else | ||
122 | s3c_irqwake_eintmask &= ~bit; | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | #else | ||
128 | #define s3c_irqext_wake NULL | ||
129 | #define s3c_irq_wake NULL | ||
130 | #endif | ||
131 | |||
132 | |||
133 | static void | ||
134 | s3c_irq_mask(unsigned int irqno) | ||
135 | { | ||
136 | unsigned long mask; | ||
137 | |||
138 | irqno -= IRQ_EINT0; | ||
139 | |||
140 | mask = __raw_readl(S3C2410_INTMSK); | ||
141 | mask |= 1UL << irqno; | ||
142 | __raw_writel(mask, S3C2410_INTMSK); | ||
143 | } | ||
144 | |||
145 | static inline void | ||
146 | s3c_irq_ack(unsigned int irqno) | ||
147 | { | ||
148 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
149 | |||
150 | __raw_writel(bitval, S3C2410_SRCPND); | ||
151 | __raw_writel(bitval, S3C2410_INTPND); | ||
152 | } | ||
153 | |||
154 | static inline void | ||
155 | s3c_irq_maskack(unsigned int irqno) | ||
156 | { | ||
157 | unsigned long bitval = 1UL << (irqno - IRQ_EINT0); | ||
158 | unsigned long mask; | ||
159 | |||
160 | mask = __raw_readl(S3C2410_INTMSK); | ||
161 | __raw_writel(mask|bitval, S3C2410_INTMSK); | ||
162 | |||
163 | __raw_writel(bitval, S3C2410_SRCPND); | ||
164 | __raw_writel(bitval, S3C2410_INTPND); | ||
165 | } | ||
166 | |||
167 | |||
168 | static void | ||
169 | s3c_irq_unmask(unsigned int irqno) | ||
170 | { | ||
171 | unsigned long mask; | ||
172 | |||
173 | if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23) | ||
174 | irqdbf2("s3c_irq_unmask %d\n", irqno); | ||
175 | |||
176 | irqno -= IRQ_EINT0; | ||
177 | |||
178 | mask = __raw_readl(S3C2410_INTMSK); | ||
179 | mask &= ~(1UL << irqno); | ||
180 | __raw_writel(mask, S3C2410_INTMSK); | ||
181 | } | ||
182 | |||
183 | struct irq_chip s3c_irq_level_chip = { | ||
184 | .name = "s3c-level", | ||
185 | .ack = s3c_irq_maskack, | ||
186 | .mask = s3c_irq_mask, | ||
187 | .unmask = s3c_irq_unmask, | ||
188 | .set_wake = s3c_irq_wake | ||
189 | }; | ||
190 | |||
191 | static struct irq_chip s3c_irq_chip = { | ||
192 | .name = "s3c", | ||
193 | .ack = s3c_irq_ack, | ||
194 | .mask = s3c_irq_mask, | ||
195 | .unmask = s3c_irq_unmask, | ||
196 | .set_wake = s3c_irq_wake | ||
197 | }; | ||
198 | |||
199 | static void | ||
200 | s3c_irqext_mask(unsigned int irqno) | ||
201 | { | ||
202 | unsigned long mask; | ||
203 | |||
204 | irqno -= EXTINT_OFF; | ||
205 | |||
206 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
207 | mask |= ( 1UL << irqno); | ||
208 | __raw_writel(mask, S3C24XX_EINTMASK); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | s3c_irqext_ack(unsigned int irqno) | ||
213 | { | ||
214 | unsigned long req; | ||
215 | unsigned long bit; | ||
216 | unsigned long mask; | ||
217 | |||
218 | bit = 1UL << (irqno - EXTINT_OFF); | ||
219 | |||
220 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
221 | |||
222 | __raw_writel(bit, S3C24XX_EINTPEND); | ||
223 | |||
224 | req = __raw_readl(S3C24XX_EINTPEND); | ||
225 | req &= ~mask; | ||
226 | |||
227 | /* not sure if we should be acking the parent irq... */ | ||
228 | |||
229 | if (irqno <= IRQ_EINT7 ) { | ||
230 | if ((req & 0xf0) == 0) | ||
231 | s3c_irq_ack(IRQ_EINT4t7); | ||
232 | } else { | ||
233 | if ((req >> 8) == 0) | ||
234 | s3c_irq_ack(IRQ_EINT8t23); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | static void | ||
239 | s3c_irqext_unmask(unsigned int irqno) | ||
240 | { | ||
241 | unsigned long mask; | ||
242 | |||
243 | irqno -= EXTINT_OFF; | ||
244 | |||
245 | mask = __raw_readl(S3C24XX_EINTMASK); | ||
246 | mask &= ~( 1UL << irqno); | ||
247 | __raw_writel(mask, S3C24XX_EINTMASK); | ||
248 | } | ||
249 | |||
250 | int | ||
251 | s3c_irqext_type(unsigned int irq, unsigned int type) | ||
252 | { | ||
253 | void __iomem *extint_reg; | ||
254 | void __iomem *gpcon_reg; | ||
255 | unsigned long gpcon_offset, extint_offset; | ||
256 | unsigned long newvalue = 0, value; | ||
257 | |||
258 | if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) | ||
259 | { | ||
260 | gpcon_reg = S3C2410_GPFCON; | ||
261 | extint_reg = S3C24XX_EXTINT0; | ||
262 | gpcon_offset = (irq - IRQ_EINT0) * 2; | ||
263 | extint_offset = (irq - IRQ_EINT0) * 4; | ||
264 | } | ||
265 | else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) | ||
266 | { | ||
267 | gpcon_reg = S3C2410_GPFCON; | ||
268 | extint_reg = S3C24XX_EXTINT0; | ||
269 | gpcon_offset = (irq - (EXTINT_OFF)) * 2; | ||
270 | extint_offset = (irq - (EXTINT_OFF)) * 4; | ||
271 | } | ||
272 | else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) | ||
273 | { | ||
274 | gpcon_reg = S3C2410_GPGCON; | ||
275 | extint_reg = S3C24XX_EXTINT1; | ||
276 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
277 | extint_offset = (irq - IRQ_EINT8) * 4; | ||
278 | } | ||
279 | else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) | ||
280 | { | ||
281 | gpcon_reg = S3C2410_GPGCON; | ||
282 | extint_reg = S3C24XX_EXTINT2; | ||
283 | gpcon_offset = (irq - IRQ_EINT8) * 2; | ||
284 | extint_offset = (irq - IRQ_EINT16) * 4; | ||
285 | } else | ||
286 | return -1; | ||
287 | |||
288 | /* Set the GPIO to external interrupt mode */ | ||
289 | value = __raw_readl(gpcon_reg); | ||
290 | value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); | ||
291 | __raw_writel(value, gpcon_reg); | ||
292 | |||
293 | /* Set the external interrupt to pointed trigger type */ | ||
294 | switch (type) | ||
295 | { | ||
296 | case IRQT_NOEDGE: | ||
297 | printk(KERN_WARNING "No edge setting!\n"); | ||
298 | break; | ||
299 | |||
300 | case IRQT_RISING: | ||
301 | newvalue = S3C2410_EXTINT_RISEEDGE; | ||
302 | break; | ||
303 | |||
304 | case IRQT_FALLING: | ||
305 | newvalue = S3C2410_EXTINT_FALLEDGE; | ||
306 | break; | ||
307 | |||
308 | case IRQT_BOTHEDGE: | ||
309 | newvalue = S3C2410_EXTINT_BOTHEDGE; | ||
310 | break; | ||
311 | |||
312 | case IRQT_LOW: | ||
313 | newvalue = S3C2410_EXTINT_LOWLEV; | ||
314 | break; | ||
315 | |||
316 | case IRQT_HIGH: | ||
317 | newvalue = S3C2410_EXTINT_HILEV; | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | printk(KERN_ERR "No such irq type %d", type); | ||
322 | return -1; | ||
323 | } | ||
324 | |||
325 | value = __raw_readl(extint_reg); | ||
326 | value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); | ||
327 | __raw_writel(value, extint_reg); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static struct irq_chip s3c_irqext_chip = { | ||
333 | .name = "s3c-ext", | ||
334 | .mask = s3c_irqext_mask, | ||
335 | .unmask = s3c_irqext_unmask, | ||
336 | .ack = s3c_irqext_ack, | ||
337 | .set_type = s3c_irqext_type, | ||
338 | .set_wake = s3c_irqext_wake | ||
339 | }; | ||
340 | |||
341 | static struct irq_chip s3c_irq_eint0t4 = { | ||
342 | .name = "s3c-ext0", | ||
343 | .ack = s3c_irq_ack, | ||
344 | .mask = s3c_irq_mask, | ||
345 | .unmask = s3c_irq_unmask, | ||
346 | .set_wake = s3c_irq_wake, | ||
347 | .set_type = s3c_irqext_type, | ||
348 | }; | ||
349 | |||
350 | /* mask values for the parent registers for each of the interrupt types */ | ||
351 | |||
352 | #define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0)) | ||
353 | #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) | ||
354 | #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) | ||
355 | #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) | ||
356 | |||
357 | |||
358 | /* UART0 */ | ||
359 | |||
360 | static void | ||
361 | s3c_irq_uart0_mask(unsigned int irqno) | ||
362 | { | ||
363 | s3c_irqsub_mask(irqno, INTMSK_UART0, 7); | ||
364 | } | ||
365 | |||
366 | static void | ||
367 | s3c_irq_uart0_unmask(unsigned int irqno) | ||
368 | { | ||
369 | s3c_irqsub_unmask(irqno, INTMSK_UART0); | ||
370 | } | ||
371 | |||
372 | static void | ||
373 | s3c_irq_uart0_ack(unsigned int irqno) | ||
374 | { | ||
375 | s3c_irqsub_maskack(irqno, INTMSK_UART0, 7); | ||
376 | } | ||
377 | |||
378 | static struct irq_chip s3c_irq_uart0 = { | ||
379 | .name = "s3c-uart0", | ||
380 | .mask = s3c_irq_uart0_mask, | ||
381 | .unmask = s3c_irq_uart0_unmask, | ||
382 | .ack = s3c_irq_uart0_ack, | ||
383 | }; | ||
384 | |||
385 | /* UART1 */ | ||
386 | |||
387 | static void | ||
388 | s3c_irq_uart1_mask(unsigned int irqno) | ||
389 | { | ||
390 | s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3); | ||
391 | } | ||
392 | |||
393 | static void | ||
394 | s3c_irq_uart1_unmask(unsigned int irqno) | ||
395 | { | ||
396 | s3c_irqsub_unmask(irqno, INTMSK_UART1); | ||
397 | } | ||
398 | |||
399 | static void | ||
400 | s3c_irq_uart1_ack(unsigned int irqno) | ||
401 | { | ||
402 | s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3); | ||
403 | } | ||
404 | |||
405 | static struct irq_chip s3c_irq_uart1 = { | ||
406 | .name = "s3c-uart1", | ||
407 | .mask = s3c_irq_uart1_mask, | ||
408 | .unmask = s3c_irq_uart1_unmask, | ||
409 | .ack = s3c_irq_uart1_ack, | ||
410 | }; | ||
411 | |||
412 | /* UART2 */ | ||
413 | |||
414 | static void | ||
415 | s3c_irq_uart2_mask(unsigned int irqno) | ||
416 | { | ||
417 | s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6); | ||
418 | } | ||
419 | |||
420 | static void | ||
421 | s3c_irq_uart2_unmask(unsigned int irqno) | ||
422 | { | ||
423 | s3c_irqsub_unmask(irqno, INTMSK_UART2); | ||
424 | } | ||
425 | |||
426 | static void | ||
427 | s3c_irq_uart2_ack(unsigned int irqno) | ||
428 | { | ||
429 | s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6); | ||
430 | } | ||
431 | |||
432 | static struct irq_chip s3c_irq_uart2 = { | ||
433 | .name = "s3c-uart2", | ||
434 | .mask = s3c_irq_uart2_mask, | ||
435 | .unmask = s3c_irq_uart2_unmask, | ||
436 | .ack = s3c_irq_uart2_ack, | ||
437 | }; | ||
438 | |||
439 | /* ADC and Touchscreen */ | ||
440 | |||
441 | static void | ||
442 | s3c_irq_adc_mask(unsigned int irqno) | ||
443 | { | ||
444 | s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
445 | } | ||
446 | |||
447 | static void | ||
448 | s3c_irq_adc_unmask(unsigned int irqno) | ||
449 | { | ||
450 | s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT); | ||
451 | } | ||
452 | |||
453 | static void | ||
454 | s3c_irq_adc_ack(unsigned int irqno) | ||
455 | { | ||
456 | s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9); | ||
457 | } | ||
458 | |||
459 | static struct irq_chip s3c_irq_adc = { | ||
460 | .name = "s3c-adc", | ||
461 | .mask = s3c_irq_adc_mask, | ||
462 | .unmask = s3c_irq_adc_unmask, | ||
463 | .ack = s3c_irq_adc_ack, | ||
464 | }; | ||
465 | |||
466 | /* irq demux for adc */ | ||
467 | static void s3c_irq_demux_adc(unsigned int irq, | ||
468 | struct irq_desc *desc) | ||
469 | { | ||
470 | unsigned int subsrc, submsk; | ||
471 | unsigned int offset = 9; | ||
472 | struct irq_desc *mydesc; | ||
473 | |||
474 | /* read the current pending interrupts, and the mask | ||
475 | * for what it is available */ | ||
476 | |||
477 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
478 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
479 | |||
480 | subsrc &= ~submsk; | ||
481 | subsrc >>= offset; | ||
482 | subsrc &= 3; | ||
483 | |||
484 | if (subsrc != 0) { | ||
485 | if (subsrc & 1) { | ||
486 | mydesc = irq_desc + IRQ_TC; | ||
487 | desc_handle_irq(IRQ_TC, mydesc); | ||
488 | } | ||
489 | if (subsrc & 2) { | ||
490 | mydesc = irq_desc + IRQ_ADC; | ||
491 | desc_handle_irq(IRQ_ADC, mydesc); | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static void s3c_irq_demux_uart(unsigned int start) | ||
497 | { | ||
498 | unsigned int subsrc, submsk; | ||
499 | unsigned int offset = start - IRQ_S3CUART_RX0; | ||
500 | struct irq_desc *desc; | ||
501 | |||
502 | /* read the current pending interrupts, and the mask | ||
503 | * for what it is available */ | ||
504 | |||
505 | subsrc = __raw_readl(S3C2410_SUBSRCPND); | ||
506 | submsk = __raw_readl(S3C2410_INTSUBMSK); | ||
507 | |||
508 | irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n", | ||
509 | start, offset, subsrc, submsk); | ||
510 | |||
511 | subsrc &= ~submsk; | ||
512 | subsrc >>= offset; | ||
513 | subsrc &= 7; | ||
514 | |||
515 | if (subsrc != 0) { | ||
516 | desc = irq_desc + start; | ||
517 | |||
518 | if (subsrc & 1) | ||
519 | desc_handle_irq(start, desc); | ||
520 | |||
521 | desc++; | ||
522 | |||
523 | if (subsrc & 2) | ||
524 | desc_handle_irq(start+1, desc); | ||
525 | |||
526 | desc++; | ||
527 | |||
528 | if (subsrc & 4) | ||
529 | desc_handle_irq(start+2, desc); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* uart demux entry points */ | ||
534 | |||
535 | static void | ||
536 | s3c_irq_demux_uart0(unsigned int irq, | ||
537 | struct irq_desc *desc) | ||
538 | { | ||
539 | irq = irq; | ||
540 | s3c_irq_demux_uart(IRQ_S3CUART_RX0); | ||
541 | } | ||
542 | |||
543 | static void | ||
544 | s3c_irq_demux_uart1(unsigned int irq, | ||
545 | struct irq_desc *desc) | ||
546 | { | ||
547 | irq = irq; | ||
548 | s3c_irq_demux_uart(IRQ_S3CUART_RX1); | ||
549 | } | ||
550 | |||
551 | static void | ||
552 | s3c_irq_demux_uart2(unsigned int irq, | ||
553 | struct irq_desc *desc) | ||
554 | { | ||
555 | irq = irq; | ||
556 | s3c_irq_demux_uart(IRQ_S3CUART_RX2); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | s3c_irq_demux_extint8(unsigned int irq, | ||
561 | struct irq_desc *desc) | ||
562 | { | ||
563 | unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); | ||
564 | unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); | ||
565 | |||
566 | eintpnd &= ~eintmsk; | ||
567 | eintpnd &= ~0xff; /* ignore lower irqs */ | ||
568 | |||
569 | /* we may as well handle all the pending IRQs here */ | ||
570 | |||
571 | while (eintpnd) { | ||
572 | irq = __ffs(eintpnd); | ||
573 | eintpnd &= ~(1<<irq); | ||
574 | |||
575 | irq += (IRQ_EINT4 - 4); | ||
576 | desc_handle_irq(irq, irq_desc + irq); | ||
577 | } | ||
578 | |||
579 | } | ||
580 | |||
581 | static void | ||
582 | s3c_irq_demux_extint4t7(unsigned int irq, | ||
583 | struct irq_desc *desc) | ||
584 | { | ||
585 | unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); | ||
586 | unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); | ||
587 | |||
588 | eintpnd &= ~eintmsk; | ||
589 | eintpnd &= 0xff; /* only lower irqs */ | ||
590 | |||
591 | /* we may as well handle all the pending IRQs here */ | ||
592 | |||
593 | while (eintpnd) { | ||
594 | irq = __ffs(eintpnd); | ||
595 | eintpnd &= ~(1<<irq); | ||
596 | |||
597 | irq += (IRQ_EINT4 - 4); | ||
598 | |||
599 | desc_handle_irq(irq, irq_desc + irq); | ||
600 | } | ||
601 | } | ||
602 | |||
603 | #ifdef CONFIG_PM | ||
604 | |||
605 | static struct sleep_save irq_save[] = { | ||
606 | SAVE_ITEM(S3C2410_INTMSK), | ||
607 | SAVE_ITEM(S3C2410_INTSUBMSK), | ||
608 | }; | ||
609 | |||
610 | /* the extint values move between the s3c2410/s3c2440 and the s3c2412 | ||
611 | * so we use an array to hold them, and to calculate the address of | ||
612 | * the register at run-time | ||
613 | */ | ||
614 | |||
615 | static unsigned long save_extint[3]; | ||
616 | static unsigned long save_eintflt[4]; | ||
617 | static unsigned long save_eintmask; | ||
618 | |||
619 | int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state) | ||
620 | { | ||
621 | unsigned int i; | ||
622 | |||
623 | for (i = 0; i < ARRAY_SIZE(save_extint); i++) | ||
624 | save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); | ||
625 | |||
626 | for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) | ||
627 | save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); | ||
628 | |||
629 | s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); | ||
630 | save_eintmask = __raw_readl(S3C24XX_EINTMASK); | ||
631 | |||
632 | return 0; | ||
633 | } | ||
634 | |||
635 | int s3c24xx_irq_resume(struct sys_device *dev) | ||
636 | { | ||
637 | unsigned int i; | ||
638 | |||
639 | for (i = 0; i < ARRAY_SIZE(save_extint); i++) | ||
640 | __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); | ||
641 | |||
642 | for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) | ||
643 | __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); | ||
644 | |||
645 | s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); | ||
646 | __raw_writel(save_eintmask, S3C24XX_EINTMASK); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | #else | ||
652 | #define s3c24xx_irq_suspend NULL | ||
653 | #define s3c24xx_irq_resume NULL | ||
654 | #endif | ||
655 | |||
656 | /* s3c24xx_init_irq | ||
657 | * | ||
658 | * Initialise S3C2410 IRQ system | ||
659 | */ | ||
660 | |||
661 | void __init s3c24xx_init_irq(void) | ||
662 | { | ||
663 | unsigned long pend; | ||
664 | unsigned long last; | ||
665 | int irqno; | ||
666 | int i; | ||
667 | |||
668 | irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); | ||
669 | |||
670 | /* first, clear all interrupts pending... */ | ||
671 | |||
672 | last = 0; | ||
673 | for (i = 0; i < 4; i++) { | ||
674 | pend = __raw_readl(S3C24XX_EINTPEND); | ||
675 | |||
676 | if (pend == 0 || pend == last) | ||
677 | break; | ||
678 | |||
679 | __raw_writel(pend, S3C24XX_EINTPEND); | ||
680 | printk("irq: clearing pending ext status %08x\n", (int)pend); | ||
681 | last = pend; | ||
682 | } | ||
683 | |||
684 | last = 0; | ||
685 | for (i = 0; i < 4; i++) { | ||
686 | pend = __raw_readl(S3C2410_INTPND); | ||
687 | |||
688 | if (pend == 0 || pend == last) | ||
689 | break; | ||
690 | |||
691 | __raw_writel(pend, S3C2410_SRCPND); | ||
692 | __raw_writel(pend, S3C2410_INTPND); | ||
693 | printk("irq: clearing pending status %08x\n", (int)pend); | ||
694 | last = pend; | ||
695 | } | ||
696 | |||
697 | last = 0; | ||
698 | for (i = 0; i < 4; i++) { | ||
699 | pend = __raw_readl(S3C2410_SUBSRCPND); | ||
700 | |||
701 | if (pend == 0 || pend == last) | ||
702 | break; | ||
703 | |||
704 | printk("irq: clearing subpending status %08x\n", (int)pend); | ||
705 | __raw_writel(pend, S3C2410_SUBSRCPND); | ||
706 | last = pend; | ||
707 | } | ||
708 | |||
709 | /* register the main interrupts */ | ||
710 | |||
711 | irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); | ||
712 | |||
713 | for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { | ||
714 | /* set all the s3c2410 internal irqs */ | ||
715 | |||
716 | switch (irqno) { | ||
717 | /* deal with the special IRQs (cascaded) */ | ||
718 | |||
719 | case IRQ_EINT4t7: | ||
720 | case IRQ_EINT8t23: | ||
721 | case IRQ_UART0: | ||
722 | case IRQ_UART1: | ||
723 | case IRQ_UART2: | ||
724 | case IRQ_ADCPARENT: | ||
725 | set_irq_chip(irqno, &s3c_irq_level_chip); | ||
726 | set_irq_handler(irqno, handle_level_irq); | ||
727 | break; | ||
728 | |||
729 | case IRQ_RESERVED6: | ||
730 | case IRQ_RESERVED24: | ||
731 | /* no IRQ here */ | ||
732 | break; | ||
733 | |||
734 | default: | ||
735 | //irqdbf("registering irq %d (s3c irq)\n", irqno); | ||
736 | set_irq_chip(irqno, &s3c_irq_chip); | ||
737 | set_irq_handler(irqno, handle_edge_irq); | ||
738 | set_irq_flags(irqno, IRQF_VALID); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | /* setup the cascade irq handlers */ | ||
743 | |||
744 | set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); | ||
745 | set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); | ||
746 | |||
747 | set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); | ||
748 | set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); | ||
749 | set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); | ||
750 | set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); | ||
751 | |||
752 | /* external interrupts */ | ||
753 | |||
754 | for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { | ||
755 | irqdbf("registering irq %d (ext int)\n", irqno); | ||
756 | set_irq_chip(irqno, &s3c_irq_eint0t4); | ||
757 | set_irq_handler(irqno, handle_edge_irq); | ||
758 | set_irq_flags(irqno, IRQF_VALID); | ||
759 | } | ||
760 | |||
761 | for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { | ||
762 | irqdbf("registering irq %d (extended s3c irq)\n", irqno); | ||
763 | set_irq_chip(irqno, &s3c_irqext_chip); | ||
764 | set_irq_handler(irqno, handle_edge_irq); | ||
765 | set_irq_flags(irqno, IRQF_VALID); | ||
766 | } | ||
767 | |||
768 | /* register the uart interrupts */ | ||
769 | |||
770 | irqdbf("s3c2410: registering external interrupts\n"); | ||
771 | |||
772 | for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { | ||
773 | irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); | ||
774 | set_irq_chip(irqno, &s3c_irq_uart0); | ||
775 | set_irq_handler(irqno, handle_level_irq); | ||
776 | set_irq_flags(irqno, IRQF_VALID); | ||
777 | } | ||
778 | |||
779 | for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { | ||
780 | irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); | ||
781 | set_irq_chip(irqno, &s3c_irq_uart1); | ||
782 | set_irq_handler(irqno, handle_level_irq); | ||
783 | set_irq_flags(irqno, IRQF_VALID); | ||
784 | } | ||
785 | |||
786 | for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { | ||
787 | irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); | ||
788 | set_irq_chip(irqno, &s3c_irq_uart2); | ||
789 | set_irq_handler(irqno, handle_level_irq); | ||
790 | set_irq_flags(irqno, IRQF_VALID); | ||
791 | } | ||
792 | |||
793 | for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { | ||
794 | irqdbf("registering irq %d (s3c adc irq)\n", irqno); | ||
795 | set_irq_chip(irqno, &s3c_irq_adc); | ||
796 | set_irq_handler(irqno, handle_edge_irq); | ||
797 | set_irq_flags(irqno, IRQF_VALID); | ||
798 | } | ||
799 | |||
800 | irqdbf("s3c2410: registered interrupt handlers\n"); | ||
801 | } | ||
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c index 619133eb7168..bd965f2feeca 100644 --- a/arch/arm/mach-s3c2410/pm-simtec.c +++ b/arch/arm/plat-s3c24xx/pm-simtec.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/pm-simtec.c | 1 | /* linux/arch/arm/plat-s3c24xx/pm-simtec.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
34 | 34 | ||
35 | #include "pm.h" | 35 | #include <asm/plat-s3c24xx/pm.h> |
36 | 36 | ||
37 | #define COPYRIGHT ", (c) 2005 Simtec Electronics" | 37 | #define COPYRIGHT ", (c) 2005 Simtec Electronics" |
38 | 38 | ||
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c new file mode 100644 index 000000000000..ecf68d611904 --- /dev/null +++ b/arch/arm/plat-s3c24xx/pm.c | |||
@@ -0,0 +1,659 @@ | |||
1 | /* linux/arch/arm/plat-s3c24xx/pm.c | ||
2 | * | ||
3 | * Copyright (c) 2004,2006 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C24XX Power Manager (Suspend-To-RAM) support | ||
7 | * | ||
8 | * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information | ||
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 as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * Parts based on arch/arm/mach-pxa/pm.c | ||
25 | * | ||
26 | * Thanks to Dimitry Andric for debugging | ||
27 | */ | ||
28 | |||
29 | #include <linux/init.h> | ||
30 | #include <linux/suspend.h> | ||
31 | #include <linux/errno.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/crc32.h> | ||
35 | #include <linux/ioport.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/serial_core.h> | ||
38 | |||
39 | #include <asm/cacheflush.h> | ||
40 | #include <asm/hardware.h> | ||
41 | #include <asm/io.h> | ||
42 | |||
43 | #include <asm/arch/regs-serial.h> | ||
44 | #include <asm/arch/regs-clock.h> | ||
45 | #include <asm/arch/regs-gpio.h> | ||
46 | #include <asm/arch/regs-mem.h> | ||
47 | #include <asm/arch/regs-irq.h> | ||
48 | |||
49 | #include <asm/mach/time.h> | ||
50 | |||
51 | #include <asm/plat-s3c24xx/pm.h> | ||
52 | |||
53 | /* for external use */ | ||
54 | |||
55 | unsigned long s3c_pm_flags; | ||
56 | |||
57 | #define PFX "s3c24xx-pm: " | ||
58 | |||
59 | static struct sleep_save core_save[] = { | ||
60 | SAVE_ITEM(S3C2410_LOCKTIME), | ||
61 | SAVE_ITEM(S3C2410_CLKCON), | ||
62 | |||
63 | /* we restore the timings here, with the proviso that the board | ||
64 | * brings the system up in an slower, or equal frequency setting | ||
65 | * to the original system. | ||
66 | * | ||
67 | * if we cannot guarantee this, then things are going to go very | ||
68 | * wrong here, as we modify the refresh and both pll settings. | ||
69 | */ | ||
70 | |||
71 | SAVE_ITEM(S3C2410_BWSCON), | ||
72 | SAVE_ITEM(S3C2410_BANKCON0), | ||
73 | SAVE_ITEM(S3C2410_BANKCON1), | ||
74 | SAVE_ITEM(S3C2410_BANKCON2), | ||
75 | SAVE_ITEM(S3C2410_BANKCON3), | ||
76 | SAVE_ITEM(S3C2410_BANKCON4), | ||
77 | SAVE_ITEM(S3C2410_BANKCON5), | ||
78 | |||
79 | SAVE_ITEM(S3C2410_CLKDIVN), | ||
80 | SAVE_ITEM(S3C2410_MPLLCON), | ||
81 | SAVE_ITEM(S3C2410_UPLLCON), | ||
82 | SAVE_ITEM(S3C2410_CLKSLOW), | ||
83 | SAVE_ITEM(S3C2410_REFRESH), | ||
84 | }; | ||
85 | |||
86 | static struct sleep_save gpio_save[] = { | ||
87 | SAVE_ITEM(S3C2410_GPACON), | ||
88 | SAVE_ITEM(S3C2410_GPADAT), | ||
89 | |||
90 | SAVE_ITEM(S3C2410_GPBCON), | ||
91 | SAVE_ITEM(S3C2410_GPBDAT), | ||
92 | SAVE_ITEM(S3C2410_GPBUP), | ||
93 | |||
94 | SAVE_ITEM(S3C2410_GPCCON), | ||
95 | SAVE_ITEM(S3C2410_GPCDAT), | ||
96 | SAVE_ITEM(S3C2410_GPCUP), | ||
97 | |||
98 | SAVE_ITEM(S3C2410_GPDCON), | ||
99 | SAVE_ITEM(S3C2410_GPDDAT), | ||
100 | SAVE_ITEM(S3C2410_GPDUP), | ||
101 | |||
102 | SAVE_ITEM(S3C2410_GPECON), | ||
103 | SAVE_ITEM(S3C2410_GPEDAT), | ||
104 | SAVE_ITEM(S3C2410_GPEUP), | ||
105 | |||
106 | SAVE_ITEM(S3C2410_GPFCON), | ||
107 | SAVE_ITEM(S3C2410_GPFDAT), | ||
108 | SAVE_ITEM(S3C2410_GPFUP), | ||
109 | |||
110 | SAVE_ITEM(S3C2410_GPGCON), | ||
111 | SAVE_ITEM(S3C2410_GPGDAT), | ||
112 | SAVE_ITEM(S3C2410_GPGUP), | ||
113 | |||
114 | SAVE_ITEM(S3C2410_GPHCON), | ||
115 | SAVE_ITEM(S3C2410_GPHDAT), | ||
116 | SAVE_ITEM(S3C2410_GPHUP), | ||
117 | |||
118 | SAVE_ITEM(S3C2410_DCLKCON), | ||
119 | }; | ||
120 | |||
121 | #ifdef CONFIG_S3C2410_PM_DEBUG | ||
122 | |||
123 | #define SAVE_UART(va) \ | ||
124 | SAVE_ITEM((va) + S3C2410_ULCON), \ | ||
125 | SAVE_ITEM((va) + S3C2410_UCON), \ | ||
126 | SAVE_ITEM((va) + S3C2410_UFCON), \ | ||
127 | SAVE_ITEM((va) + S3C2410_UMCON), \ | ||
128 | SAVE_ITEM((va) + S3C2410_UBRDIV) | ||
129 | |||
130 | static struct sleep_save uart_save[] = { | ||
131 | SAVE_UART(S3C24XX_VA_UART0), | ||
132 | SAVE_UART(S3C24XX_VA_UART1), | ||
133 | #ifndef CONFIG_CPU_S3C2400 | ||
134 | SAVE_UART(S3C24XX_VA_UART2), | ||
135 | #endif | ||
136 | }; | ||
137 | |||
138 | /* debug | ||
139 | * | ||
140 | * we send the debug to printascii() to allow it to be seen if the | ||
141 | * system never wakes up from the sleep | ||
142 | */ | ||
143 | |||
144 | extern void printascii(const char *); | ||
145 | |||
146 | void pm_dbg(const char *fmt, ...) | ||
147 | { | ||
148 | va_list va; | ||
149 | char buff[256]; | ||
150 | |||
151 | va_start(va, fmt); | ||
152 | vsprintf(buff, fmt, va); | ||
153 | va_end(va); | ||
154 | |||
155 | printascii(buff); | ||
156 | } | ||
157 | |||
158 | static void s3c2410_pm_debug_init(void) | ||
159 | { | ||
160 | unsigned long tmp = __raw_readl(S3C2410_CLKCON); | ||
161 | |||
162 | /* re-start uart clocks */ | ||
163 | tmp |= S3C2410_CLKCON_UART0; | ||
164 | tmp |= S3C2410_CLKCON_UART1; | ||
165 | tmp |= S3C2410_CLKCON_UART2; | ||
166 | |||
167 | __raw_writel(tmp, S3C2410_CLKCON); | ||
168 | udelay(10); | ||
169 | } | ||
170 | |||
171 | #define DBG(fmt...) pm_dbg(fmt) | ||
172 | #else | ||
173 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | ||
174 | |||
175 | #define s3c2410_pm_debug_init() do { } while(0) | ||
176 | |||
177 | static struct sleep_save uart_save[] = {}; | ||
178 | #endif | ||
179 | |||
180 | #if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 | ||
181 | |||
182 | /* suspend checking code... | ||
183 | * | ||
184 | * this next area does a set of crc checks over all the installed | ||
185 | * memory, so the system can verify if the resume was ok. | ||
186 | * | ||
187 | * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, | ||
188 | * increasing it will mean that the area corrupted will be less easy to spot, | ||
189 | * and reducing the size will cause the CRC save area to grow | ||
190 | */ | ||
191 | |||
192 | #define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024) | ||
193 | |||
194 | static u32 crc_size; /* size needed for the crc block */ | ||
195 | static u32 *crcs; /* allocated over suspend/resume */ | ||
196 | |||
197 | typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); | ||
198 | |||
199 | /* s3c2410_pm_run_res | ||
200 | * | ||
201 | * go thorugh the given resource list, and look for system ram | ||
202 | */ | ||
203 | |||
204 | static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) | ||
205 | { | ||
206 | while (ptr != NULL) { | ||
207 | if (ptr->child != NULL) | ||
208 | s3c2410_pm_run_res(ptr->child, fn, arg); | ||
209 | |||
210 | if ((ptr->flags & IORESOURCE_MEM) && | ||
211 | strcmp(ptr->name, "System RAM") == 0) { | ||
212 | DBG("Found system RAM at %08lx..%08lx\n", | ||
213 | ptr->start, ptr->end); | ||
214 | arg = (fn)(ptr, arg); | ||
215 | } | ||
216 | |||
217 | ptr = ptr->sibling; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg) | ||
222 | { | ||
223 | s3c2410_pm_run_res(&iomem_resource, fn, arg); | ||
224 | } | ||
225 | |||
226 | static u32 *s3c2410_pm_countram(struct resource *res, u32 *val) | ||
227 | { | ||
228 | u32 size = (u32)(res->end - res->start)+1; | ||
229 | |||
230 | size += CHECK_CHUNKSIZE-1; | ||
231 | size /= CHECK_CHUNKSIZE; | ||
232 | |||
233 | DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size); | ||
234 | |||
235 | *val += size * sizeof(u32); | ||
236 | return val; | ||
237 | } | ||
238 | |||
239 | /* s3c2410_pm_prepare_check | ||
240 | * | ||
241 | * prepare the necessary information for creating the CRCs. This | ||
242 | * must be done before the final save, as it will require memory | ||
243 | * allocating, and thus touching bits of the kernel we do not | ||
244 | * know about. | ||
245 | */ | ||
246 | |||
247 | static void s3c2410_pm_check_prepare(void) | ||
248 | { | ||
249 | crc_size = 0; | ||
250 | |||
251 | s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); | ||
252 | |||
253 | DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); | ||
254 | |||
255 | crcs = kmalloc(crc_size+4, GFP_KERNEL); | ||
256 | if (crcs == NULL) | ||
257 | printk(KERN_ERR "Cannot allocated CRC save area\n"); | ||
258 | } | ||
259 | |||
260 | static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) | ||
261 | { | ||
262 | unsigned long addr, left; | ||
263 | |||
264 | for (addr = res->start; addr < res->end; | ||
265 | addr += CHECK_CHUNKSIZE) { | ||
266 | left = res->end - addr; | ||
267 | |||
268 | if (left > CHECK_CHUNKSIZE) | ||
269 | left = CHECK_CHUNKSIZE; | ||
270 | |||
271 | *val = crc32_le(~0, phys_to_virt(addr), left); | ||
272 | val++; | ||
273 | } | ||
274 | |||
275 | return val; | ||
276 | } | ||
277 | |||
278 | /* s3c2410_pm_check_store | ||
279 | * | ||
280 | * compute the CRC values for the memory blocks before the final | ||
281 | * sleep. | ||
282 | */ | ||
283 | |||
284 | static void s3c2410_pm_check_store(void) | ||
285 | { | ||
286 | if (crcs != NULL) | ||
287 | s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs); | ||
288 | } | ||
289 | |||
290 | /* in_region | ||
291 | * | ||
292 | * return TRUE if the area defined by ptr..ptr+size contatins the | ||
293 | * what..what+whatsz | ||
294 | */ | ||
295 | |||
296 | static inline int in_region(void *ptr, int size, void *what, size_t whatsz) | ||
297 | { | ||
298 | if ((what+whatsz) < ptr) | ||
299 | return 0; | ||
300 | |||
301 | if (what > (ptr+size)) | ||
302 | return 0; | ||
303 | |||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val) | ||
308 | { | ||
309 | void *save_at = phys_to_virt(s3c2410_sleep_save_phys); | ||
310 | unsigned long addr; | ||
311 | unsigned long left; | ||
312 | void *ptr; | ||
313 | u32 calc; | ||
314 | |||
315 | for (addr = res->start; addr < res->end; | ||
316 | addr += CHECK_CHUNKSIZE) { | ||
317 | left = res->end - addr; | ||
318 | |||
319 | if (left > CHECK_CHUNKSIZE) | ||
320 | left = CHECK_CHUNKSIZE; | ||
321 | |||
322 | ptr = phys_to_virt(addr); | ||
323 | |||
324 | if (in_region(ptr, left, crcs, crc_size)) { | ||
325 | DBG("skipping %08lx, has crc block in\n", addr); | ||
326 | goto skip_check; | ||
327 | } | ||
328 | |||
329 | if (in_region(ptr, left, save_at, 32*4 )) { | ||
330 | DBG("skipping %08lx, has save block in\n", addr); | ||
331 | goto skip_check; | ||
332 | } | ||
333 | |||
334 | /* calculate and check the checksum */ | ||
335 | |||
336 | calc = crc32_le(~0, ptr, left); | ||
337 | if (calc != *val) { | ||
338 | printk(KERN_ERR PFX "Restore CRC error at " | ||
339 | "%08lx (%08x vs %08x)\n", addr, calc, *val); | ||
340 | |||
341 | DBG("Restore CRC error at %08lx (%08x vs %08x)\n", | ||
342 | addr, calc, *val); | ||
343 | } | ||
344 | |||
345 | skip_check: | ||
346 | val++; | ||
347 | } | ||
348 | |||
349 | return val; | ||
350 | } | ||
351 | |||
352 | /* s3c2410_pm_check_restore | ||
353 | * | ||
354 | * check the CRCs after the restore event and free the memory used | ||
355 | * to hold them | ||
356 | */ | ||
357 | |||
358 | static void s3c2410_pm_check_restore(void) | ||
359 | { | ||
360 | if (crcs != NULL) { | ||
361 | s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs); | ||
362 | kfree(crcs); | ||
363 | crcs = NULL; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | #else | ||
368 | |||
369 | #define s3c2410_pm_check_prepare() do { } while(0) | ||
370 | #define s3c2410_pm_check_restore() do { } while(0) | ||
371 | #define s3c2410_pm_check_store() do { } while(0) | ||
372 | #endif | ||
373 | |||
374 | /* helper functions to save and restore register state */ | ||
375 | |||
376 | void s3c2410_pm_do_save(struct sleep_save *ptr, int count) | ||
377 | { | ||
378 | for (; count > 0; count--, ptr++) { | ||
379 | ptr->val = __raw_readl(ptr->reg); | ||
380 | DBG("saved %p value %08lx\n", ptr->reg, ptr->val); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | /* s3c2410_pm_do_restore | ||
385 | * | ||
386 | * restore the system from the given list of saved registers | ||
387 | * | ||
388 | * Note, we do not use DBG() in here, as the system may not have | ||
389 | * restore the UARTs state yet | ||
390 | */ | ||
391 | |||
392 | void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) | ||
393 | { | ||
394 | for (; count > 0; count--, ptr++) { | ||
395 | printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", | ||
396 | ptr->reg, ptr->val, __raw_readl(ptr->reg)); | ||
397 | |||
398 | __raw_writel(ptr->val, ptr->reg); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* s3c2410_pm_do_restore_core | ||
403 | * | ||
404 | * similar to s3c2410_pm_do_restore_core | ||
405 | * | ||
406 | * WARNING: Do not put any debug in here that may effect memory or use | ||
407 | * peripherals, as things may be changing! | ||
408 | */ | ||
409 | |||
410 | static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) | ||
411 | { | ||
412 | for (; count > 0; count--, ptr++) { | ||
413 | __raw_writel(ptr->val, ptr->reg); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | /* s3c2410_pm_show_resume_irqs | ||
418 | * | ||
419 | * print any IRQs asserted at resume time (ie, we woke from) | ||
420 | */ | ||
421 | |||
422 | static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, | ||
423 | unsigned long mask) | ||
424 | { | ||
425 | int i; | ||
426 | |||
427 | which &= ~mask; | ||
428 | |||
429 | for (i = 0; i <= 31; i++) { | ||
430 | if ((which) & (1L<<i)) { | ||
431 | DBG("IRQ %d asserted at resume\n", start+i); | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | |||
436 | /* s3c2410_pm_check_resume_pin | ||
437 | * | ||
438 | * check to see if the pin is configured correctly for sleep mode, and | ||
439 | * make any necessary adjustments if it is not | ||
440 | */ | ||
441 | |||
442 | static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) | ||
443 | { | ||
444 | unsigned long irqstate; | ||
445 | unsigned long pinstate; | ||
446 | int irq = s3c2410_gpio_getirq(pin); | ||
447 | |||
448 | if (irqoffs < 4) | ||
449 | irqstate = s3c_irqwake_intmask & (1L<<irqoffs); | ||
450 | else | ||
451 | irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); | ||
452 | |||
453 | pinstate = s3c2410_gpio_getcfg(pin); | ||
454 | |||
455 | if (!irqstate) { | ||
456 | if (pinstate == S3C2410_GPIO_IRQ) | ||
457 | DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin); | ||
458 | } else { | ||
459 | if (pinstate == S3C2410_GPIO_IRQ) { | ||
460 | DBG("Disabling IRQ %d (pin %d)\n", irq, pin); | ||
461 | s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT); | ||
462 | } | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /* s3c2410_pm_configure_extint | ||
467 | * | ||
468 | * configure all external interrupt pins | ||
469 | */ | ||
470 | |||
471 | static void s3c2410_pm_configure_extint(void) | ||
472 | { | ||
473 | int pin; | ||
474 | |||
475 | /* for each of the external interrupts (EINT0..EINT15) we | ||
476 | * need to check wether it is an external interrupt source, | ||
477 | * and then configure it as an input if it is not | ||
478 | */ | ||
479 | |||
480 | for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) { | ||
481 | s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0); | ||
482 | } | ||
483 | |||
484 | for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) { | ||
485 | s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | void (*pm_cpu_prep)(void); | ||
490 | void (*pm_cpu_sleep)(void); | ||
491 | |||
492 | #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) | ||
493 | |||
494 | /* s3c2410_pm_enter | ||
495 | * | ||
496 | * central control for sleep/resume process | ||
497 | */ | ||
498 | |||
499 | static int s3c2410_pm_enter(suspend_state_t state) | ||
500 | { | ||
501 | unsigned long regs_save[16]; | ||
502 | |||
503 | /* ensure the debug is initialised (if enabled) */ | ||
504 | |||
505 | s3c2410_pm_debug_init(); | ||
506 | |||
507 | DBG("s3c2410_pm_enter(%d)\n", state); | ||
508 | |||
509 | if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { | ||
510 | printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | |||
514 | if (state != PM_SUSPEND_MEM) { | ||
515 | printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | |||
519 | /* check if we have anything to wake-up with... bad things seem | ||
520 | * to happen if you suspend with no wakeup (system will often | ||
521 | * require a full power-cycle) | ||
522 | */ | ||
523 | |||
524 | if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && | ||
525 | !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { | ||
526 | printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); | ||
527 | printk(KERN_ERR PFX "Aborting sleep\n"); | ||
528 | return -EINVAL; | ||
529 | } | ||
530 | |||
531 | /* prepare check area if configured */ | ||
532 | |||
533 | s3c2410_pm_check_prepare(); | ||
534 | |||
535 | /* store the physical address of the register recovery block */ | ||
536 | |||
537 | s3c2410_sleep_save_phys = virt_to_phys(regs_save); | ||
538 | |||
539 | DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys); | ||
540 | |||
541 | /* save all necessary core registers not covered by the drivers */ | ||
542 | |||
543 | s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save)); | ||
544 | s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save)); | ||
545 | s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); | ||
546 | |||
547 | /* set the irq configuration for wake */ | ||
548 | |||
549 | s3c2410_pm_configure_extint(); | ||
550 | |||
551 | DBG("sleep: irq wakeup masks: %08lx,%08lx\n", | ||
552 | s3c_irqwake_intmask, s3c_irqwake_eintmask); | ||
553 | |||
554 | __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); | ||
555 | __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); | ||
556 | |||
557 | /* ack any outstanding external interrupts before we go to sleep */ | ||
558 | |||
559 | __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); | ||
560 | __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); | ||
561 | __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); | ||
562 | |||
563 | /* call cpu specific preperation */ | ||
564 | |||
565 | pm_cpu_prep(); | ||
566 | |||
567 | /* flush cache back to ram */ | ||
568 | |||
569 | flush_cache_all(); | ||
570 | |||
571 | s3c2410_pm_check_store(); | ||
572 | |||
573 | /* send the cpu to sleep... */ | ||
574 | |||
575 | __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ | ||
576 | |||
577 | /* s3c2410_cpu_save will also act as our return point from when | ||
578 | * we resume as it saves its own register state, so use the return | ||
579 | * code to differentiate return from save and return from sleep */ | ||
580 | |||
581 | if (s3c2410_cpu_save(regs_save) == 0) { | ||
582 | flush_cache_all(); | ||
583 | pm_cpu_sleep(); | ||
584 | } | ||
585 | |||
586 | /* restore the cpu state */ | ||
587 | |||
588 | cpu_init(); | ||
589 | |||
590 | /* restore the system state */ | ||
591 | |||
592 | s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); | ||
593 | s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save)); | ||
594 | s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); | ||
595 | |||
596 | s3c2410_pm_debug_init(); | ||
597 | |||
598 | /* check what irq (if any) restored the system */ | ||
599 | |||
600 | DBG("post sleep: IRQs 0x%08x, 0x%08x\n", | ||
601 | __raw_readl(S3C2410_SRCPND), | ||
602 | __raw_readl(S3C2410_EINTPEND)); | ||
603 | |||
604 | s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), | ||
605 | s3c_irqwake_intmask); | ||
606 | |||
607 | s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), | ||
608 | s3c_irqwake_eintmask); | ||
609 | |||
610 | DBG("post sleep, preparing to return\n"); | ||
611 | |||
612 | s3c2410_pm_check_restore(); | ||
613 | |||
614 | /* ok, let's return from sleep */ | ||
615 | |||
616 | DBG("S3C2410 PM Resume (post-restore)\n"); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Called after processes are frozen, but before we shut down devices. | ||
622 | */ | ||
623 | static int s3c2410_pm_prepare(suspend_state_t state) | ||
624 | { | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | /* | ||
629 | * Called after devices are re-setup, but before processes are thawed. | ||
630 | */ | ||
631 | static int s3c2410_pm_finish(suspend_state_t state) | ||
632 | { | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | /* | ||
637 | * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. | ||
638 | */ | ||
639 | static struct pm_ops s3c2410_pm_ops = { | ||
640 | .pm_disk_mode = PM_DISK_FIRMWARE, | ||
641 | .prepare = s3c2410_pm_prepare, | ||
642 | .enter = s3c2410_pm_enter, | ||
643 | .finish = s3c2410_pm_finish, | ||
644 | }; | ||
645 | |||
646 | /* s3c2410_pm_init | ||
647 | * | ||
648 | * Attach the power management functions. This should be called | ||
649 | * from the board specific initialisation if the board supports | ||
650 | * it. | ||
651 | */ | ||
652 | |||
653 | int __init s3c2410_pm_init(void) | ||
654 | { | ||
655 | printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); | ||
656 | |||
657 | pm_set_ops(&s3c2410_pm_ops); | ||
658 | return 0; | ||
659 | } | ||
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c index ede94636a72a..a0e39d894014 100644 --- a/arch/arm/mach-s3c2410/s3c244x-irq.c +++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c244x-irq.c | 1 | /* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c |
2 | * | 2 | * |
3 | * Copyright (c) 2003,2004 Simtec Electronics | 3 | * Copyright (c) 2003,2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -35,9 +35,9 @@ | |||
35 | #include <asm/arch/regs-irq.h> | 35 | #include <asm/arch/regs-irq.h> |
36 | #include <asm/arch/regs-gpio.h> | 36 | #include <asm/arch/regs-gpio.h> |
37 | 37 | ||
38 | #include "cpu.h" | 38 | #include <asm/plat-s3c24xx/cpu.h> |
39 | #include "pm.h" | 39 | #include <asm/plat-s3c24xx/pm.h> |
40 | #include "irq.h" | 40 | #include <asm/plat-s3c24xx/irq.h> |
41 | 41 | ||
42 | /* camera irq */ | 42 | /* camera irq */ |
43 | 43 | ||
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c index 23c7494ad10d..87aace4c8f8c 100644 --- a/arch/arm/mach-s3c2410/s3c244x.c +++ b/arch/arm/plat-s3c24xx/s3c244x.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/s3c244x.c | 1 | /* linux/arch/arm/plat-s3c24xx/s3c244x.c |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2006 Simtec Electronics | 3 | * Copyright (c) 2004-2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
@@ -35,13 +35,13 @@ | |||
35 | #include <asm/arch/regs-gpioj.h> | 35 | #include <asm/arch/regs-gpioj.h> |
36 | #include <asm/arch/regs-dsc.h> | 36 | #include <asm/arch/regs-dsc.h> |
37 | 37 | ||
38 | #include "s3c2410.h" | 38 | #include <asm/plat-s3c24xx/s3c2410.h> |
39 | #include "s3c2440.h" | 39 | #include <asm/plat-s3c24xx/s3c2440.h> |
40 | #include "s3c244x.h" | 40 | #include "s3c244x.h" |
41 | #include "clock.h" | 41 | #include <asm/plat-s3c24xx/clock.h> |
42 | #include "devs.h" | 42 | #include <asm/plat-s3c24xx/devs.h> |
43 | #include "cpu.h" | 43 | #include <asm/plat-s3c24xx/cpu.h> |
44 | #include "pm.h" | 44 | #include <asm/plat-s3c24xx/pm.h> |
45 | 45 | ||
46 | static struct map_desc s3c244x_iodesc[] __initdata = { | 46 | static struct map_desc s3c244x_iodesc[] __initdata = { |
47 | IODESC_ENT(CLKPWR), | 47 | IODESC_ENT(CLKPWR), |
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h index 1488c1eb37e6..f8ed17676a35 100644 --- a/arch/arm/mach-s3c2410/s3c244x.h +++ b/arch/arm/plat-s3c24xx/s3c244x.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c244x.h | 1 | /* linux/arch/arm/plat-s3c24xx/s3c244x.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S new file mode 100644 index 000000000000..2018c2e1dcc5 --- /dev/null +++ b/arch/arm/plat-s3c24xx/sleep.S | |||
@@ -0,0 +1,159 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/sleep.S | ||
2 | * | ||
3 | * Copyright (c) 2004 Simtec Electronics | ||
4 | * Ben Dooks <ben@simtec.co.uk> | ||
5 | * | ||
6 | * S3C2410 Power Manager (Suspend-To-RAM) support | ||
7 | * | ||
8 | * Based on PXA/SA1100 sleep code by: | ||
9 | * Nicolas Pitre, (c) 2002 Monta Vista Software Inc | ||
10 | * Cliff Brake, (c) 2001 | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/linkage.h> | ||
28 | #include <asm/assembler.h> | ||
29 | #include <asm/hardware.h> | ||
30 | #include <asm/arch/map.h> | ||
31 | |||
32 | #include <asm/arch/regs-gpio.h> | ||
33 | #include <asm/arch/regs-clock.h> | ||
34 | #include <asm/arch/regs-mem.h> | ||
35 | #include <asm/arch/regs-serial.h> | ||
36 | |||
37 | /* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not | ||
38 | * reset the UART configuration, only enable if you really need this! | ||
39 | */ | ||
40 | //#define CONFIG_DEBUG_RESUME | ||
41 | |||
42 | .text | ||
43 | |||
44 | /* s3c2410_cpu_save | ||
45 | * | ||
46 | * save enough of the CPU state to allow us to re-start | ||
47 | * pm.c code. as we store items like the sp/lr, we will | ||
48 | * end up returning from this function when the cpu resumes | ||
49 | * so the return value is set to mark this. | ||
50 | * | ||
51 | * This arangement means we avoid having to flush the cache | ||
52 | * from this code. | ||
53 | * | ||
54 | * entry: | ||
55 | * r0 = pointer to save block | ||
56 | * | ||
57 | * exit: | ||
58 | * r0 = 0 => we stored everything | ||
59 | * 1 => resumed from sleep | ||
60 | */ | ||
61 | |||
62 | ENTRY(s3c2410_cpu_save) | ||
63 | stmfd sp!, { r4 - r12, lr } | ||
64 | |||
65 | @@ store co-processor registers | ||
66 | |||
67 | mrc p15, 0, r4, c15, c1, 0 @ CP access register | ||
68 | mrc p15, 0, r5, c13, c0, 0 @ PID | ||
69 | mrc p15, 0, r6, c3, c0, 0 @ Domain ID | ||
70 | mrc p15, 0, r7, c2, c0, 0 @ translation table base address | ||
71 | mrc p15, 0, r8, c1, c0, 0 @ control register | ||
72 | |||
73 | stmia r0, { r4 - r13 } | ||
74 | |||
75 | mov r0, #0 | ||
76 | ldmfd sp, { r4 - r12, pc } | ||
77 | |||
78 | @@ return to the caller, after having the MMU | ||
79 | @@ turned on, this restores the last bits from the | ||
80 | @@ stack | ||
81 | resume_with_mmu: | ||
82 | mov r0, #1 | ||
83 | ldmfd sp!, { r4 - r12, pc } | ||
84 | |||
85 | .ltorg | ||
86 | |||
87 | @@ the next bits sit in the .data segment, even though they | ||
88 | @@ happen to be code... the s3c2410_sleep_save_phys needs to be | ||
89 | @@ accessed by the resume code before it can restore the MMU. | ||
90 | @@ This means that the variable has to be close enough for the | ||
91 | @@ code to read it... since the .text segment needs to be RO, | ||
92 | @@ the data segment can be the only place to put this code. | ||
93 | |||
94 | .data | ||
95 | |||
96 | .global s3c2410_sleep_save_phys | ||
97 | s3c2410_sleep_save_phys: | ||
98 | .word 0 | ||
99 | |||
100 | /* s3c2410_cpu_resume | ||
101 | * | ||
102 | * resume code entry for bootloader to call | ||
103 | * | ||
104 | * we must put this code here in the data segment as we have no | ||
105 | * other way of restoring the stack pointer after sleep, and we | ||
106 | * must not write to the code segment (code is read-only) | ||
107 | */ | ||
108 | |||
109 | ENTRY(s3c2410_cpu_resume) | ||
110 | mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE | ||
111 | msr cpsr_c, r0 | ||
112 | |||
113 | @@ load UART to allow us to print the two characters for | ||
114 | @@ resume debug | ||
115 | |||
116 | mov r2, #S3C24XX_PA_UART & 0xff000000 | ||
117 | orr r2, r2, #S3C24XX_PA_UART & 0xff000 | ||
118 | |||
119 | #if 0 | ||
120 | /* SMDK2440 LED set */ | ||
121 | mov r14, #S3C24XX_PA_GPIO | ||
122 | ldr r12, [ r14, #0x54 ] | ||
123 | bic r12, r12, #3<<4 | ||
124 | orr r12, r12, #1<<7 | ||
125 | str r12, [ r14, #0x54 ] | ||
126 | #endif | ||
127 | |||
128 | #ifdef CONFIG_DEBUG_RESUME | ||
129 | mov r3, #'L' | ||
130 | strb r3, [ r2, #S3C2410_UTXH ] | ||
131 | 1001: | ||
132 | ldrb r14, [ r3, #S3C2410_UTRSTAT ] | ||
133 | tst r14, #S3C2410_UTRSTAT_TXE | ||
134 | beq 1001b | ||
135 | #endif /* CONFIG_DEBUG_RESUME */ | ||
136 | |||
137 | mov r1, #0 | ||
138 | mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs | ||
139 | mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches | ||
140 | |||
141 | ldr r0, s3c2410_sleep_save_phys @ address of restore block | ||
142 | ldmia r0, { r4 - r13 } | ||
143 | |||
144 | mcr p15, 0, r4, c15, c1, 0 @ CP access register | ||
145 | mcr p15, 0, r5, c13, c0, 0 @ PID | ||
146 | mcr p15, 0, r6, c3, c0, 0 @ Domain ID | ||
147 | mcr p15, 0, r7, c2, c0, 0 @ translation table base | ||
148 | |||
149 | #ifdef CONFIG_DEBUG_RESUME | ||
150 | mov r3, #'R' | ||
151 | strb r3, [ r2, #S3C2410_UTXH ] | ||
152 | #endif | ||
153 | |||
154 | ldr r2, =resume_with_mmu | ||
155 | mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc | ||
156 | nop @ second-to-last before mmu | ||
157 | mov pc, r2 @ go back to virtual address | ||
158 | |||
159 | .ltorg | ||
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/plat-s3c24xx/time.c index 9910bf0f2cea..c523d1c9cce5 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/plat-s3c24xx/time.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/time.c | 1 | /* linux/arch/arm/plat-s3c24xx/time.c |
2 | * | 2 | * |
3 | * Copyright (C) 2003-2005 Simtec Electronics | 3 | * Copyright (C) 2003-2005 Simtec Electronics |
4 | * Ben Dooks, <ben@simtec.co.uk> | 4 | * Ben Dooks, <ben@simtec.co.uk> |
@@ -37,8 +37,8 @@ | |||
37 | #include <asm/arch/regs-irq.h> | 37 | #include <asm/arch/regs-irq.h> |
38 | #include <asm/mach/time.h> | 38 | #include <asm/mach/time.h> |
39 | 39 | ||
40 | #include "clock.h" | 40 | #include <asm/plat-s3c24xx/clock.h> |
41 | #include "cpu.h" | 41 | #include <asm/plat-s3c24xx/cpu.h> |
42 | 42 | ||
43 | static unsigned long timer_startval; | 43 | static unsigned long timer_startval; |
44 | static unsigned long timer_usec_ticks; | 44 | static unsigned long timer_usec_ticks; |
diff --git a/arch/arm/mach-s3c2410/clock.h b/include/asm-arm/plat-s3c24xx/clock.h index 7f0ea03e1d49..f6135dbb9fa9 100644 --- a/arch/arm/mach-s3c2410/clock.h +++ b/include/asm-arm/plat-s3c24xx/clock.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* linux/include/asm-arm/plat-s3c24xx/clock.h |
2 | * linux/arch/arm/mach-s3c2410/clock.h | 2 | * linux/arch/arm/mach-s3c2410/clock.h |
3 | * | 3 | * |
4 | * Copyright (c) 2004-2005 Simtec Electronics | 4 | * Copyright (c) 2004-2005 Simtec Electronics |
diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/include/asm-arm/plat-s3c24xx/common-smdk.h index 0e3a3be330a3..58d9094c935c 100644 --- a/arch/arm/mach-s3c2410/common-smdk.h +++ b/include/asm-arm/plat-s3c24xx/common-smdk.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/common-smdk.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/common-smdk.h |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h index be42e4032a6d..8181b22532bd 100644 --- a/arch/arm/mach-s3c2410/cpu.h +++ b/include/asm-arm/plat-s3c24xx/cpu.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/cpu.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/cpu.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/devs.h b/include/asm-arm/plat-s3c24xx/devs.h index 14fb0bade716..dddf485fc067 100644 --- a/arch/arm/mach-s3c2410/devs.h +++ b/include/asm-arm/plat-s3c24xx/devs.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/devs.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/devs.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/dma.h b/include/asm-arm/plat-s3c24xx/dma.h index 0ebfe0aab80b..421b567fa019 100644 --- a/arch/arm/mach-s3c2410/dma.h +++ b/include/asm-arm/plat-s3c24xx/dma.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/dma.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/dma.h |
2 | * | 2 | * |
3 | * Copyright (C) 2006 Simtec Electronics | 3 | * Copyright (C) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/irq.h b/include/asm-arm/plat-s3c24xx/irq.h index e5913da3b919..8af6d9579b31 100644 --- a/arch/arm/mach-s3c2410/irq.h +++ b/include/asm-arm/plat-s3c24xx/irq.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/irq.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/irq.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/pm.h b/include/asm-arm/plat-s3c24xx/pm.h index ffe197a119fb..cc623667e48a 100644 --- a/arch/arm/mach-s3c2410/pm.h +++ b/include/asm-arm/plat-s3c24xx/pm.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* linux/arch/arm/mach-s3c2410/pm.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/pm.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Written by Ben Dooks, <ben@simtec.co.uk> | 4 | * Written by Ben Dooks, <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/s3c2400.h b/include/asm-arm/plat-s3c24xx/s3c2400.h index 8b2394e1ed40..3a5a16821af8 100644 --- a/arch/arm/mach-s3c2410/s3c2400.h +++ b/include/asm-arm/plat-s3c24xx/s3c2400.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c2400.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/s3c2400.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/include/asm-arm/plat-s3c24xx/s3c2410.h index fbed084f26d0..36de0b835873 100644 --- a/arch/arm/mach-s3c2410/s3c2410.h +++ b/include/asm-arm/plat-s3c24xx/s3c2410.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c2410.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/s3c2410.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics | 3 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/include/asm-arm/plat-s3c24xx/s3c2412.h index c6e56032a6e7..3ec97685e781 100644 --- a/arch/arm/mach-s3c2410/s3c2412.h +++ b/include/asm-arm/plat-s3c24xx/s3c2412.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c2412.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/s3c2412.h |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/include/asm-arm/plat-s3c24xx/s3c2440.h index dcd316076c59..107853bf9481 100644 --- a/arch/arm/mach-s3c2410/s3c2440.h +++ b/include/asm-arm/plat-s3c24xx/s3c2440.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c2440.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/s3c2440.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004-2005 Simtec Electronics | 3 | * Copyright (c) 2004-2005 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/include/asm-arm/plat-s3c24xx/s3c2442.h index 0ae37d24866c..451a23a2092a 100644 --- a/arch/arm/mach-s3c2410/s3c2442.h +++ b/include/asm-arm/plat-s3c24xx/s3c2442.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* arch/arm/mach-s3c2410/s3c2442.h | 1 | /* linux/include/asm-arm/plat-s3c24xx/s3c2442.h |
2 | * | 2 | * |
3 | * Copyright (c) 2006 Simtec Electronics | 3 | * Copyright (c) 2006 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |