aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 13:11:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-17 13:11:25 -0400
commit7b7adc4a016a1decb806eb71ecab98721fa7f146 (patch)
tree0a6f9a6e5659faa94604fbc575382a18f143c657
parent31598e8713ef501c8f6aad2e2ec8a9457e8877c1 (diff)
parent289d6b0e287e0acd85f3e6b7ea6c2cb5c234909a (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32: (40 commits) unicore32: rewrite arch-specific tlb.h to use asm-generic version unicore32: modify io_p2v and io_v2p macros, and adjust PKUNITY_mmio_BASEs unicore32: replace unicore32-specific iomap functions with generic lib implementation unicore32 machine related: add frame buffer driver for pkunity-v3 soc unicore32 machine related files: add i2c bus drivers for pkunity-v3 soc unicore32 io: redefine __REG(x) and re-use readl/writel funcs unicore32 i8042 upgrade and bugfix: adjust resource request region type unicore32 upgrade to v2.6.38-rc5: add one more paramter for pte_alloc_map call unicore32 i8042: adjust io funcs of i8042-unicore32io.h unicore32: rename PKUNITY_IOSPACE_BASE to PKUNITY_MMIO_BASE unicore32: modify function names and parameters for irq_chips unicore32: remove unused lines in arch/unicore32/include/asm/irq.h unicore32 time.c: change calculate method for clock_event_device unicore32: ADD MAINTAINER for unicore32 architecture unicore32 machine related files: ps2 driver unicore32 machine related files: pci bus handling unicore32 machine related files: hardware registers unicore32 machine related files: core files unicore32 additional architecture files: boot process unicore32 additional architecture files: low-level lib: misc ... Acked-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--MAINTAINERS16
-rw-r--r--arch/unicore32/.gitignore21
-rw-r--r--arch/unicore32/Kconfig275
-rw-r--r--arch/unicore32/Kconfig.debug68
-rw-r--r--arch/unicore32/Makefile95
-rw-r--r--arch/unicore32/boot/Makefile47
-rw-r--r--arch/unicore32/boot/compressed/Makefile68
-rw-r--r--arch/unicore32/boot/compressed/head.S204
-rw-r--r--arch/unicore32/boot/compressed/misc.c126
-rw-r--r--arch/unicore32/boot/compressed/piggy.S.in6
-rw-r--r--arch/unicore32/boot/compressed/vmlinux.lds.in61
-rw-r--r--arch/unicore32/configs/debug_defconfig215
-rw-r--r--arch/unicore32/include/asm/Kbuild2
-rw-r--r--arch/unicore32/include/asm/assembler.h131
-rw-r--r--arch/unicore32/include/asm/bitops.h47
-rw-r--r--arch/unicore32/include/asm/byteorder.h24
-rw-r--r--arch/unicore32/include/asm/cache.h27
-rw-r--r--arch/unicore32/include/asm/cacheflush.h211
-rw-r--r--arch/unicore32/include/asm/checksum.h41
-rw-r--r--arch/unicore32/include/asm/cpu-single.h45
-rw-r--r--arch/unicore32/include/asm/cputype.h33
-rw-r--r--arch/unicore32/include/asm/delay.h52
-rw-r--r--arch/unicore32/include/asm/dma-mapping.h124
-rw-r--r--arch/unicore32/include/asm/dma.h23
-rw-r--r--arch/unicore32/include/asm/elf.h94
-rw-r--r--arch/unicore32/include/asm/fpstate.h26
-rw-r--r--arch/unicore32/include/asm/fpu-ucf64.h53
-rw-r--r--arch/unicore32/include/asm/futex.h143
-rw-r--r--arch/unicore32/include/asm/gpio.h104
-rw-r--r--arch/unicore32/include/asm/hwcap.h32
-rw-r--r--arch/unicore32/include/asm/io.h55
-rw-r--r--arch/unicore32/include/asm/irq.h105
-rw-r--r--arch/unicore32/include/asm/irqflags.h53
-rw-r--r--arch/unicore32/include/asm/linkage.h22
-rw-r--r--arch/unicore32/include/asm/memblock.h46
-rw-r--r--arch/unicore32/include/asm/memory.h123
-rw-r--r--arch/unicore32/include/asm/mmu.h17
-rw-r--r--arch/unicore32/include/asm/mmu_context.h87
-rw-r--r--arch/unicore32/include/asm/mutex.h20
-rw-r--r--arch/unicore32/include/asm/page.h80
-rw-r--r--arch/unicore32/include/asm/pci.h46
-rw-r--r--arch/unicore32/include/asm/pgalloc.h110
-rw-r--r--arch/unicore32/include/asm/pgtable-hwdef.h55
-rw-r--r--arch/unicore32/include/asm/pgtable.h317
-rw-r--r--arch/unicore32/include/asm/processor.h92
-rw-r--r--arch/unicore32/include/asm/ptrace.h133
-rw-r--r--arch/unicore32/include/asm/sigcontext.h29
-rw-r--r--arch/unicore32/include/asm/stacktrace.h31
-rw-r--r--arch/unicore32/include/asm/string.h38
-rw-r--r--arch/unicore32/include/asm/suspend.h30
-rw-r--r--arch/unicore32/include/asm/system.h161
-rw-r--r--arch/unicore32/include/asm/thread_info.h154
-rw-r--r--arch/unicore32/include/asm/timex.h34
-rw-r--r--arch/unicore32/include/asm/tlb.h28
-rw-r--r--arch/unicore32/include/asm/tlbflush.h195
-rw-r--r--arch/unicore32/include/asm/traps.h21
-rw-r--r--arch/unicore32/include/asm/uaccess.h47
-rw-r--r--arch/unicore32/include/asm/unistd.h18
-rw-r--r--arch/unicore32/include/mach/PKUnity.h108
-rw-r--r--arch/unicore32/include/mach/bitfield.h24
-rw-r--r--arch/unicore32/include/mach/dma.h48
-rw-r--r--arch/unicore32/include/mach/hardware.h38
-rw-r--r--arch/unicore32/include/mach/map.h20
-rw-r--r--arch/unicore32/include/mach/memory.h58
-rw-r--r--arch/unicore32/include/mach/ocd.h36
-rw-r--r--arch/unicore32/include/mach/pm.h43
-rw-r--r--arch/unicore32/include/mach/regs-ac97.h32
-rw-r--r--arch/unicore32/include/mach/regs-dmac.h81
-rw-r--r--arch/unicore32/include/mach/regs-gpio.h70
-rw-r--r--arch/unicore32/include/mach/regs-i2c.h63
-rw-r--r--arch/unicore32/include/mach/regs-intc.h28
-rw-r--r--arch/unicore32/include/mach/regs-nand.h79
-rw-r--r--arch/unicore32/include/mach/regs-ost.h92
-rw-r--r--arch/unicore32/include/mach/regs-pci.h94
-rw-r--r--arch/unicore32/include/mach/regs-pm.h126
-rw-r--r--arch/unicore32/include/mach/regs-ps2.h20
-rw-r--r--arch/unicore32/include/mach/regs-resetc.h34
-rw-r--r--arch/unicore32/include/mach/regs-rtc.h37
-rw-r--r--arch/unicore32/include/mach/regs-sdc.h156
-rw-r--r--arch/unicore32/include/mach/regs-spi.h98
-rw-r--r--arch/unicore32/include/mach/regs-uart.h3
-rw-r--r--arch/unicore32/include/mach/regs-umal.h229
-rw-r--r--arch/unicore32/include/mach/regs-unigfx.h200
-rw-r--r--arch/unicore32/include/mach/uncompress.h34
-rw-r--r--arch/unicore32/kernel/Makefile33
-rw-r--r--arch/unicore32/kernel/asm-offsets.c112
-rw-r--r--arch/unicore32/kernel/clock.c390
-rw-r--r--arch/unicore32/kernel/cpu-ucv2.c93
-rw-r--r--arch/unicore32/kernel/debug-macro.S89
-rw-r--r--arch/unicore32/kernel/debug.S85
-rw-r--r--arch/unicore32/kernel/dma.c183
-rw-r--r--arch/unicore32/kernel/early_printk.c59
-rw-r--r--arch/unicore32/kernel/elf.c38
-rw-r--r--arch/unicore32/kernel/entry.S824
-rw-r--r--arch/unicore32/kernel/fpu-ucf64.c126
-rw-r--r--arch/unicore32/kernel/gpio.c122
-rw-r--r--arch/unicore32/kernel/head.S252
-rw-r--r--arch/unicore32/kernel/hibernate.c160
-rw-r--r--arch/unicore32/kernel/hibernate_asm.S117
-rw-r--r--arch/unicore32/kernel/init_task.c44
-rw-r--r--arch/unicore32/kernel/irq.c426
-rw-r--r--arch/unicore32/kernel/ksyms.c99
-rw-r--r--arch/unicore32/kernel/ksyms.h15
-rw-r--r--arch/unicore32/kernel/module.c152
-rw-r--r--arch/unicore32/kernel/pci.c404
-rw-r--r--arch/unicore32/kernel/pm.c123
-rw-r--r--arch/unicore32/kernel/process.c389
-rw-r--r--arch/unicore32/kernel/ptrace.c149
-rw-r--r--arch/unicore32/kernel/puv3-core.c285
-rw-r--r--arch/unicore32/kernel/puv3-nb0916.c145
-rw-r--r--arch/unicore32/kernel/pwm.c263
-rw-r--r--arch/unicore32/kernel/rtc.c380
-rw-r--r--arch/unicore32/kernel/setup.c360
-rw-r--r--arch/unicore32/kernel/setup.h30
-rw-r--r--arch/unicore32/kernel/signal.c494
-rw-r--r--arch/unicore32/kernel/sleep.S202
-rw-r--r--arch/unicore32/kernel/stacktrace.c131
-rw-r--r--arch/unicore32/kernel/sys.c126
-rw-r--r--arch/unicore32/kernel/time.c143
-rw-r--r--arch/unicore32/kernel/traps.c333
-rw-r--r--arch/unicore32/kernel/vmlinux.lds.S61
-rw-r--r--arch/unicore32/lib/Makefile27
-rw-r--r--arch/unicore32/lib/backtrace.S163
-rw-r--r--arch/unicore32/lib/clear_user.S57
-rw-r--r--arch/unicore32/lib/copy_from_user.S108
-rw-r--r--arch/unicore32/lib/copy_page.S39
-rw-r--r--arch/unicore32/lib/copy_template.S214
-rw-r--r--arch/unicore32/lib/copy_to_user.S96
-rw-r--r--arch/unicore32/lib/delay.S51
-rw-r--r--arch/unicore32/lib/findbit.S98
-rw-r--r--arch/unicore32/lib/strncpy_from_user.S45
-rw-r--r--arch/unicore32/lib/strnlen_user.S42
-rw-r--r--arch/unicore32/mm/Kconfig50
-rw-r--r--arch/unicore32/mm/Makefile15
-rw-r--r--arch/unicore32/mm/alignment.c523
-rw-r--r--arch/unicore32/mm/cache-ucv2.S212
-rw-r--r--arch/unicore32/mm/dma-swiotlb.c34
-rw-r--r--arch/unicore32/mm/extable.c24
-rw-r--r--arch/unicore32/mm/fault.c479
-rw-r--r--arch/unicore32/mm/flush.c98
-rw-r--r--arch/unicore32/mm/init.c517
-rw-r--r--arch/unicore32/mm/ioremap.c261
-rw-r--r--arch/unicore32/mm/mm.h39
-rw-r--r--arch/unicore32/mm/mmu.c533
-rw-r--r--arch/unicore32/mm/pgd.c102
-rw-r--r--arch/unicore32/mm/proc-macros.S145
-rw-r--r--arch/unicore32/mm/proc-syms.c23
-rw-r--r--arch/unicore32/mm/proc-ucv2.S134
-rw-r--r--arch/unicore32/mm/tlb-ucv2.S89
-rw-r--r--drivers/i2c/busses/Kconfig11
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-puv3.c306
-rw-r--r--drivers/input/serio/i8042-unicore32io.h73
-rw-r--r--drivers/input/serio/i8042.h2
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/video/Kconfig11
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/fb-puv3.c846
-rw-r--r--include/asm-generic/ftrace.h16
-rw-r--r--include/asm-generic/io.h33
-rw-r--r--include/asm-generic/sizes.h47
-rw-r--r--include/asm-generic/uaccess.h8
-rw-r--r--include/linux/fb.h2
163 files changed, 19408 insertions, 17 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index caec208de1a..c07b1d7bb02 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4907,6 +4907,15 @@ S: Maintained
4907F: drivers/block/pktcdvd.c 4907F: drivers/block/pktcdvd.c
4908F: include/linux/pktcdvd.h 4908F: include/linux/pktcdvd.h
4909 4909
4910PKUNITY SOC DRIVERS
4911M: Guan Xuetao <gxt@mprc.pku.edu.cn>
4912W: http://mprc.pku.edu.cn/~guanxuetao/linux
4913S: Maintained
4914T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git
4915F: drivers/input/serio/i8042-unicore32io.h
4916F: drivers/i2c/busses/i2c-puv3.c
4917F: drivers/video/fb-puv3.c
4918
4910PMC SIERRA MaxRAID DRIVER 4919PMC SIERRA MaxRAID DRIVER
4911M: Anil Ravindranath <anil_ravindranath@pmc-sierra.com> 4920M: Anil Ravindranath <anil_ravindranath@pmc-sierra.com>
4912L: linux-scsi@vger.kernel.org 4921L: linux-scsi@vger.kernel.org
@@ -6270,6 +6279,13 @@ F: drivers/uwb/
6270F: include/linux/uwb.h 6279F: include/linux/uwb.h
6271F: include/linux/uwb/ 6280F: include/linux/uwb/
6272 6281
6282UNICORE32 ARCHITECTURE:
6283M: Guan Xuetao <gxt@mprc.pku.edu.cn>
6284W: http://mprc.pku.edu.cn/~guanxuetao/linux
6285S: Maintained
6286T: git git://git.kernel.org/pub/scm/linux/kernel/git/epip/linux-2.6-unicore32.git
6287F: arch/unicore32/
6288
6273UNIFDEF 6289UNIFDEF
6274M: Tony Finch <dot@dotat.at> 6290M: Tony Finch <dot@dotat.at>
6275W: http://dotat.at/prog/unifdef 6291W: http://dotat.at/prog/unifdef
diff --git a/arch/unicore32/.gitignore b/arch/unicore32/.gitignore
new file mode 100644
index 00000000000..947e99c2a95
--- /dev/null
+++ b/arch/unicore32/.gitignore
@@ -0,0 +1,21 @@
1#
2# Generated include files
3#
4include/generated
5#
6# Generated ld script file
7#
8kernel/vmlinux.lds
9#
10# Generated images in boot
11#
12boot/Image
13boot/zImage
14boot/uImage
15#
16# Generated files in boot/compressed
17#
18boot/compressed/piggy.S
19boot/compressed/piggy.gzip
20boot/compressed/vmlinux
21boot/compressed/vmlinux.lds
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
new file mode 100644
index 00000000000..4a36db45fb3
--- /dev/null
+++ b/arch/unicore32/Kconfig
@@ -0,0 +1,275 @@
1config UNICORE32
2 def_bool y
3 select HAVE_MEMBLOCK
4 select HAVE_GENERIC_DMA_COHERENT
5 select HAVE_GENERIC_HARDIRQS
6 select HAVE_DMA_ATTRS
7 select HAVE_KERNEL_GZIP
8 select HAVE_KERNEL_BZIP2
9 select HAVE_KERNEL_LZO
10 select HAVE_KERNEL_LZMA
11 select GENERIC_FIND_FIRST_BIT
12 select GENERIC_IRQ_PROBE
13 select GENERIC_HARDIRQS_NO_DEPRECATED
14 select ARCH_WANT_FRAME_POINTERS
15 help
16 UniCore-32 is 32-bit Instruction Set Architecture,
17 including a series of low-power-consumption RISC chip
18 designs licensed by PKUnity Ltd.
19 Please see web page at <http://www.pkunity.com/>.
20
21config HAVE_PWM
22 bool
23
24config GENERIC_GPIO
25 def_bool y
26
27config GENERIC_CLOCKEVENTS
28 bool
29
30config GENERIC_CSUM
31 def_bool y
32
33config GENERIC_IOMAP
34 def_bool y
35
36config NO_IOPORT
37 bool
38
39config STACKTRACE_SUPPORT
40 def_bool y
41
42config HAVE_LATENCYTOP_SUPPORT
43 def_bool y
44
45config LOCKDEP_SUPPORT
46 def_bool y
47
48config RWSEM_GENERIC_SPINLOCK
49 def_bool y
50
51config RWSEM_XCHGADD_ALGORITHM
52 bool
53
54config ARCH_HAS_ILOG2_U32
55 bool
56
57config ARCH_HAS_ILOG2_U64
58 bool
59
60config ARCH_HAS_CPUFREQ
61 bool
62
63config GENERIC_HWEIGHT
64 def_bool y
65
66config GENERIC_CALIBRATE_DELAY
67 def_bool y
68
69config ARCH_MAY_HAVE_PC_FDC
70 bool
71
72config NEED_DMA_MAP_STATE
73 def_bool y
74
75source "init/Kconfig"
76
77source "kernel/Kconfig.freezer"
78
79menu "System Type"
80
81config MMU
82 def_bool y
83
84config ARCH_FPGA
85 bool
86
87config ARCH_PUV3
88 def_bool y
89 select CPU_UCV2
90 select GENERIC_CLOCKEVENTS
91 select HAVE_CLK
92 select ARCH_REQUIRE_GPIOLIB
93 select ARCH_HAS_CPUFREQ
94
95# CONFIGs for ARCH_PUV3
96
97if ARCH_PUV3
98
99choice
100 prompt "Board Selection"
101 default PUV3_DB0913
102
103config PUV3_FPGA_DLX200
104 select ARCH_FPGA
105 bool "FPGA board"
106
107config PUV3_DB0913
108 bool "DEBUG board (0913)"
109
110config PUV3_NB0916
111 bool "NetBook board (0916)"
112 select HAVE_PWM
113
114config PUV3_SMW0919
115 bool "Security Mini-Workstation board (0919)"
116
117endchoice
118
119config PUV3_PM
120 def_bool y if !ARCH_FPGA
121
122endif
123
124source "arch/unicore32/mm/Kconfig"
125
126comment "Floating poing support"
127
128config UNICORE_FPU_F64
129 def_bool y if !ARCH_FPGA
130
131endmenu
132
133menu "Bus support"
134
135config PCI
136 bool "PCI Support"
137 help
138 Find out whether you have a PCI motherboard. PCI is the name of a
139 bus system, i.e. the way the CPU talks to the other stuff inside
140 your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
141 VESA. If you have PCI, say Y, otherwise N.
142
143source "drivers/pci/Kconfig"
144
145source "drivers/pcmcia/Kconfig"
146
147endmenu
148
149menu "Kernel Features"
150
151source "kernel/time/Kconfig"
152
153source "kernel/Kconfig.preempt"
154
155source "kernel/Kconfig.hz"
156
157source "mm/Kconfig"
158
159config LEDS
160 def_bool y
161 depends on GENERIC_GPIO
162
163config ALIGNMENT_TRAP
164 def_bool y
165 help
166 Unicore processors can not fetch/store information which is not
167 naturally aligned on the bus, i.e., a 4 byte fetch must start at an
168 address divisible by 4. On 32-bit Unicore processors, these non-aligned
169 fetch/store instructions will be emulated in software if you say
170 here, which has a severe performance impact. This is necessary for
171 correct operation of some network protocols. With an IP-only
172 configuration it is safe to say N, otherwise say Y.
173
174endmenu
175
176menu "Boot options"
177
178config CMDLINE
179 string "Default kernel command string"
180 default ""
181
182config CMDLINE_FORCE
183 bool "Always use the default kernel command string"
184 depends on CMDLINE != ""
185 help
186 Always use the default kernel command string, even if the boot
187 loader passes other arguments to the kernel.
188 This is useful if you cannot or don't want to change the
189 command-line options your boot loader passes to the kernel.
190
191 If unsure, say N.
192
193endmenu
194
195menu "Userspace binary formats"
196
197source "fs/Kconfig.binfmt"
198
199endmenu
200
201menu "Power management options"
202
203source "kernel/power/Kconfig"
204
205if ARCH_HAS_CPUFREQ
206source "drivers/cpufreq/Kconfig"
207endif
208
209config ARCH_SUSPEND_POSSIBLE
210 def_bool y if !ARCH_FPGA
211
212config ARCH_HIBERNATION_POSSIBLE
213 def_bool y if !ARCH_FPGA
214
215endmenu
216
217source "net/Kconfig"
218
219if ARCH_PUV3
220
221config PUV3_GPIO
222 bool
223 depends on !ARCH_FPGA
224 select GENERIC_GPIO
225 select GPIO_SYSFS if EXPERIMENTAL
226 default y
227
228config PUV3_PWM
229 tristate
230 default BACKLIGHT_PWM
231 help
232 Enable support for NB0916 PWM controllers
233
234config PUV3_RTC
235 tristate "PKUnity v3 RTC Support"
236 depends on !ARCH_FPGA
237
238if PUV3_NB0916
239
240menu "PKUnity NetBook-0916 Features"
241
242config I2C_BATTERY_BQ27200
243 tristate "I2C Battery BQ27200 Support"
244 select PUV3_I2C
245 select POWER_SUPPLY
246 select BATTERY_BQ27x00
247
248config I2C_EEPROM_AT24
249 tristate "I2C EEPROMs AT24 support"
250 select PUV3_I2C
251 select MISC_DEVICES
252 select EEPROM_AT24
253
254config LCD_BACKLIGHT
255 tristate "LCD Backlight support"
256 select BACKLIGHT_LCD_SUPPORT
257 select BACKLIGHT_PWM
258
259endmenu
260
261endif
262
263endif
264
265source "drivers/Kconfig"
266
267source "fs/Kconfig"
268
269source "arch/unicore32/Kconfig.debug"
270
271source "security/Kconfig"
272
273source "crypto/Kconfig"
274
275source "lib/Kconfig"
diff --git a/arch/unicore32/Kconfig.debug b/arch/unicore32/Kconfig.debug
new file mode 100644
index 00000000000..3140151ede4
--- /dev/null
+++ b/arch/unicore32/Kconfig.debug
@@ -0,0 +1,68 @@
1menu "Kernel hacking"
2
3source "lib/Kconfig.debug"
4
5config STRICT_DEVMEM
6 bool "Filter access to /dev/mem"
7 depends on MMU
8 ---help---
9 If this option is disabled, you allow userspace (root) access to all
10 of memory, including kernel and userspace memory. Accidental
11 access to this is obviously disastrous, but specific access can
12 be used by people debugging the kernel.
13
14 If this option is switched on, the /dev/mem file only allows
15 userspace access to memory mapped peripherals.
16
17 If in doubt, say Y.
18
19config EARLY_PRINTK
20 def_bool DEBUG_OCD
21 help
22 Write kernel log output directly into the ocd or to a serial port.
23
24 This is useful for kernel debugging when your machine crashes very
25 early before the console code is initialized. For normal operation
26 it is not recommended because it looks ugly and doesn't cooperate
27 with klogd/syslogd or the X server. You should normally N here,
28 unless you want to debug such a crash.
29
30config DEBUG_STACK_USAGE
31 bool "Enable stack utilization instrumentation"
32 depends on DEBUG_KERNEL
33 help
34 Enables the display of the minimum amount of free stack which each
35 task has ever had available in the sysrq-T output.
36
37# These options are only for real kernel hackers who want to get their hands dirty.
38config DEBUG_LL
39 bool "Kernel low-level debugging functions"
40 depends on DEBUG_KERNEL
41 help
42 Say Y here to include definitions of printascii, printch, printhex
43 in the kernel. This is helpful if you are debugging code that
44 executes before the console is initialized.
45
46config DEBUG_OCD
47 bool "Kernel low-level debugging via On-Chip-Debugger"
48 depends on DEBUG_LL
49 default y
50 help
51 Say Y here if you want the debug print routines to direct their
52 output to the UniCore On-Chip-Debugger channel using CP #1.
53
54config DEBUG_OCD_BREAKPOINT
55 bool "Breakpoint support via On-Chip-Debugger"
56 depends on DEBUG_OCD
57
58config DEBUG_UART
59 int "Kernel low-level debugging messages via serial port"
60 depends on DEBUG_LL
61 range 0 1
62 default "0"
63 help
64 Choice for UART for kernel low-level using PKUnity UARTS,
65 should be between zero and one. The port must have been
66 initialised by the boot-loader before use.
67
68endmenu
diff --git a/arch/unicore32/Makefile b/arch/unicore32/Makefile
new file mode 100644
index 00000000000..e08d6d370a8
--- /dev/null
+++ b/arch/unicore32/Makefile
@@ -0,0 +1,95 @@
1#
2# arch/unicore32/Makefile
3#
4# This file is included by the global makefile so that you can add your own
5# architecture-specific flags and dependencies.
6#
7# This file is subject to the terms and conditions of the GNU General Public
8# License. See the file "COPYING" in the main directory of this archive
9# for more details.
10#
11# Copyright (C) 2002~2010 by Guan Xue-tao
12#
13ifneq ($(SUBARCH),$(ARCH))
14 ifeq ($(CROSS_COMPILE),)
15 CROSS_COMPILE := $(call cc-cross-prefix, unicore32-linux-)
16 endif
17endif
18
19LDFLAGS_vmlinux := -p --no-undefined -X
20
21OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -S
22
23# Never generate .eh_frame
24KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
25
26# Never use hard float in kernel
27KBUILD_CFLAGS += -msoft-float
28
29ifeq ($(CONFIG_FRAME_POINTER),y)
30KBUILD_CFLAGS += -mno-sched-prolog
31endif
32
33CHECKFLAGS += -D__unicore32__
34
35head-y := arch/unicore32/kernel/head.o
36head-y += arch/unicore32/kernel/init_task.o
37
38core-y += arch/unicore32/kernel/
39core-y += arch/unicore32/mm/
40
41libs-y += arch/unicore32/lib/
42
43ASM_GENERATED_DIR := $(srctree)/arch/unicore32/include/generated
44LINUXINCLUDE += -I$(ASM_GENERATED_DIR)
45
46ASM_GENERIC_HEADERS := atomic.h auxvec.h
47ASM_GENERIC_HEADERS += bitsperlong.h bug.h bugs.h
48ASM_GENERIC_HEADERS += cputime.h current.h
49ASM_GENERIC_HEADERS += device.h div64.h
50ASM_GENERIC_HEADERS += emergency-restart.h errno.h
51ASM_GENERIC_HEADERS += fb.h fcntl.h ftrace.h
52ASM_GENERIC_HEADERS += hardirq.h hw_irq.h
53ASM_GENERIC_HEADERS += ioctl.h ioctls.h ipcbuf.h irq_regs.h
54ASM_GENERIC_HEADERS += kdebug.h kmap_types.h
55ASM_GENERIC_HEADERS += local.h
56ASM_GENERIC_HEADERS += mman.h module.h msgbuf.h
57ASM_GENERIC_HEADERS += param.h parport.h percpu.h poll.h posix_types.h
58ASM_GENERIC_HEADERS += resource.h
59ASM_GENERIC_HEADERS += scatterlist.h sections.h segment.h sembuf.h serial.h
60ASM_GENERIC_HEADERS += setup.h shmbuf.h shmparam.h
61ASM_GENERIC_HEADERS += siginfo.h signal.h sizes.h
62ASM_GENERIC_HEADERS += socket.h sockios.h stat.h statfs.h swab.h syscalls.h
63ASM_GENERIC_HEADERS += termbits.h termios.h topology.h types.h
64ASM_GENERIC_HEADERS += ucontext.h unaligned.h user.h
65ASM_GENERIC_HEADERS += vga.h
66ASM_GENERIC_HEADERS += xor.h
67
68archprepare:
69ifneq ($(ASM_GENERATED_DIR), $(wildcard $(ASM_GENERATED_DIR)))
70 $(Q)mkdir -p $(ASM_GENERATED_DIR)/asm
71 $(Q)$(foreach a, $(ASM_GENERIC_HEADERS), \
72 echo '#include <asm-generic/$a>' \
73 > $(ASM_GENERATED_DIR)/asm/$a; )
74endif
75
76boot := arch/unicore32/boot
77
78# Default target when executing plain make
79KBUILD_IMAGE := zImage
80
81all: $(KBUILD_IMAGE)
82
83zImage Image uImage: vmlinux
84 $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
85
86MRPROPER_DIRS += $(ASM_GENERATED_DIR)
87
88archclean:
89 $(Q)$(MAKE) $(clean)=$(boot)
90
91define archhelp
92 echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
93 echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
94 echo ' uImage - U-Boot wrapped zImage'
95endef
diff --git a/arch/unicore32/boot/Makefile b/arch/unicore32/boot/Makefile
new file mode 100644
index 00000000000..79e5f88845d
--- /dev/null
+++ b/arch/unicore32/boot/Makefile
@@ -0,0 +1,47 @@
1#
2# arch/unicore32/boot/Makefile
3#
4# This file is included by the global makefile so that you can add your own
5# architecture-specific flags and dependencies.
6#
7# This file is subject to the terms and conditions of the GNU General Public
8# License. See the file "COPYING" in the main directory of this archive
9# for more details.
10#
11# Copyright (C) 2001~2010 GUAN Xue-tao
12#
13
14MKIMAGE := $(srctree)/scripts/mkuboot.sh
15
16targets := Image zImage uImage
17
18$(obj)/Image: vmlinux FORCE
19 $(call if_changed,objcopy)
20 @echo ' Kernel: $@ is ready'
21
22$(obj)/compressed/vmlinux: $(obj)/Image FORCE
23 $(Q)$(MAKE) $(build)=$(obj)/compressed $@
24
25$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
26 $(call if_changed,objcopy)
27 @echo ' Kernel: $@ is ready'
28
29quiet_cmd_uimage = UIMAGE $@
30 cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A unicore -O linux -T kernel \
31 -C none -a $(LOADADDR) -e $(STARTADDR) \
32 -n 'Linux-$(KERNELRELEASE)' -d $< $@
33
34$(obj)/uImage: LOADADDR=0x0
35
36$(obj)/uImage: STARTADDR=$(LOADADDR)
37
38$(obj)/uImage: $(obj)/zImage FORCE
39 $(call if_changed,uimage)
40 @echo ' Image $@ is ready'
41
42PHONY += initrd FORCE
43initrd:
44 @test "$(INITRD)" != "" || \
45 (echo You must specify INITRD; exit -1)
46
47subdir- := compressed
diff --git a/arch/unicore32/boot/compressed/Makefile b/arch/unicore32/boot/compressed/Makefile
new file mode 100644
index 00000000000..95373428cb3
--- /dev/null
+++ b/arch/unicore32/boot/compressed/Makefile
@@ -0,0 +1,68 @@
1#
2# linux/arch/unicore32/boot/compressed/Makefile
3#
4# create a compressed vmlinuz image from the original vmlinux
5#
6# This file is subject to the terms and conditions of the GNU General Public
7# License. See the file "COPYING" in the main directory of this archive
8# for more details.
9#
10# Copyright (C) 2001~2010 GUAN Xue-tao
11#
12
13EXTRA_CFLAGS := -fpic -fno-builtin
14EXTRA_AFLAGS := -Wa,-march=all
15
16OBJS := misc.o
17
18# font.c and font.o
19CFLAGS_font.o := -Dstatic=
20$(obj)/font.c: $(srctree)/drivers/video/console/font_8x8.c
21 $(call cmd,shipped)
22
23# piggy.S and piggy.o
24suffix_$(CONFIG_KERNEL_GZIP) := gzip
25suffix_$(CONFIG_KERNEL_BZIP2) := bz2
26suffix_$(CONFIG_KERNEL_LZO) := lzo
27suffix_$(CONFIG_KERNEL_LZMA) := lzma
28
29$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
30 $(call if_changed,$(suffix_y))
31
32SEDFLAGS_piggy = s/DECOMP_SUFFIX/$(suffix_y)/
33$(obj)/piggy.S: $(obj)/piggy.S.in
34 @sed "$(SEDFLAGS_piggy)" < $< > $@
35
36$(obj)/piggy.o: $(obj)/piggy.$(suffix_y) $(obj)/piggy.S FORCE
37
38targets := vmlinux vmlinux.lds font.o font.c head.o misc.o \
39 piggy.$(suffix_y) piggy.o piggy.S \
40
41# Make sure files are removed during clean
42extra-y += piggy.gzip piggy.bz2 piggy.lzo piggy.lzma
43
44# ?
45LDFLAGS_vmlinux += -p
46# Report unresolved symbol references
47LDFLAGS_vmlinux += --no-undefined
48# Delete all temporary local symbols
49LDFLAGS_vmlinux += -X
50# Next argument is a linker script
51LDFLAGS_vmlinux += -T
52
53# For uidivmod
54$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head.o $(obj)/piggy.o \
55 $(obj)/misc.o FORCE
56 $(call if_changed,ld)
57 @:
58
59# We now have a PIC decompressor implementation. Decompressors running
60# from RAM should not define ZTEXTADDR. Decompressors running directly
61# from ROM or Flash must define ZTEXTADDR (preferably via the config)
62ZTEXTADDR := 0
63ZBSSADDR := ALIGN(4)
64
65SEDFLAGS_lds = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
66$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/unicore32/boot/Makefile $(KCONFIG_CONFIG)
67 @sed "$(SEDFLAGS_lds)" < $< > $@
68
diff --git a/arch/unicore32/boot/compressed/head.S b/arch/unicore32/boot/compressed/head.S
new file mode 100644
index 00000000000..fbd1e374c68
--- /dev/null
+++ b/arch/unicore32/boot/compressed/head.S
@@ -0,0 +1,204 @@
1/*
2 * linux/arch/unicore32/boot/compressed/head.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <mach/memory.h>
14
15#define csub cmpsub
16#define cand cmpand
17#define nop8 nop; nop; nop; nop; nop; nop; nop; nop
18
19 .section ".start", #alloc, #execinstr
20 .text
21start:
22 .type start,#function
23
24 /* Initialize ASR, PRIV mode and INTR off */
25 mov r0, #0xD3
26 mov.a asr, r0
27
28 adr r0, LC0
29 ldm (r1, r2, r3, r5, r6, r7, r8), [r0]+
30 ldw sp, [r0+], #28
31 sub.a r0, r0, r1 @ calculate the delta offset
32
33 /*
34 * if delta is zero, we are running at the address
35 * we were linked at.
36 */
37 beq not_relocated
38
39 /*
40 * We're running at a different address. We need to fix
41 * up various pointers:
42 * r5 - zImage base address (_start)
43 * r7 - GOT start
44 * r8 - GOT end
45 */
46 add r5, r5, r0
47 add r7, r7, r0
48 add r8, r8, r0
49
50 /*
51 * we need to fix up pointers into the BSS region.
52 * r2 - BSS start
53 * r3 - BSS end
54 * sp - stack pointer
55 */
56 add r2, r2, r0
57 add r3, r3, r0
58 add sp, sp, r0
59
60 /*
61 * Relocate all entries in the GOT table.
62 * This fixes up the C references.
63 * r7 - GOT start
64 * r8 - GOT end
65 */
661001: ldw r1, [r7+], #0
67 add r1, r1, r0
68 stw.w r1, [r7]+, #4
69 csub.a r7, r8
70 bub 1001b
71
72not_relocated:
73 /*
74 * Clear BSS region.
75 * r2 - BSS start
76 * r3 - BSS end
77 */
78 mov r0, #0
791002: stw.w r0, [r2]+, #4
80 csub.a r2, r3
81 bub 1002b
82
83 /*
84 * Turn on the cache.
85 */
86 mov r0, #0
87 movc p0.c5, r0, #28 @ cache invalidate all
88 nop8
89 movc p0.c6, r0, #6 @ tlb invalidate all
90 nop8
91
92 mov r0, #0x1c @ en icache and wb dcache
93 movc p0.c1, r0, #0
94 nop8
95
96 /*
97 * Set up some pointers, for starting decompressing.
98 */
99
100 mov r1, sp @ malloc space above stack
101 add r2, sp, #0x10000 @ 64k max
102
103 /*
104 * Check to see if we will overwrite ourselves.
105 * r4 = final kernel address
106 * r5 = start of this image
107 * r6 = size of decompressed image
108 * r2 = end of malloc space (and therefore this image)
109 * We basically want:
110 * r4 >= r2 -> OK
111 * r4 + image length <= r5 -> OK
112 */
113 ldw r4, =KERNEL_IMAGE_START
114 csub.a r4, r2
115 bea wont_overwrite
116 add r0, r4, r6
117 csub.a r0, r5
118 beb wont_overwrite
119
120 /*
121 * If overwrite, just print error message
122 */
123 b __error_overwrite
124
125 /*
126 * We're not in danger of overwriting ourselves.
127 * Do this the simple way.
128 */
129wont_overwrite:
130 /*
131 * decompress_kernel:
132 * r0: output_start
133 * r1: free_mem_ptr_p
134 * r2: free_mem_ptr_end_p
135 */
136 mov r0, r4
137 b.l decompress_kernel @ C functions
138
139 /*
140 * Clean and flush the cache to maintain consistency.
141 */
142 mov r0, #0
143 movc p0.c5, r0, #14 @ flush dcache
144 nop8
145 movc p0.c5, r0, #20 @ icache invalidate all
146 nop8
147
148 /*
149 * Turn off the Cache and MMU.
150 */
151 mov r0, #0 @ disable i/d cache and MMU
152 movc p0.c1, r0, #0
153 nop8
154
155 mov r0, #0 @ must be zero
156 ldw r4, =KERNEL_IMAGE_START
157 mov pc, r4 @ call kernel
158
159
160 .align 2
161 .type LC0, #object
162LC0: .word LC0 @ r1
163 .word __bss_start @ r2
164 .word _end @ r3
165 .word _start @ r5
166 .word _image_size @ r6
167 .word _got_start @ r7
168 .word _got_end @ r8
169 .word decompress_stack_end @ sp
170 .size LC0, . - LC0
171
172print_string:
173#ifdef CONFIG_DEBUG_OCD
1742001: ldb.w r1, [r0]+, #1
175 csub.a r1, #0
176 bne 2002f
177 mov pc, lr
1782002:
179 movc r2, p1.c0, #0
180 cand.a r2, #2
181 bne 2002b
182 movc p1.c1, r1, #1
183 csub.a r1, #'\n'
184 cmoveq r1, #'\r'
185 beq 2002b
186 b 2001b
187#else
188 mov pc, lr
189#endif
190
191__error_overwrite:
192 adr r0, str_error
193 b.l print_string
1942001: nop8
195 b 2001b
196str_error: .asciz "\nError: Kernel address OVERWRITE\n"
197 .align
198
199 .ltorg
200
201 .align 4
202 .section ".stack", "aw", %nobits
203decompress_stack: .space 4096
204decompress_stack_end:
diff --git a/arch/unicore32/boot/compressed/misc.c b/arch/unicore32/boot/compressed/misc.c
new file mode 100644
index 00000000000..176d5bda355
--- /dev/null
+++ b/arch/unicore32/boot/compressed/misc.c
@@ -0,0 +1,126 @@
1/*
2 * linux/arch/unicore32/boot/compressed/misc.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <asm/unaligned.h>
14#include <mach/uncompress.h>
15
16/*
17 * gzip delarations
18 */
19unsigned char *output_data;
20unsigned long output_ptr;
21
22unsigned int free_mem_ptr;
23unsigned int free_mem_end_ptr;
24
25#define STATIC static
26#define STATIC_RW_DATA /* non-static please */
27
28/*
29 * arch-dependent implementations
30 */
31#ifndef ARCH_HAVE_DECOMP_ERROR
32#define arch_decomp_error(x)
33#endif
34
35#ifndef ARCH_HAVE_DECOMP_SETUP
36#define arch_decomp_setup()
37#endif
38
39#ifndef ARCH_HAVE_DECOMP_PUTS
40#define arch_decomp_puts(p)
41#endif
42
43void *memcpy(void *dest, const void *src, size_t n)
44{
45 int i = 0;
46 unsigned char *d = (unsigned char *)dest, *s = (unsigned char *)src;
47
48 for (i = n >> 3; i > 0; i--) {
49 *d++ = *s++;
50 *d++ = *s++;
51 *d++ = *s++;
52 *d++ = *s++;
53 *d++ = *s++;
54 *d++ = *s++;
55 *d++ = *s++;
56 *d++ = *s++;
57 }
58
59 if (n & 1 << 2) {
60 *d++ = *s++;
61 *d++ = *s++;
62 *d++ = *s++;
63 *d++ = *s++;
64 }
65
66 if (n & 1 << 1) {
67 *d++ = *s++;
68 *d++ = *s++;
69 }
70
71 if (n & 1)
72 *d++ = *s++;
73
74 return dest;
75}
76
77void error(char *x)
78{
79 arch_decomp_puts("\n\n");
80 arch_decomp_puts(x);
81 arch_decomp_puts("\n\n -- System halted");
82
83 arch_decomp_error(x);
84
85 for (;;)
86 ; /* Halt */
87}
88
89/* Heap size should be adjusted for different decompress method */
90#ifdef CONFIG_KERNEL_GZIP
91#include "../../../../lib/decompress_inflate.c"
92#endif
93
94#ifdef CONFIG_KERNEL_BZIP2
95#include "../../../../lib/decompress_bunzip2.c"
96#endif
97
98#ifdef CONFIG_KERNEL_LZO
99#include "../../../../lib/decompress_unlzo.c"
100#endif
101
102#ifdef CONFIG_KERNEL_LZMA
103#include "../../../../lib/decompress_unlzma.c"
104#endif
105
106unsigned long decompress_kernel(unsigned long output_start,
107 unsigned long free_mem_ptr_p,
108 unsigned long free_mem_ptr_end_p)
109{
110 unsigned char *tmp;
111
112 output_data = (unsigned char *)output_start;
113 free_mem_ptr = free_mem_ptr_p;
114 free_mem_end_ptr = free_mem_ptr_end_p;
115
116 arch_decomp_setup();
117
118 tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
119 output_ptr = get_unaligned_le32(tmp);
120
121 arch_decomp_puts("Uncompressing Linux...");
122 decompress(input_data, input_data_end - input_data, NULL, NULL,
123 output_data, NULL, error);
124 arch_decomp_puts(" done, booting the kernel.\n");
125 return output_ptr;
126}
diff --git a/arch/unicore32/boot/compressed/piggy.S.in b/arch/unicore32/boot/compressed/piggy.S.in
new file mode 100644
index 00000000000..b79704d5802
--- /dev/null
+++ b/arch/unicore32/boot/compressed/piggy.S.in
@@ -0,0 +1,6 @@
1 .section .piggydata,#alloc
2 .globl input_data
3input_data:
4 .incbin "arch/unicore32/boot/compressed/piggy.DECOMP_SUFFIX"
5 .globl input_data_end
6input_data_end:
diff --git a/arch/unicore32/boot/compressed/vmlinux.lds.in b/arch/unicore32/boot/compressed/vmlinux.lds.in
new file mode 100644
index 00000000000..d5a3ce29623
--- /dev/null
+++ b/arch/unicore32/boot/compressed/vmlinux.lds.in
@@ -0,0 +1,61 @@
1/*
2 * linux/arch/unicore/boot/compressed/vmlinux.lds.in
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12OUTPUT_ARCH(unicore32)
13ENTRY(_start)
14SECTIONS
15{
16 /DISCARD/ : {
17 /*
18 * Discard any r/w data - this produces a link error if we have any,
19 * which is required for PIC decompression. Local data generates
20 * GOTOFF relocations, which prevents it being relocated independently
21 * of the text/got segments.
22 */
23 *(.data)
24 }
25
26 . = TEXT_START;
27 _text = .;
28
29 .text : {
30 _start = .;
31 *(.start)
32 *(.text)
33 *(.text.*)
34 *(.fixup)
35 *(.gnu.warning)
36 *(.rodata)
37 *(.rodata.*)
38 *(.piggydata)
39 . = ALIGN(4);
40 }
41
42 _etext = .;
43
44 /* Assume size of decompressed image is 4x the compressed image */
45 _image_size = (_etext - _text) * 4;
46
47 _got_start = .;
48 .got : { *(.got) }
49 _got_end = .;
50 .got.plt : { *(.got.plt) }
51 _edata = .;
52
53 . = BSS_START;
54 __bss_start = .;
55 .bss : { *(.bss) }
56 _end = .;
57
58 .stack : { *(.stack) }
59 .comment 0 : { *(.comment) }
60}
61
diff --git a/arch/unicore32/configs/debug_defconfig b/arch/unicore32/configs/debug_defconfig
new file mode 100644
index 00000000000..b5fbde9f1cb
--- /dev/null
+++ b/arch/unicore32/configs/debug_defconfig
@@ -0,0 +1,215 @@
1### General setup
2CONFIG_EXPERIMENTAL=y
3CONFIG_LOCALVERSION="-debug"
4CONFIG_SWAP=y
5CONFIG_SYSVIPC=y
6CONFIG_POSIX_MQUEUE=y
7CONFIG_HOTPLUG=y
8# Initial RAM filesystem and RAM disk (initramfs/initrd) support
9#CONFIG_BLK_DEV_INITRD=y
10#CONFIG_INITRAMFS_SOURCE="arch/unicore/ramfs/ramfs_config"
11
12### Enable loadable module support
13CONFIG_MODULES=n
14CONFIG_MODULE_UNLOAD=y
15
16### System Type
17CONFIG_ARCH_PUV3=y
18# Board Selection
19CONFIG_PUV3_NB0916=y
20# Processor Features
21CONFIG_CPU_DCACHE_LINE_DISABLE=y
22CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE=n
23
24### Bus support
25CONFIG_PCI=y
26CONFIG_PCI_LEGACY=n
27
28### Boot options
29# for debug, adding: earlyprintk=ocd,keep initcall_debug
30# others support: test_suspend=mem root=/dev/sda
31# hibernate support: resume=/dev/sda3
32CONFIG_CMDLINE="earlyprintk=ocd,keep ignore_loglevel"
33# TODO: mem=512M video=unifb:1024x600-16@75
34# for nfs: root=/dev/nfs rw nfsroot=192.168.10.88:/home/udb/nfs/,rsize=1024,wsize=1024
35# ip=192.168.10.83:192.168.10.88:192.168.10.1:255.255.255.0::eth0:off
36CONFIG_CMDLINE_FORCE=y
37
38### Power management options
39CONFIG_PM=y
40CONFIG_HIBERNATION=y
41CONFIG_PM_STD_PARTITION="/dev/sda3"
42CONFIG_CPU_FREQ=n
43CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
44
45### Networking support
46CONFIG_NET=y
47# Networking options
48CONFIG_PACKET=m
49CONFIG_UNIX=m
50# TCP/IP networking
51CONFIG_INET=y
52CONFIG_IP_MULTICAST=y
53CONFIG_IP_PNP=y
54CONFIG_IPV6=n
55# Wireless
56CONFIG_WIRELESS=y
57CONFIG_WIRELESS_EXT=y
58CONFIG_MAC80211=m
59
60### PKUnity SoC Features
61CONFIG_USB_WLAN_HED_AQ3=n
62CONFIG_USB_CMMB_INNOFIDEI=n
63CONFIG_I2C_BATTERY_BQ27200=n
64CONFIG_I2C_EEPROM_AT24=n
65CONFIG_LCD_BACKLIGHT=n
66
67CONFIG_PUV3_RTC=y
68CONFIG_PUV3_UMAL=y
69CONFIG_PUV3_MUSB=n
70CONFIG_PUV3_AC97=n
71CONFIG_PUV3_NAND=n
72CONFIG_PUV3_MMC=n
73CONFIG_PUV3_UART=n
74
75### Device Drivers
76# Memory Technology Device (MTD) support
77CONFIG_MTD=m
78CONFIG_MTD_UBI=m
79CONFIG_MTD_PARTITIONS=y
80CONFIG_MTD_CHAR=m
81CONFIG_MTD_BLKDEVS=m
82# RAM/ROM/Flash chip drivers
83CONFIG_MTD_CFI=m
84CONFIG_MTD_JEDECPROBE=m
85CONFIG_MTD_CFI_AMDSTD=m
86# Mapping drivers for chip access
87CONFIG_MTD_PHYSMAP=m
88
89# Block devices
90CONFIG_BLK_DEV_LOOP=m
91
92# SCSI device support
93CONFIG_SCSI=y
94CONFIG_BLK_DEV_SD=y
95CONFIG_BLK_DEV_SR=m
96CONFIG_CHR_DEV_SG=m
97
98# Serial ATA (prod) and Parallel ATA (experimental) drivers
99CONFIG_ATA=y
100CONFIG_SATA_VIA=y
101
102# Network device support
103CONFIG_NETDEVICES=y
104CONFIG_NET_ETHERNET=y
105CONFIG_NETDEV_1000=y
106# Wireless LAN
107CONFIG_WLAN_80211=n
108CONFIG_RT2X00=n
109CONFIG_RT73USB=n
110
111# Input device support
112CONFIG_INPUT_EVDEV=m
113# Keyboards
114CONFIG_KEYBOARD_GPIO=m
115
116# I2C support
117CONFIG_I2C=y
118CONFIG_I2C_PUV3=y
119
120# Hardware Monitoring support
121#CONFIG_SENSORS_LM75=m
122# Generic Thermal sysfs driver
123#CONFIG_THERMAL=m
124#CONFIG_THERMAL_HWMON=y
125
126# Multimedia support
127CONFIG_MEDIA_SUPPORT=n
128CONFIG_VIDEO_DEV=n
129CONFIG_USB_VIDEO_CLASS=n
130
131# Graphics support
132CONFIG_FB=y
133CONFIG_FB_PUV3_UNIGFX=y
134# Console display driver support
135CONFIG_VGA_CONSOLE=n
136CONFIG_FRAMEBUFFER_CONSOLE=y
137CONFIG_FONTS=y
138CONFIG_FONT_8x8=y
139CONFIG_FONT_8x16=y
140# Bootup logo
141CONFIG_LOGO=n
142
143# Sound card support
144CONFIG_SOUND=m
145# Advanced Linux Sound Architecture
146CONFIG_SND=m
147CONFIG_SND_MIXER_OSS=m
148CONFIG_SND_PCM_OSS=m
149
150# USB support
151CONFIG_USB_ARCH_HAS_HCD=n
152CONFIG_USB=n
153CONFIG_USB_DEVICEFS=n
154CONFIG_USB_PRINTER=n
155CONFIG_USB_STORAGE=n
156# Inventra Highspeed Dual Role Controller
157CONFIG_USB_MUSB_HDRC=n
158
159# LED Support
160CONFIG_NEW_LEDS=y
161CONFIG_LEDS_CLASS=y
162CONFIG_LEDS_GPIO=y
163# LED Triggers
164CONFIG_LEDS_TRIGGERS=y
165CONFIG_LEDS_TRIGGER_TIMER=y
166CONFIG_LEDS_TRIGGER_IDE_DISK=y
167CONFIG_LEDS_TRIGGER_HEARTBEAT=y
168
169# Real Time Clock
170CONFIG_RTC_LIB=m
171CONFIG_RTC_CLASS=m
172
173### File systems
174CONFIG_EXT2_FS=m
175CONFIG_EXT3_FS=y
176CONFIG_EXT4_FS=y
177CONFIG_FUSE_FS=m
178# CD-ROM/DVD Filesystems
179CONFIG_ISO9660_FS=m
180CONFIG_JOLIET=y
181CONFIG_UDF_FS=m
182# DOS/FAT/NT Filesystems
183CONFIG_VFAT_FS=m
184# Pseudo filesystems
185CONFIG_PROC_FS=y
186CONFIG_SYSFS=y
187CONFIG_TMPFS=y
188# Miscellaneous filesystems
189CONFIG_MISC_FILESYSTEMS=y
190CONFIG_JFFS2_FS=m
191CONFIG_UBIFS_FS=m
192# Network File Systems
193CONFIG_NETWORK_FILESYSTEMS=y
194CONFIG_NFS_FS=y
195CONFIG_NFS_V3=y
196CONFIG_ROOT_NFS=y
197# Partition Types
198CONFIG_PARTITION_ADVANCED=y
199CONFIG_MSDOS_PARTITION=y
200# Native language support
201CONFIG_NLS=y
202CONFIG_NLS_CODEPAGE_437=m
203CONFIG_NLS_CODEPAGE_936=m
204CONFIG_NLS_ISO8859_1=m
205CONFIG_NLS_UTF8=m
206
207### Kernel hacking
208CONFIG_FRAME_WARN=8096
209CONFIG_MAGIC_SYSRQ=y
210CONFIG_DEBUG_KERNEL=y
211CONFIG_PROVE_LOCKING=n
212CONFIG_DEBUG_BUGVERBOSE=y
213CONFIG_FRAME_POINTER=y
214CONFIG_DEBUG_LL=y
215
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
new file mode 100644
index 00000000000..b200fdaca44
--- /dev/null
+++ b/arch/unicore32/include/asm/Kbuild
@@ -0,0 +1,2 @@
1include include/asm-generic/Kbuild.asm
2
diff --git a/arch/unicore32/include/asm/assembler.h b/arch/unicore32/include/asm/assembler.h
new file mode 100644
index 00000000000..8e87ed7faeb
--- /dev/null
+++ b/arch/unicore32/include/asm/assembler.h
@@ -0,0 +1,131 @@
1/*
2 * linux/arch/unicore32/include/asm/assembler.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Do not include any C declarations in this file - it is included by
13 * assembler source.
14 */
15#ifndef __ASSEMBLY__
16#error "Only include this from assembly code"
17#endif
18
19#include <asm/ptrace.h>
20
21/*
22 * Little Endian independent macros for shifting bytes within registers.
23 */
24#define pull >>
25#define push <<
26#define get_byte_0 << #0
27#define get_byte_1 >> #8
28#define get_byte_2 >> #16
29#define get_byte_3 >> #24
30#define put_byte_0 << #0
31#define put_byte_1 << #8
32#define put_byte_2 << #16
33#define put_byte_3 << #24
34
35#define cadd cmpadd
36#define cand cmpand
37#define csub cmpsub
38#define cxor cmpxor
39
40/*
41 * Enable and disable interrupts
42 */
43 .macro disable_irq, temp
44 mov \temp, asr
45 andn \temp, \temp, #0xFF
46 or \temp, \temp, #PSR_I_BIT | PRIV_MODE
47 mov.a asr, \temp
48 .endm
49
50 .macro enable_irq, temp
51 mov \temp, asr
52 andn \temp, \temp, #0xFF
53 or \temp, \temp, #PRIV_MODE
54 mov.a asr, \temp
55 .endm
56
57#define USER(x...) \
589999: x; \
59 .pushsection __ex_table, "a"; \
60 .align 3; \
61 .long 9999b, 9001f; \
62 .popsection
63
64 .macro notcond, cond, nexti = .+8
65 .ifc \cond, eq
66 bne \nexti
67 .else; .ifc \cond, ne
68 beq \nexti
69 .else; .ifc \cond, ea
70 bub \nexti
71 .else; .ifc \cond, ub
72 bea \nexti
73 .else; .ifc \cond, fs
74 bns \nexti
75 .else; .ifc \cond, ns
76 bfs \nexti
77 .else; .ifc \cond, fv
78 bnv \nexti
79 .else; .ifc \cond, nv
80 bfv \nexti
81 .else; .ifc \cond, ua
82 beb \nexti
83 .else; .ifc \cond, eb
84 bua \nexti
85 .else; .ifc \cond, eg
86 bsl \nexti
87 .else; .ifc \cond, sl
88 beg \nexti
89 .else; .ifc \cond, sg
90 bel \nexti
91 .else; .ifc \cond, el
92 bsg \nexti
93 .else; .ifnc \cond, al
94 .error "Unknown cond in notcond macro argument"
95 .endif; .endif; .endif; .endif; .endif; .endif; .endif
96 .endif; .endif; .endif; .endif; .endif; .endif; .endif
97 .endif
98 .endm
99
100 .macro usracc, instr, reg, ptr, inc, cond, rept, abort
101 .rept \rept
102 notcond \cond, .+8
1039999 :
104 .if \inc == 1
105 \instr\()b.u \reg, [\ptr], #\inc
106 .elseif \inc == 4
107 \instr\()w.u \reg, [\ptr], #\inc
108 .else
109 .error "Unsupported inc macro argument"
110 .endif
111
112 .pushsection __ex_table, "a"
113 .align 3
114 .long 9999b, \abort
115 .popsection
116 .endr
117 .endm
118
119 .macro strusr, reg, ptr, inc, cond = al, rept = 1, abort = 9001f
120 usracc st, \reg, \ptr, \inc, \cond, \rept, \abort
121 .endm
122
123 .macro ldrusr, reg, ptr, inc, cond = al, rept = 1, abort = 9001f
124 usracc ld, \reg, \ptr, \inc, \cond, \rept, \abort
125 .endm
126
127 .macro nop8
128 .rept 8
129 nop
130 .endr
131 .endm
diff --git a/arch/unicore32/include/asm/bitops.h b/arch/unicore32/include/asm/bitops.h
new file mode 100644
index 00000000000..1628a632899
--- /dev/null
+++ b/arch/unicore32/include/asm/bitops.h
@@ -0,0 +1,47 @@
1/*
2 * linux/arch/unicore32/include/asm/bitops.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_BITOPS_H__
14#define __UNICORE_BITOPS_H__
15
16#define find_next_bit __uc32_find_next_bit
17#define find_next_zero_bit __uc32_find_next_zero_bit
18
19#define find_first_bit __uc32_find_first_bit
20#define find_first_zero_bit __uc32_find_first_zero_bit
21
22#define _ASM_GENERIC_BITOPS_FLS_H_
23#define _ASM_GENERIC_BITOPS___FLS_H_
24#define _ASM_GENERIC_BITOPS_FFS_H_
25#define _ASM_GENERIC_BITOPS___FFS_H_
26/*
27 * On UNICORE, those functions can be implemented around
28 * the cntlz instruction for much better code efficiency.
29 */
30
31static inline int fls(int x)
32{
33 int ret;
34
35 asm("cntlz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
36 ret = 32 - ret;
37
38 return ret;
39}
40
41#define __fls(x) (fls(x) - 1)
42#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
43#define __ffs(x) (ffs(x) - 1)
44
45#include <asm-generic/bitops.h>
46
47#endif /* __UNICORE_BITOPS_H__ */
diff --git a/arch/unicore32/include/asm/byteorder.h b/arch/unicore32/include/asm/byteorder.h
new file mode 100644
index 00000000000..ebe1b3fef3e
--- /dev/null
+++ b/arch/unicore32/include/asm/byteorder.h
@@ -0,0 +1,24 @@
1/*
2 * linux/arch/unicore32/include/asm/byteorder.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * UniCore ONLY support Little Endian mode, the data bus is connected such
13 * that byte accesses appear as:
14 * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31
15 * and word accesses (data or instruction) appear as:
16 * d0...d31
17 */
18#ifndef __UNICORE_BYTEORDER_H__
19#define __UNICORE_BYTEORDER_H__
20
21#include <linux/byteorder/little_endian.h>
22
23#endif
24
diff --git a/arch/unicore32/include/asm/cache.h b/arch/unicore32/include/asm/cache.h
new file mode 100644
index 00000000000..ad8f795d86c
--- /dev/null
+++ b/arch/unicore32/include/asm/cache.h
@@ -0,0 +1,27 @@
1/*
2 * linux/arch/unicore32/include/asm/cache.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_CACHE_H__
13#define __UNICORE_CACHE_H__
14
15#define L1_CACHE_SHIFT (5)
16#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
17
18/*
19 * Memory returned by kmalloc() may be used for DMA, so we must make
20 * sure that all such allocations are cache aligned. Otherwise,
21 * unrelated code may cause parts of the buffer to be read into the
22 * cache before the transfer is done, causing old data to be seen by
23 * the CPU.
24 */
25#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
26
27#endif
diff --git a/arch/unicore32/include/asm/cacheflush.h b/arch/unicore32/include/asm/cacheflush.h
new file mode 100644
index 00000000000..c0301e6c8b8
--- /dev/null
+++ b/arch/unicore32/include/asm/cacheflush.h
@@ -0,0 +1,211 @@
1/*
2 * linux/arch/unicore32/include/asm/cacheflush.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_CACHEFLUSH_H__
13#define __UNICORE_CACHEFLUSH_H__
14
15#include <linux/mm.h>
16
17#include <asm/shmparam.h>
18
19#define CACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
20
21/*
22 * This flag is used to indicate that the page pointed to by a pte is clean
23 * and does not require cleaning before returning it to the user.
24 */
25#define PG_dcache_clean PG_arch_1
26
27/*
28 * MM Cache Management
29 * ===================
30 *
31 * The arch/unicore32/mm/cache.S files implement these methods.
32 *
33 * Start addresses are inclusive and end addresses are exclusive;
34 * start addresses should be rounded down, end addresses up.
35 *
36 * See Documentation/cachetlb.txt for more information.
37 * Please note that the implementation of these, and the required
38 * effects are cache-type (VIVT/VIPT/PIPT) specific.
39 *
40 * flush_icache_all()
41 *
42 * Unconditionally clean and invalidate the entire icache.
43 * Currently only needed for cache-v6.S and cache-v7.S, see
44 * __flush_icache_all for the generic implementation.
45 *
46 * flush_kern_all()
47 *
48 * Unconditionally clean and invalidate the entire cache.
49 *
50 * flush_user_all()
51 *
52 * Clean and invalidate all user space cache entries
53 * before a change of page tables.
54 *
55 * flush_user_range(start, end, flags)
56 *
57 * Clean and invalidate a range of cache entries in the
58 * specified address space before a change of page tables.
59 * - start - user start address (inclusive, page aligned)
60 * - end - user end address (exclusive, page aligned)
61 * - flags - vma->vm_flags field
62 *
63 * coherent_kern_range(start, end)
64 *
65 * Ensure coherency between the Icache and the Dcache in the
66 * region described by start, end. If you have non-snooping
67 * Harvard caches, you need to implement this function.
68 * - start - virtual start address
69 * - end - virtual end address
70 *
71 * coherent_user_range(start, end)
72 *
73 * Ensure coherency between the Icache and the Dcache in the
74 * region described by start, end. If you have non-snooping
75 * Harvard caches, you need to implement this function.
76 * - start - virtual start address
77 * - end - virtual end address
78 *
79 * flush_kern_dcache_area(kaddr, size)
80 *
81 * Ensure that the data held in page is written back.
82 * - kaddr - page address
83 * - size - region size
84 *
85 * DMA Cache Coherency
86 * ===================
87 *
88 * dma_flush_range(start, end)
89 *
90 * Clean and invalidate the specified virtual address range.
91 * - start - virtual start address
92 * - end - virtual end address
93 */
94
95extern void __cpuc_flush_icache_all(void);
96extern void __cpuc_flush_kern_all(void);
97extern void __cpuc_flush_user_all(void);
98extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
99extern void __cpuc_coherent_kern_range(unsigned long, unsigned long);
100extern void __cpuc_coherent_user_range(unsigned long, unsigned long);
101extern void __cpuc_flush_dcache_area(void *, size_t);
102extern void __cpuc_flush_kern_dcache_area(void *addr, size_t size);
103
104/*
105 * These are private to the dma-mapping API. Do not use directly.
106 * Their sole purpose is to ensure that data held in the cache
107 * is visible to DMA, or data written by DMA to system memory is
108 * visible to the CPU.
109 */
110extern void __cpuc_dma_clean_range(unsigned long, unsigned long);
111extern void __cpuc_dma_flush_range(unsigned long, unsigned long);
112
113/*
114 * Copy user data from/to a page which is mapped into a different
115 * processes address space. Really, we want to allow our "user
116 * space" model to handle this.
117 */
118extern void copy_to_user_page(struct vm_area_struct *, struct page *,
119 unsigned long, void *, const void *, unsigned long);
120#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
121 do { \
122 memcpy(dst, src, len); \
123 } while (0)
124
125/*
126 * Convert calls to our calling convention.
127 */
128/* Invalidate I-cache */
129static inline void __flush_icache_all(void)
130{
131 asm("movc p0.c5, %0, #20;\n"
132 "nop; nop; nop; nop; nop; nop; nop; nop\n"
133 :
134 : "r" (0));
135}
136
137#define flush_cache_all() __cpuc_flush_kern_all()
138
139extern void flush_cache_mm(struct mm_struct *mm);
140extern void flush_cache_range(struct vm_area_struct *vma,
141 unsigned long start, unsigned long end);
142extern void flush_cache_page(struct vm_area_struct *vma,
143 unsigned long user_addr, unsigned long pfn);
144
145#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
146
147/*
148 * flush_cache_user_range is used when we want to ensure that the
149 * Harvard caches are synchronised for the user space address range.
150 * This is used for the UniCore private sys_cacheflush system call.
151 */
152#define flush_cache_user_range(vma, start, end) \
153 __cpuc_coherent_user_range((start) & PAGE_MASK, PAGE_ALIGN(end))
154
155/*
156 * Perform necessary cache operations to ensure that data previously
157 * stored within this range of addresses can be executed by the CPU.
158 */
159#define flush_icache_range(s, e) __cpuc_coherent_kern_range(s, e)
160
161/*
162 * Perform necessary cache operations to ensure that the TLB will
163 * see data written in the specified area.
164 */
165#define clean_dcache_area(start, size) cpu_dcache_clean_area(start, size)
166
167/*
168 * flush_dcache_page is used when the kernel has written to the page
169 * cache page at virtual address page->virtual.
170 *
171 * If this page isn't mapped (ie, page_mapping == NULL), or it might
172 * have userspace mappings, then we _must_ always clean + invalidate
173 * the dcache entries associated with the kernel mapping.
174 *
175 * Otherwise we can defer the operation, and clean the cache when we are
176 * about to change to user space. This is the same method as used on SPARC64.
177 * See update_mmu_cache for the user space part.
178 */
179#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
180extern void flush_dcache_page(struct page *);
181
182#define flush_dcache_mmap_lock(mapping) \
183 spin_lock_irq(&(mapping)->tree_lock)
184#define flush_dcache_mmap_unlock(mapping) \
185 spin_unlock_irq(&(mapping)->tree_lock)
186
187#define flush_icache_user_range(vma, page, addr, len) \
188 flush_dcache_page(page)
189
190/*
191 * We don't appear to need to do anything here. In fact, if we did, we'd
192 * duplicate cache flushing elsewhere performed by flush_dcache_page().
193 */
194#define flush_icache_page(vma, page) do { } while (0)
195
196/*
197 * flush_cache_vmap() is used when creating mappings (eg, via vmap,
198 * vmalloc, ioremap etc) in kernel space for pages. On non-VIPT
199 * caches, since the direct-mappings of these pages may contain cached
200 * data, we need to do a full cache flush to ensure that writebacks
201 * don't corrupt data placed into these pages via the new mappings.
202 */
203static inline void flush_cache_vmap(unsigned long start, unsigned long end)
204{
205}
206
207static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
208{
209}
210
211#endif
diff --git a/arch/unicore32/include/asm/checksum.h b/arch/unicore32/include/asm/checksum.h
new file mode 100644
index 00000000000..f55c3f937c3
--- /dev/null
+++ b/arch/unicore32/include/asm/checksum.h
@@ -0,0 +1,41 @@
1/*
2 * linux/arch/unicore32/include/asm/checksum.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * IP checksum routines
13 */
14#ifndef __UNICORE_CHECKSUM_H__
15#define __UNICORE_CHECKSUM_H__
16
17/*
18 * computes the checksum of the TCP/UDP pseudo-header
19 * returns a 16-bit checksum, already complemented
20 */
21
22static inline __wsum
23csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
24 unsigned short proto, __wsum sum)
25{
26 __asm__(
27 "add.a %0, %1, %2\n"
28 "addc.a %0, %0, %3\n"
29 "addc.a %0, %0, %4 << #8\n"
30 "addc.a %0, %0, %5\n"
31 "addc %0, %0, #0\n"
32 : "=&r"(sum)
33 : "r" (sum), "r" (daddr), "r" (saddr), "r" (len), "Ir" (htons(proto))
34 : "cc");
35 return sum;
36}
37#define csum_tcpudp_nofold csum_tcpudp_nofold
38
39#include <asm-generic/checksum.h>
40
41#endif
diff --git a/arch/unicore32/include/asm/cpu-single.h b/arch/unicore32/include/asm/cpu-single.h
new file mode 100644
index 00000000000..0f55d182343
--- /dev/null
+++ b/arch/unicore32/include/asm/cpu-single.h
@@ -0,0 +1,45 @@
1/*
2 * linux/arch/unicore32/include/asm/cpu-single.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_CPU_SINGLE_H__
13#define __UNICORE_CPU_SINGLE_H__
14
15#include <asm/page.h>
16#include <asm/memory.h>
17
18#ifdef __KERNEL__
19#ifndef __ASSEMBLY__
20
21#define cpu_switch_mm(pgd, mm) cpu_do_switch_mm(virt_to_phys(pgd), mm)
22
23#define cpu_get_pgd() \
24 ({ \
25 unsigned long pg; \
26 __asm__("movc %0, p0.c2, #0" \
27 : "=r" (pg) : : "cc"); \
28 pg &= ~0x0fff; \
29 (pgd_t *)phys_to_virt(pg); \
30 })
31
32struct mm_struct;
33
34/* declare all the functions as extern */
35extern void cpu_proc_fin(void);
36extern int cpu_do_idle(void);
37extern void cpu_dcache_clean_area(void *, int);
38extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
39extern void cpu_set_pte(pte_t *ptep, pte_t pte);
40extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
41
42#endif /* __ASSEMBLY__ */
43#endif /* __KERNEL__ */
44
45#endif /* __UNICORE_CPU_SINGLE_H__ */
diff --git a/arch/unicore32/include/asm/cputype.h b/arch/unicore32/include/asm/cputype.h
new file mode 100644
index 00000000000..ec1a30f9807
--- /dev/null
+++ b/arch/unicore32/include/asm/cputype.h
@@ -0,0 +1,33 @@
1/*
2 * linux/arch/unicore32/include/asm/cputype.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_CPUTYPE_H__
13#define __UNICORE_CPUTYPE_H__
14
15#include <linux/stringify.h>
16
17#define CPUID_CPUID 0
18#define CPUID_CACHETYPE 1
19
20#define read_cpuid(reg) \
21 ({ \
22 unsigned int __val; \
23 asm("movc %0, p0.c0, #" __stringify(reg) \
24 : "=r" (__val) \
25 : \
26 : "cc"); \
27 __val; \
28 })
29
30#define uc32_cpuid read_cpuid(CPUID_CPUID)
31#define uc32_cachetype read_cpuid(CPUID_CACHETYPE)
32
33#endif
diff --git a/arch/unicore32/include/asm/delay.h b/arch/unicore32/include/asm/delay.h
new file mode 100644
index 00000000000..164ae61cd6f
--- /dev/null
+++ b/arch/unicore32/include/asm/delay.h
@@ -0,0 +1,52 @@
1/*
2 * linux/arch/unicore32/include/asm/delay.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Delay routines, using a pre-computed "loops_per_second" value.
13 */
14#ifndef __UNICORE_DELAY_H__
15#define __UNICORE_DELAY_H__
16
17#include <asm/param.h> /* HZ */
18
19extern void __delay(int loops);
20
21/*
22 * This function intentionally does not exist; if you see references to
23 * it, it means that you're calling udelay() with an out of range value.
24 *
25 * With currently imposed limits, this means that we support a max delay
26 * of 2000us. Further limits: HZ<=1000 and bogomips<=3355
27 */
28extern void __bad_udelay(void);
29
30/*
31 * division by multiplication: you don't have to worry about
32 * loss of precision.
33 *
34 * Use only for very small delays ( < 1 msec). Should probably use a
35 * lookup table, really, as the multiplications take much too long with
36 * short delays. This is a "reasonable" implementation, though (and the
37 * first constant multiplications gets optimized away if the delay is
38 * a constant)
39 */
40extern void __udelay(unsigned long usecs);
41extern void __const_udelay(unsigned long);
42
43#define MAX_UDELAY_MS 2
44
45#define udelay(n) \
46 (__builtin_constant_p(n) ? \
47 ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : \
48 __const_udelay((n) * ((2199023U*HZ)>>11))) : \
49 __udelay(n))
50
51#endif /* __UNICORE_DELAY_H__ */
52
diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h
new file mode 100644
index 00000000000..9258e592f41
--- /dev/null
+++ b/arch/unicore32/include/asm/dma-mapping.h
@@ -0,0 +1,124 @@
1/*
2 * linux/arch/unicore32/include/asm/dma-mapping.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_DMA_MAPPING_H__
13#define __UNICORE_DMA_MAPPING_H__
14
15#ifdef __KERNEL__
16
17#include <linux/mm_types.h>
18#include <linux/scatterlist.h>
19#include <linux/swiotlb.h>
20
21#include <asm-generic/dma-coherent.h>
22
23#include <asm/memory.h>
24#include <asm/cacheflush.h>
25
26extern struct dma_map_ops swiotlb_dma_map_ops;
27
28static inline struct dma_map_ops *get_dma_ops(struct device *dev)
29{
30 return &swiotlb_dma_map_ops;
31}
32
33static inline int dma_supported(struct device *dev, u64 mask)
34{
35 struct dma_map_ops *dma_ops = get_dma_ops(dev);
36
37 if (unlikely(dma_ops == NULL))
38 return 0;
39
40 return dma_ops->dma_supported(dev, mask);
41}
42
43static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
44{
45 struct dma_map_ops *dma_ops = get_dma_ops(dev);
46
47 if (dma_ops->mapping_error)
48 return dma_ops->mapping_error(dev, dma_addr);
49
50 return 0;
51}
52
53#include <asm-generic/dma-mapping-common.h>
54
55static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
56{
57 if (dev && dev->dma_mask)
58 return addr + size - 1 <= *dev->dma_mask;
59
60 return 1;
61}
62
63static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
64{
65 return paddr;
66}
67
68static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
69{
70 return daddr;
71}
72
73static inline void dma_mark_clean(void *addr, size_t size) {}
74
75static inline int dma_set_mask(struct device *dev, u64 dma_mask)
76{
77 if (!dev->dma_mask || !dma_supported(dev, dma_mask))
78 return -EIO;
79
80 *dev->dma_mask = dma_mask;
81
82 return 0;
83}
84
85static inline void *dma_alloc_coherent(struct device *dev, size_t size,
86 dma_addr_t *dma_handle, gfp_t flag)
87{
88 struct dma_map_ops *dma_ops = get_dma_ops(dev);
89
90 return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
91}
92
93static inline void dma_free_coherent(struct device *dev, size_t size,
94 void *cpu_addr, dma_addr_t dma_handle)
95{
96 struct dma_map_ops *dma_ops = get_dma_ops(dev);
97
98 dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
99}
100
101#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
102#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
103
104static inline void dma_cache_sync(struct device *dev, void *vaddr,
105 size_t size, enum dma_data_direction direction)
106{
107 unsigned long start = (unsigned long)vaddr;
108 unsigned long end = start + size;
109
110 switch (direction) {
111 case DMA_NONE:
112 BUG();
113 case DMA_FROM_DEVICE:
114 case DMA_BIDIRECTIONAL: /* writeback and invalidate */
115 __cpuc_dma_flush_range(start, end);
116 break;
117 case DMA_TO_DEVICE: /* writeback only */
118 __cpuc_dma_clean_range(start, end);
119 break;
120 }
121}
122
123#endif /* __KERNEL__ */
124#endif
diff --git a/arch/unicore32/include/asm/dma.h b/arch/unicore32/include/asm/dma.h
new file mode 100644
index 00000000000..38dfff9df32
--- /dev/null
+++ b/arch/unicore32/include/asm/dma.h
@@ -0,0 +1,23 @@
1/*
2 * linux/arch/unicore32/include/asm/dma.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_DMA_H__
14#define __UNICORE_DMA_H__
15
16#include <asm/memory.h>
17#include <asm-generic/dma.h>
18
19#ifdef CONFIG_PCI
20extern int isa_dma_bridge_buggy;
21#endif
22
23#endif /* __UNICORE_DMA_H__ */
diff --git a/arch/unicore32/include/asm/elf.h b/arch/unicore32/include/asm/elf.h
new file mode 100644
index 00000000000..829042d0772
--- /dev/null
+++ b/arch/unicore32/include/asm/elf.h
@@ -0,0 +1,94 @@
1/*
2 * linux/arch/unicore32/include/asm/elf.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_ELF_H__
14#define __UNICORE_ELF_H__
15
16#include <asm/hwcap.h>
17
18/*
19 * ELF register definitions..
20 */
21#include <asm/ptrace.h>
22
23typedef unsigned long elf_greg_t;
24typedef unsigned long elf_freg_t[3];
25
26#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
27typedef elf_greg_t elf_gregset_t[ELF_NGREG];
28
29typedef struct fp_state elf_fpregset_t;
30
31#define EM_UNICORE 110
32
33#define R_UNICORE_NONE 0
34#define R_UNICORE_PC24 1
35#define R_UNICORE_ABS32 2
36#define R_UNICORE_CALL 28
37#define R_UNICORE_JUMP24 29
38
39/*
40 * These are used to set parameters in the core dumps.
41 */
42#define ELF_CLASS ELFCLASS32
43#define ELF_DATA ELFDATA2LSB
44#define ELF_ARCH EM_UNICORE
45
46/*
47 * This yields a string that ld.so will use to load implementation
48 * specific libraries for optimization. This is more specific in
49 * intent than poking at uname or /proc/cpuinfo.
50 *
51 */
52#define ELF_PLATFORM_SIZE 8
53#define ELF_PLATFORM (elf_platform)
54
55extern char elf_platform[];
56
57struct elf32_hdr;
58
59/*
60 * This is used to ensure we don't load something for the wrong architecture.
61 */
62extern int elf_check_arch(const struct elf32_hdr *);
63#define elf_check_arch elf_check_arch
64
65struct task_struct;
66int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
67#define ELF_CORE_COPY_TASK_REGS dump_task_regs
68
69#define ELF_EXEC_PAGESIZE 4096
70
71/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
72 use of this is to invoke "./ld.so someprog" to test out a new version of
73 the loader. We need to make sure that it is out of the way of the program
74 that it will "exec", and that there is sufficient room for the brk. */
75
76#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
77
78/* When the program starts, a1 contains a pointer to a function to be
79 registered with atexit, as per the SVR4 ABI. A value of 0 means we
80 have no such handler. */
81#define ELF_PLAT_INIT(_r, load_addr) {(_r)->UCreg_00 = 0; }
82
83extern void elf_set_personality(const struct elf32_hdr *);
84#define SET_PERSONALITY(ex) elf_set_personality(&(ex))
85
86struct mm_struct;
87extern unsigned long arch_randomize_brk(struct mm_struct *mm);
88#define arch_randomize_brk arch_randomize_brk
89
90extern int vectors_user_mapping(void);
91#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
92#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
93
94#endif
diff --git a/arch/unicore32/include/asm/fpstate.h b/arch/unicore32/include/asm/fpstate.h
new file mode 100644
index 00000000000..ba97fac6220
--- /dev/null
+++ b/arch/unicore32/include/asm/fpstate.h
@@ -0,0 +1,26 @@
1/*
2 * linux/arch/unicore32/include/asm/fpstate.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_FPSTATE_H__
14#define __UNICORE_FPSTATE_H__
15
16#ifndef __ASSEMBLY__
17
18#define FP_REGS_NUMBER 33
19
20struct fp_state {
21 unsigned int regs[FP_REGS_NUMBER];
22} __attribute__((aligned(8)));
23
24#endif
25
26#endif
diff --git a/arch/unicore32/include/asm/fpu-ucf64.h b/arch/unicore32/include/asm/fpu-ucf64.h
new file mode 100644
index 00000000000..16c1457882e
--- /dev/null
+++ b/arch/unicore32/include/asm/fpu-ucf64.h
@@ -0,0 +1,53 @@
1/*
2 * linux/arch/unicore32/include/asm/fpu-ucf64.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#define FPSCR s31
14
15/* FPSCR bits */
16#define FPSCR_DEFAULT_NAN (1<<25)
17
18#define FPSCR_CMPINSTR_BIT (1<<31)
19
20#define FPSCR_CON (1<<29)
21#define FPSCR_TRAP (1<<27)
22
23/* RND mode */
24#define FPSCR_ROUND_NEAREST (0<<0)
25#define FPSCR_ROUND_PLUSINF (2<<0)
26#define FPSCR_ROUND_MINUSINF (3<<0)
27#define FPSCR_ROUND_TOZERO (1<<0)
28#define FPSCR_RMODE_BIT (0)
29#define FPSCR_RMODE_MASK (7 << FPSCR_RMODE_BIT)
30
31/* trap enable */
32#define FPSCR_IOE (1<<16)
33#define FPSCR_OFE (1<<14)
34#define FPSCR_UFE (1<<13)
35#define FPSCR_IXE (1<<12)
36#define FPSCR_HIE (1<<11)
37#define FPSCR_NDE (1<<10) /* non denomal */
38
39/* flags */
40#define FPSCR_IDC (1<<24)
41#define FPSCR_HIC (1<<23)
42#define FPSCR_IXC (1<<22)
43#define FPSCR_OFC (1<<21)
44#define FPSCR_UFC (1<<20)
45#define FPSCR_IOC (1<<19)
46
47/* stick bits */
48#define FPSCR_IOS (1<<9)
49#define FPSCR_OFS (1<<7)
50#define FPSCR_UFS (1<<6)
51#define FPSCR_IXS (1<<5)
52#define FPSCR_HIS (1<<4)
53#define FPSCR_NDS (1<<3) /*non denomal */
diff --git a/arch/unicore32/include/asm/futex.h b/arch/unicore32/include/asm/futex.h
new file mode 100644
index 00000000000..07dea617055
--- /dev/null
+++ b/arch/unicore32/include/asm/futex.h
@@ -0,0 +1,143 @@
1/*
2 * linux/arch/unicore32/include/asm/futex.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_FUTEX_H__
14#define __UNICORE_FUTEX_H__
15
16#ifdef __KERNEL__
17
18#include <linux/futex.h>
19#include <linux/preempt.h>
20#include <linux/uaccess.h>
21#include <linux/errno.h>
22
23#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
24 __asm__ __volatile__( \
25 "1: ldw.u %1, [%2]\n" \
26 " " insn "\n" \
27 "2: stw.u %0, [%2]\n" \
28 " mov %0, #0\n" \
29 "3:\n" \
30 " .pushsection __ex_table,\"a\"\n" \
31 " .align 3\n" \
32 " .long 1b, 4f, 2b, 4f\n" \
33 " .popsection\n" \
34 " .pushsection .fixup,\"ax\"\n" \
35 "4: mov %0, %4\n" \
36 " b 3b\n" \
37 " .popsection" \
38 : "=&r" (ret), "=&r" (oldval) \
39 : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
40 : "cc", "memory")
41
42static inline int
43futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
44{
45 int op = (encoded_op >> 28) & 7;
46 int cmp = (encoded_op >> 24) & 15;
47 int oparg = (encoded_op << 8) >> 20;
48 int cmparg = (encoded_op << 20) >> 20;
49 int oldval = 0, ret;
50
51 if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
52 oparg = 1 << oparg;
53
54 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
55 return -EFAULT;
56
57 pagefault_disable(); /* implies preempt_disable() */
58
59 switch (op) {
60 case FUTEX_OP_SET:
61 __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
62 break;
63 case FUTEX_OP_ADD:
64 __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
65 break;
66 case FUTEX_OP_OR:
67 __futex_atomic_op("or %0, %1, %3", ret, oldval, uaddr, oparg);
68 break;
69 case FUTEX_OP_ANDN:
70 __futex_atomic_op("and %0, %1, %3",
71 ret, oldval, uaddr, ~oparg);
72 break;
73 case FUTEX_OP_XOR:
74 __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg);
75 break;
76 default:
77 ret = -ENOSYS;
78 }
79
80 pagefault_enable(); /* subsumes preempt_enable() */
81
82 if (!ret) {
83 switch (cmp) {
84 case FUTEX_OP_CMP_EQ:
85 ret = (oldval == cmparg);
86 break;
87 case FUTEX_OP_CMP_NE:
88 ret = (oldval != cmparg);
89 break;
90 case FUTEX_OP_CMP_LT:
91 ret = (oldval < cmparg);
92 break;
93 case FUTEX_OP_CMP_GE:
94 ret = (oldval >= cmparg);
95 break;
96 case FUTEX_OP_CMP_LE:
97 ret = (oldval <= cmparg);
98 break;
99 case FUTEX_OP_CMP_GT:
100 ret = (oldval > cmparg);
101 break;
102 default:
103 ret = -ENOSYS;
104 }
105 }
106 return ret;
107}
108
109static inline int
110futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
111{
112 int val;
113
114 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
115 return -EFAULT;
116
117 pagefault_disable(); /* implies preempt_disable() */
118
119 __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
120 "1: ldw.u %0, [%3]\n"
121 " cmpxor.a %0, %1\n"
122 " bne 3f\n"
123 "2: stw.u %2, [%3]\n"
124 "3:\n"
125 " .pushsection __ex_table,\"a\"\n"
126 " .align 3\n"
127 " .long 1b, 4f, 2b, 4f\n"
128 " .popsection\n"
129 " .pushsection .fixup,\"ax\"\n"
130 "4: mov %0, %4\n"
131 " b 3b\n"
132 " .popsection"
133 : "=&r" (val)
134 : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
135 : "cc", "memory");
136
137 pagefault_enable(); /* subsumes preempt_enable() */
138
139 return val;
140}
141
142#endif /* __KERNEL__ */
143#endif /* __UNICORE_FUTEX_H__ */
diff --git a/arch/unicore32/include/asm/gpio.h b/arch/unicore32/include/asm/gpio.h
new file mode 100644
index 00000000000..2716f14e3ff
--- /dev/null
+++ b/arch/unicore32/include/asm/gpio.h
@@ -0,0 +1,104 @@
1/*
2 * linux/arch/unicore32/include/asm/gpio.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_GPIO_H__
14#define __UNICORE_GPIO_H__
15
16#include <linux/io.h>
17#include <asm/irq.h>
18#include <mach/hardware.h>
19#include <asm-generic/gpio.h>
20
21#define GPI_OTP_INT 0
22#define GPI_PCI_INTA 1
23#define GPI_PCI_INTB 2
24#define GPI_PCI_INTC 3
25#define GPI_PCI_INTD 4
26#define GPI_BAT_DET 5
27#define GPI_SD_CD 6
28#define GPI_SOFF_REQ 7
29#define GPI_SD_WP 8
30#define GPI_LCD_CASE_OFF 9
31#define GPO_WIFI_EN 10
32#define GPO_HDD_LED 11
33#define GPO_VGA_EN 12
34#define GPO_LCD_EN 13
35#define GPO_LED_DATA 14
36#define GPO_LED_CLK 15
37#define GPO_CAM_PWR_EN 16
38#define GPO_LCD_VCC_EN 17
39#define GPO_SOFT_OFF 18
40#define GPO_BT_EN 19
41#define GPO_FAN_ON 20
42#define GPO_SPKR 21
43#define GPO_SET_V1 23
44#define GPO_SET_V2 24
45#define GPO_CPU_HEALTH 25
46#define GPO_LAN_SEL 26
47
48#ifdef CONFIG_PUV3_NB0916
49#define GPI_BTN_TOUCH 14
50#define GPIO_IN 0x000043ff /* 1 for input */
51#define GPIO_OUT 0x0fffbc00 /* 1 for output */
52#endif /* CONFIG_PUV3_NB0916 */
53
54#ifdef CONFIG_PUV3_SMW0919
55#define GPIO_IN 0x000003ff /* 1 for input */
56#define GPIO_OUT 0x0ffffc00 /* 1 for output */
57#endif /* CONFIG_PUV3_SMW0919 */
58
59#ifdef CONFIG_PUV3_DB0913
60#define GPIO_IN 0x000001df /* 1 for input */
61#define GPIO_OUT 0x03fee800 /* 1 for output */
62#endif /* CONFIG_PUV3_DB0913 */
63
64#define GPIO_DIR (~((GPIO_IN) | 0xf0000000))
65 /* 0 input, 1 output */
66
67static inline int gpio_get_value(unsigned gpio)
68{
69 if (__builtin_constant_p(gpio) && (gpio <= GPIO_MAX))
70 return readl(GPIO_GPLR) & GPIO_GPIO(gpio);
71 else
72 return __gpio_get_value(gpio);
73}
74
75static inline void gpio_set_value(unsigned gpio, int value)
76{
77 if (__builtin_constant_p(gpio) && (gpio <= GPIO_MAX))
78 if (value)
79 writel(GPIO_GPIO(gpio), GPIO_GPSR);
80 else
81 writel(GPIO_GPIO(gpio), GPIO_GPCR);
82 else
83 __gpio_set_value(gpio, value);
84}
85
86#define gpio_cansleep __gpio_cansleep
87
88static inline unsigned gpio_to_irq(unsigned gpio)
89{
90 if ((gpio < IRQ_GPIOHIGH) && (FIELD(1, 1, gpio) & readl(GPIO_GPIR)))
91 return IRQ_GPIOLOW0 + gpio;
92 else
93 return IRQ_GPIO0 + gpio;
94}
95
96static inline unsigned irq_to_gpio(unsigned irq)
97{
98 if (irq < IRQ_GPIOHIGH)
99 return irq - IRQ_GPIOLOW0;
100 else
101 return irq - IRQ_GPIO0;
102}
103
104#endif /* __UNICORE_GPIO_H__ */
diff --git a/arch/unicore32/include/asm/hwcap.h b/arch/unicore32/include/asm/hwcap.h
new file mode 100644
index 00000000000..97bd40fdd4a
--- /dev/null
+++ b/arch/unicore32/include/asm/hwcap.h
@@ -0,0 +1,32 @@
1/*
2 * linux/arch/unicore32/include/asm/hwcap.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_HWCAP_H__
13#define __UNICORE_HWCAP_H__
14
15/*
16 * HWCAP flags
17 */
18#define HWCAP_MSP 1
19#define HWCAP_UNICORE16 2
20#define HWCAP_CMOV 4
21#define HWCAP_UNICORE_F64 8
22#define HWCAP_TLS 0x80
23
24#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
25/*
26 * This yields a mask that user programs can use to figure out what
27 * instruction set this cpu supports.
28 */
29#define ELF_HWCAP (HWCAP_CMOV | HWCAP_UNICORE_F64)
30#endif
31
32#endif
diff --git a/arch/unicore32/include/asm/io.h b/arch/unicore32/include/asm/io.h
new file mode 100644
index 00000000000..4bd87f3d13d
--- /dev/null
+++ b/arch/unicore32/include/asm/io.h
@@ -0,0 +1,55 @@
1/*
2 * linux/arch/unicore32/include/asm/io.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_IO_H__
13#define __UNICORE_IO_H__
14
15#ifdef __KERNEL__
16
17#include <asm/byteorder.h>
18#include <asm/memory.h>
19#include <asm/system.h>
20
21#define PCI_IOBASE PKUNITY_PCILIO_BASE
22#include <asm-generic/io.h>
23
24/*
25 * __uc32_ioremap and __uc32_ioremap_cached takes CPU physical address.
26 */
27extern void __iomem *__uc32_ioremap(unsigned long, size_t);
28extern void __iomem *__uc32_ioremap_cached(unsigned long, size_t);
29extern void __uc32_iounmap(volatile void __iomem *addr);
30
31/*
32 * ioremap and friends.
33 *
34 * ioremap takes a PCI memory address, as specified in
35 * Documentation/IO-mapping.txt.
36 *
37 */
38#define ioremap(cookie, size) __uc32_ioremap(cookie, size)
39#define ioremap_cached(cookie, size) __uc32_ioremap_cached(cookie, size)
40#define iounmap(cookie) __uc32_iounmap(cookie)
41
42/*
43 * Convert a physical pointer to a virtual kernel pointer for /dev/mem
44 * access
45 */
46#undef xlate_dev_mem_ptr
47#define xlate_dev_mem_ptr(p) __va(p)
48
49#define HAVE_ARCH_PIO_SIZE
50#define PIO_OFFSET (unsigned int)(PCI_IOBASE)
51#define PIO_MASK (unsigned int)(IO_SPACE_LIMIT)
52#define PIO_RESERVED (PIO_OFFSET + PIO_MASK + 1)
53
54#endif /* __KERNEL__ */
55#endif /* __UNICORE_IO_H__ */
diff --git a/arch/unicore32/include/asm/irq.h b/arch/unicore32/include/asm/irq.h
new file mode 100644
index 00000000000..baea93e2a6e
--- /dev/null
+++ b/arch/unicore32/include/asm/irq.h
@@ -0,0 +1,105 @@
1/*
2 * linux/arch/unicore32/include/asm/irq.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_IRQ_H__
13#define __UNICORE_IRQ_H__
14
15#include <asm-generic/irq.h>
16
17#define IRQ_GPIOLOW0 0x00
18#define IRQ_GPIOLOW1 0x01
19#define IRQ_GPIOLOW2 0x02
20#define IRQ_GPIOLOW3 0x03
21#define IRQ_GPIOLOW4 0x04
22#define IRQ_GPIOLOW5 0x05
23#define IRQ_GPIOLOW6 0x06
24#define IRQ_GPIOLOW7 0x07
25#define IRQ_GPIOHIGH 0x08
26#define IRQ_USB 0x09
27#define IRQ_SDC 0x0a
28#define IRQ_AC97 0x0b
29#define IRQ_SATA 0x0c
30#define IRQ_MME 0x0d
31#define IRQ_PCI_BRIDGE 0x0e
32#define IRQ_DDR 0x0f
33#define IRQ_SPI 0x10
34#define IRQ_UNIGFX 0x11
35#define IRQ_I2C 0x11
36#define IRQ_UART1 0x12
37#define IRQ_UART0 0x13
38#define IRQ_UMAL 0x14
39#define IRQ_NAND 0x15
40#define IRQ_PS2_KBD 0x16
41#define IRQ_PS2_AUX 0x17
42#define IRQ_DMA 0x18
43#define IRQ_DMAERR 0x19
44#define IRQ_TIMER0 0x1a
45#define IRQ_TIMER1 0x1b
46#define IRQ_TIMER2 0x1c
47#define IRQ_TIMER3 0x1d
48#define IRQ_RTC 0x1e
49#define IRQ_RTCAlarm 0x1f
50
51#define IRQ_GPIO0 0x20
52#define IRQ_GPIO1 0x21
53#define IRQ_GPIO2 0x22
54#define IRQ_GPIO3 0x23
55#define IRQ_GPIO4 0x24
56#define IRQ_GPIO5 0x25
57#define IRQ_GPIO6 0x26
58#define IRQ_GPIO7 0x27
59#define IRQ_GPIO8 0x28
60#define IRQ_GPIO9 0x29
61#define IRQ_GPIO10 0x2a
62#define IRQ_GPIO11 0x2b
63#define IRQ_GPIO12 0x2c
64#define IRQ_GPIO13 0x2d
65#define IRQ_GPIO14 0x2e
66#define IRQ_GPIO15 0x2f
67#define IRQ_GPIO16 0x30
68#define IRQ_GPIO17 0x31
69#define IRQ_GPIO18 0x32
70#define IRQ_GPIO19 0x33
71#define IRQ_GPIO20 0x34
72#define IRQ_GPIO21 0x35
73#define IRQ_GPIO22 0x36
74#define IRQ_GPIO23 0x37
75#define IRQ_GPIO24 0x38
76#define IRQ_GPIO25 0x39
77#define IRQ_GPIO26 0x3a
78#define IRQ_GPIO27 0x3b
79
80#ifdef CONFIG_ARCH_FPGA
81#define IRQ_PCIINTA IRQ_GPIOLOW2
82#define IRQ_PCIINTB IRQ_GPIOLOW1
83#define IRQ_PCIINTC IRQ_GPIOLOW0
84#define IRQ_PCIINTD IRQ_GPIOLOW6
85#endif
86
87#if defined(CONFIG_PUV3_DB0913) || defined(CONFIG_PUV3_NB0916) \
88 || defined(CONFIG_PUV3_SMW0919)
89#define IRQ_PCIINTA IRQ_GPIOLOW1
90#define IRQ_PCIINTB IRQ_GPIOLOW2
91#define IRQ_PCIINTC IRQ_GPIOLOW3
92#define IRQ_PCIINTD IRQ_GPIOLOW4
93#endif
94
95#define IRQ_SD_CD IRQ_GPIO6 /* falling or rising trigger */
96
97#ifndef __ASSEMBLY__
98struct pt_regs;
99
100extern void asm_do_IRQ(unsigned int, struct pt_regs *);
101
102#endif
103
104#endif
105
diff --git a/arch/unicore32/include/asm/irqflags.h b/arch/unicore32/include/asm/irqflags.h
new file mode 100644
index 00000000000..6d8a28dfdba
--- /dev/null
+++ b/arch/unicore32/include/asm/irqflags.h
@@ -0,0 +1,53 @@
1/*
2 * linux/arch/unicore32/include/asm/irqflags.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_IRQFLAGS_H__
13#define __UNICORE_IRQFLAGS_H__
14
15#ifdef __KERNEL__
16
17#include <asm/ptrace.h>
18
19#define ARCH_IRQ_DISABLED (PRIV_MODE | PSR_I_BIT)
20#define ARCH_IRQ_ENABLED (PRIV_MODE)
21
22/*
23 * Save the current interrupt enable state.
24 */
25static inline unsigned long arch_local_save_flags(void)
26{
27 unsigned long temp;
28
29 asm volatile("mov %0, asr" : "=r" (temp) : : "memory", "cc");
30
31 return temp & PSR_c;
32}
33
34/*
35 * restore saved IRQ state
36 */
37static inline void arch_local_irq_restore(unsigned long flags)
38{
39 unsigned long temp;
40
41 asm volatile(
42 "mov %0, asr\n"
43 "mov.a asr, %1\n"
44 "mov.f asr, %0"
45 : "=&r" (temp)
46 : "r" (flags)
47 : "memory", "cc");
48}
49
50#include <asm-generic/irqflags.h>
51
52#endif
53#endif
diff --git a/arch/unicore32/include/asm/linkage.h b/arch/unicore32/include/asm/linkage.h
new file mode 100644
index 00000000000..d1618bd35b6
--- /dev/null
+++ b/arch/unicore32/include/asm/linkage.h
@@ -0,0 +1,22 @@
1/*
2 * linux/arch/unicore32/include/asm/linkage.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_LINKAGE_H__
13#define __UNICORE_LINKAGE_H__
14
15#define __ALIGN .align 0
16#define __ALIGN_STR ".align 0"
17
18#define ENDPROC(name) \
19 .type name, %function; \
20 END(name)
21
22#endif
diff --git a/arch/unicore32/include/asm/memblock.h b/arch/unicore32/include/asm/memblock.h
new file mode 100644
index 00000000000..a8a5d8d0a26
--- /dev/null
+++ b/arch/unicore32/include/asm/memblock.h
@@ -0,0 +1,46 @@
1/*
2 * linux/arch/unicore32/include/asm/memblock.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_MEMBLOCK_H__
14#define __UNICORE_MEMBLOCK_H__
15
16/*
17 * Memory map description
18 */
19# define NR_BANKS 8
20
21struct membank {
22 unsigned long start;
23 unsigned long size;
24 unsigned int highmem;
25};
26
27struct meminfo {
28 int nr_banks;
29 struct membank bank[NR_BANKS];
30};
31
32extern struct meminfo meminfo;
33
34#define for_each_bank(iter, mi) \
35 for (iter = 0; iter < (mi)->nr_banks; iter++)
36
37#define bank_pfn_start(bank) __phys_to_pfn((bank)->start)
38#define bank_pfn_end(bank) __phys_to_pfn((bank)->start + (bank)->size)
39#define bank_pfn_size(bank) ((bank)->size >> PAGE_SHIFT)
40#define bank_phys_start(bank) ((bank)->start)
41#define bank_phys_end(bank) ((bank)->start + (bank)->size)
42#define bank_phys_size(bank) ((bank)->size)
43
44extern void uc32_memblock_init(struct meminfo *);
45
46#endif
diff --git a/arch/unicore32/include/asm/memory.h b/arch/unicore32/include/asm/memory.h
new file mode 100644
index 00000000000..5eddb997def
--- /dev/null
+++ b/arch/unicore32/include/asm/memory.h
@@ -0,0 +1,123 @@
1/*
2 * linux/arch/unicore32/include/asm/memory.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Note: this file should not be included by non-asm/.h files
13 */
14#ifndef __UNICORE_MEMORY_H__
15#define __UNICORE_MEMORY_H__
16
17#include <linux/compiler.h>
18#include <linux/const.h>
19#include <asm/sizes.h>
20#include <mach/memory.h>
21
22/*
23 * Allow for constants defined here to be used from assembly code
24 * by prepending the UL suffix only with actual C code compilation.
25 */
26#define UL(x) _AC(x, UL)
27
28/*
29 * PAGE_OFFSET - the virtual address of the start of the kernel image
30 * TASK_SIZE - the maximum size of a user space task.
31 * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
32 */
33#define PAGE_OFFSET UL(0xC0000000)
34#define TASK_SIZE (PAGE_OFFSET - UL(0x41000000))
35#define TASK_UNMAPPED_BASE (PAGE_OFFSET / 3)
36
37/*
38 * The module space lives between the addresses given by TASK_SIZE
39 * and PAGE_OFFSET - it must be within 32MB of the kernel text.
40 */
41#define MODULES_VADDR (PAGE_OFFSET - 16*1024*1024)
42#if TASK_SIZE > MODULES_VADDR
43#error Top of user space clashes with start of module space
44#endif
45
46#define MODULES_END (PAGE_OFFSET)
47
48/*
49 * Allow 16MB-aligned ioremap pages
50 */
51#define IOREMAP_MAX_ORDER 24
52
53/*
54 * Physical vs virtual RAM address space conversion. These are
55 * private definitions which should NOT be used outside memory.h
56 * files. Use virt_to_phys/phys_to_virt/__pa/__va instead.
57 */
58#ifndef __virt_to_phys
59#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
60#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
61#endif
62
63/*
64 * Convert a physical address to a Page Frame Number and back
65 */
66#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT)
67#define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
68
69/*
70 * Convert a page to/from a physical address
71 */
72#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
73#define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys)))
74
75#ifndef __ASSEMBLY__
76
77#ifndef arch_adjust_zones
78#define arch_adjust_zones(size, holes) do { } while (0)
79#endif
80
81/*
82 * PFNs are used to describe any physical page; this means
83 * PFN 0 == physical address 0.
84 *
85 * This is the PFN of the first RAM page in the kernel
86 * direct-mapped view. We assume this is the first page
87 * of RAM in the mem_map as well.
88 */
89#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
90
91/*
92 * Drivers should NOT use these either.
93 */
94#define __pa(x) __virt_to_phys((unsigned long)(x))
95#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
96#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
97
98/*
99 * Conversion between a struct page and a physical address.
100 *
101 * Note: when converting an unknown physical address to a
102 * struct page, the resulting pointer must be validated
103 * using VALID_PAGE(). It must return an invalid struct page
104 * for any physical address not corresponding to a system
105 * RAM address.
106 *
107 * page_to_pfn(page) convert a struct page * to a PFN number
108 * pfn_to_page(pfn) convert a _valid_ PFN number to struct page *
109 *
110 * virt_to_page(k) convert a _valid_ virtual address to struct page *
111 * virt_addr_valid(k) indicates whether a virtual address is valid
112 */
113#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET
114
115#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
116#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && \
117 (unsigned long)(kaddr) < (unsigned long)high_memory)
118
119#endif
120
121#include <asm-generic/memory_model.h>
122
123#endif
diff --git a/arch/unicore32/include/asm/mmu.h b/arch/unicore32/include/asm/mmu.h
new file mode 100644
index 00000000000..66fa341dc2c
--- /dev/null
+++ b/arch/unicore32/include/asm/mmu.h
@@ -0,0 +1,17 @@
1/*
2 * linux/arch/unicore32/include/asm/mmu.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_MMU_H__
13#define __UNICORE_MMU_H__
14
15typedef unsigned long mm_context_t;
16
17#endif
diff --git a/arch/unicore32/include/asm/mmu_context.h b/arch/unicore32/include/asm/mmu_context.h
new file mode 100644
index 00000000000..fb5e4c658f7
--- /dev/null
+++ b/arch/unicore32/include/asm/mmu_context.h
@@ -0,0 +1,87 @@
1/*
2 * linux/arch/unicore32/include/asm/mmu_context.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_MMU_CONTEXT_H__
13#define __UNICORE_MMU_CONTEXT_H__
14
15#include <linux/compiler.h>
16#include <linux/sched.h>
17#include <linux/io.h>
18
19#include <asm/cacheflush.h>
20#include <asm/cpu-single.h>
21
22#define init_new_context(tsk, mm) 0
23
24#define destroy_context(mm) do { } while (0)
25
26/*
27 * This is called when "tsk" is about to enter lazy TLB mode.
28 *
29 * mm: describes the currently active mm context
30 * tsk: task which is entering lazy tlb
31 * cpu: cpu number which is entering lazy tlb
32 *
33 * tsk->mm will be NULL
34 */
35static inline void
36enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
37{
38}
39
40/*
41 * This is the actual mm switch as far as the scheduler
42 * is concerned. No registers are touched. We avoid
43 * calling the CPU specific function when the mm hasn't
44 * actually changed.
45 */
46static inline void
47switch_mm(struct mm_struct *prev, struct mm_struct *next,
48 struct task_struct *tsk)
49{
50 unsigned int cpu = smp_processor_id();
51
52 if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
53 cpu_switch_mm(next->pgd, next);
54}
55
56#define deactivate_mm(tsk, mm) do { } while (0)
57#define activate_mm(prev, next) switch_mm(prev, next, NULL)
58
59/*
60 * We are inserting a "fake" vma for the user-accessible vector page so
61 * gdb and friends can get to it through ptrace and /proc/<pid>/mem.
62 * But we also want to remove it before the generic code gets to see it
63 * during process exit or the unmapping of it would cause total havoc.
64 * (the macro is used as remove_vma() is static to mm/mmap.c)
65 */
66#define arch_exit_mmap(mm) \
67do { \
68 struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
69 if (high_vma) { \
70 BUG_ON(high_vma->vm_next); /* it should be last */ \
71 if (high_vma->vm_prev) \
72 high_vma->vm_prev->vm_next = NULL; \
73 else \
74 mm->mmap = NULL; \
75 rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
76 mm->mmap_cache = NULL; \
77 mm->map_count--; \
78 remove_vma(high_vma); \
79 } \
80} while (0)
81
82static inline void arch_dup_mmap(struct mm_struct *oldmm,
83 struct mm_struct *mm)
84{
85}
86
87#endif
diff --git a/arch/unicore32/include/asm/mutex.h b/arch/unicore32/include/asm/mutex.h
new file mode 100644
index 00000000000..fab7d0e8adf
--- /dev/null
+++ b/arch/unicore32/include/asm/mutex.h
@@ -0,0 +1,20 @@
1/*
2 * linux/arch/unicore32/include/asm/mutex.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * UniCore optimized mutex locking primitives
13 *
14 * Please look into asm-generic/mutex-xchg.h for a formal definition.
15 */
16#ifndef __UNICORE_MUTEX_H__
17#define __UNICORE_MUTEX_H__
18
19# include <asm-generic/mutex-xchg.h>
20#endif
diff --git a/arch/unicore32/include/asm/page.h b/arch/unicore32/include/asm/page.h
new file mode 100644
index 00000000000..594b3226250
--- /dev/null
+++ b/arch/unicore32/include/asm/page.h
@@ -0,0 +1,80 @@
1/*
2 * linux/arch/unicore32/include/asm/page.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PAGE_H__
13#define __UNICORE_PAGE_H__
14
15/* PAGE_SHIFT determines the page size */
16#define PAGE_SHIFT 12
17#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
18#define PAGE_MASK (~(PAGE_SIZE-1))
19
20#ifndef __ASSEMBLY__
21
22struct page;
23struct vm_area_struct;
24
25#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
26extern void copy_page(void *to, const void *from);
27
28#define clear_user_page(page, vaddr, pg) clear_page(page)
29#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
30
31#undef STRICT_MM_TYPECHECKS
32
33#ifdef STRICT_MM_TYPECHECKS
34/*
35 * These are used to make use of C type-checking..
36 */
37typedef struct { unsigned long pte; } pte_t;
38typedef struct { unsigned long pgd; } pgd_t;
39typedef struct { unsigned long pgprot; } pgprot_t;
40
41#define pte_val(x) ((x).pte)
42#define pgd_val(x) ((x).pgd)
43#define pgprot_val(x) ((x).pgprot)
44
45#define __pte(x) ((pte_t) { (x) })
46#define __pgd(x) ((pgd_t) { (x) })
47#define __pgprot(x) ((pgprot_t) { (x) })
48
49#else
50/*
51 * .. while these make it easier on the compiler
52 */
53typedef unsigned long pte_t;
54typedef unsigned long pgd_t;
55typedef unsigned long pgprot_t;
56
57#define pte_val(x) (x)
58#define pgd_val(x) (x)
59#define pgprot_val(x) (x)
60
61#define __pte(x) (x)
62#define __pgd(x) (x)
63#define __pgprot(x) (x)
64
65#endif /* STRICT_MM_TYPECHECKS */
66
67typedef struct page *pgtable_t;
68
69extern int pfn_valid(unsigned long);
70
71#include <asm/memory.h>
72
73#endif /* !__ASSEMBLY__ */
74
75#define VM_DATA_DEFAULT_FLAGS \
76 (VM_READ | VM_WRITE | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
77
78#include <asm-generic/getorder.h>
79
80#endif
diff --git a/arch/unicore32/include/asm/pci.h b/arch/unicore32/include/asm/pci.h
new file mode 100644
index 00000000000..c5b28b45953
--- /dev/null
+++ b/arch/unicore32/include/asm/pci.h
@@ -0,0 +1,46 @@
1/*
2 * linux/arch/unicore32/include/asm/pci.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PCI_H__
13#define __UNICORE_PCI_H__
14
15#ifdef __KERNEL__
16#include <asm-generic/pci-dma-compat.h>
17#include <asm-generic/pci.h>
18#include <mach/hardware.h> /* for PCIBIOS_MIN_* */
19
20static inline void pcibios_set_master(struct pci_dev *dev)
21{
22 /* No special bus mastering setup handling */
23}
24
25static inline void pcibios_penalize_isa_irq(int irq, int active)
26{
27 /* We don't do dynamic PCI IRQ allocation */
28}
29
30#ifdef CONFIG_PCI
31static inline void pci_dma_burst_advice(struct pci_dev *pdev,
32 enum pci_dma_burst_strategy *strat,
33 unsigned long *strategy_parameter)
34{
35 *strat = PCI_DMA_BURST_INFINITY;
36 *strategy_parameter = ~0UL;
37}
38#endif
39
40#define HAVE_PCI_MMAP
41extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
42 enum pci_mmap_state mmap_state, int write_combine);
43
44#endif /* __KERNEL__ */
45
46#endif
diff --git a/arch/unicore32/include/asm/pgalloc.h b/arch/unicore32/include/asm/pgalloc.h
new file mode 100644
index 00000000000..0213e373a89
--- /dev/null
+++ b/arch/unicore32/include/asm/pgalloc.h
@@ -0,0 +1,110 @@
1/*
2 * linux/arch/unicore32/include/asm/pgalloc.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PGALLOC_H__
13#define __UNICORE_PGALLOC_H__
14
15#include <asm/pgtable-hwdef.h>
16#include <asm/processor.h>
17#include <asm/cacheflush.h>
18#include <asm/tlbflush.h>
19
20#define check_pgt_cache() do { } while (0)
21
22#define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_PRESENT)
23#define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_PRESENT)
24
25extern pgd_t *get_pgd_slow(struct mm_struct *mm);
26extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd);
27
28#define pgd_alloc(mm) get_pgd_slow(mm)
29#define pgd_free(mm, pgd) free_pgd_slow(mm, pgd)
30
31#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
32
33/*
34 * Allocate one PTE table.
35 */
36static inline pte_t *
37pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
38{
39 pte_t *pte;
40
41 pte = (pte_t *)__get_free_page(PGALLOC_GFP);
42 if (pte)
43 clean_dcache_area(pte, PTRS_PER_PTE * sizeof(pte_t));
44
45 return pte;
46}
47
48static inline pgtable_t
49pte_alloc_one(struct mm_struct *mm, unsigned long addr)
50{
51 struct page *pte;
52
53 pte = alloc_pages(PGALLOC_GFP, 0);
54 if (pte) {
55 if (!PageHighMem(pte)) {
56 void *page = page_address(pte);
57 clean_dcache_area(page, PTRS_PER_PTE * sizeof(pte_t));
58 }
59 pgtable_page_ctor(pte);
60 }
61
62 return pte;
63}
64
65/*
66 * Free one PTE table.
67 */
68static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
69{
70 if (pte)
71 free_page((unsigned long)pte);
72}
73
74static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
75{
76 pgtable_page_dtor(pte);
77 __free_page(pte);
78}
79
80static inline void __pmd_populate(pmd_t *pmdp, unsigned long pmdval)
81{
82 set_pmd(pmdp, __pmd(pmdval));
83 flush_pmd_entry(pmdp);
84}
85
86/*
87 * Populate the pmdp entry with a pointer to the pte. This pmd is part
88 * of the mm address space.
89 */
90static inline void
91pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
92{
93 unsigned long pte_ptr = (unsigned long)ptep;
94
95 /*
96 * The pmd must be loaded with the physical
97 * address of the PTE table
98 */
99 __pmd_populate(pmdp, __pa(pte_ptr) | _PAGE_KERNEL_TABLE);
100}
101
102static inline void
103pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
104{
105 __pmd_populate(pmdp,
106 page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE);
107}
108#define pmd_pgtable(pmd) pmd_page(pmd)
109
110#endif
diff --git a/arch/unicore32/include/asm/pgtable-hwdef.h b/arch/unicore32/include/asm/pgtable-hwdef.h
new file mode 100644
index 00000000000..7314e859cca
--- /dev/null
+++ b/arch/unicore32/include/asm/pgtable-hwdef.h
@@ -0,0 +1,55 @@
1/*
2 * linux/arch/unicore32/include/asm/pgtable-hwdef.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PGTABLE_HWDEF_H__
13#define __UNICORE_PGTABLE_HWDEF_H__
14
15/*
16 * Hardware page table definitions.
17 *
18 * + Level 1 descriptor (PMD)
19 * - common
20 */
21#define PMD_TYPE_MASK (3 << 0)
22#define PMD_TYPE_TABLE (0 << 0)
23/*#define PMD_TYPE_LARGE (1 << 0) */
24#define PMD_TYPE_INVALID (2 << 0)
25#define PMD_TYPE_SECT (3 << 0)
26
27#define PMD_PRESENT (1 << 2)
28#define PMD_YOUNG (1 << 3)
29
30/*#define PMD_SECT_DIRTY (1 << 4) */
31#define PMD_SECT_CACHEABLE (1 << 5)
32#define PMD_SECT_EXEC (1 << 6)
33#define PMD_SECT_WRITE (1 << 7)
34#define PMD_SECT_READ (1 << 8)
35
36/*
37 * + Level 2 descriptor (PTE)
38 * - common
39 */
40#define PTE_TYPE_MASK (3 << 0)
41#define PTE_TYPE_SMALL (0 << 0)
42#define PTE_TYPE_MIDDLE (1 << 0)
43#define PTE_TYPE_LARGE (2 << 0)
44#define PTE_TYPE_INVALID (3 << 0)
45
46#define PTE_PRESENT (1 << 2)
47#define PTE_FILE (1 << 3) /* only when !PRESENT */
48#define PTE_YOUNG (1 << 3)
49#define PTE_DIRTY (1 << 4)
50#define PTE_CACHEABLE (1 << 5)
51#define PTE_EXEC (1 << 6)
52#define PTE_WRITE (1 << 7)
53#define PTE_READ (1 << 8)
54
55#endif
diff --git a/arch/unicore32/include/asm/pgtable.h b/arch/unicore32/include/asm/pgtable.h
new file mode 100644
index 00000000000..68b2f297ac9
--- /dev/null
+++ b/arch/unicore32/include/asm/pgtable.h
@@ -0,0 +1,317 @@
1/*
2 * linux/arch/unicore32/include/asm/pgtable.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PGTABLE_H__
13#define __UNICORE_PGTABLE_H__
14
15#include <asm-generic/pgtable-nopmd.h>
16#include <asm/cpu-single.h>
17
18#include <asm/memory.h>
19#include <asm/pgtable-hwdef.h>
20
21/*
22 * Just any arbitrary offset to the start of the vmalloc VM area: the
23 * current 8MB value just means that there will be a 8MB "hole" after the
24 * physical memory until the kernel virtual memory starts. That means that
25 * any out-of-bounds memory accesses will hopefully be caught.
26 * The vmalloc() routines leaves a hole of 4kB between each vmalloced
27 * area for the same reason. ;)
28 *
29 * Note that platforms may override VMALLOC_START, but they must provide
30 * VMALLOC_END. VMALLOC_END defines the (exclusive) limit of this space,
31 * which may not overlap IO space.
32 */
33#ifndef VMALLOC_START
34#define VMALLOC_OFFSET SZ_8M
35#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) \
36 & ~(VMALLOC_OFFSET-1))
37#define VMALLOC_END (0xff000000UL)
38#endif
39
40#define PTRS_PER_PTE 1024
41#define PTRS_PER_PGD 1024
42
43/*
44 * PGDIR_SHIFT determines what a third-level page table entry can map
45 */
46#define PGDIR_SHIFT 22
47
48#ifndef __ASSEMBLY__
49extern void __pte_error(const char *file, int line, unsigned long val);
50extern void __pgd_error(const char *file, int line, unsigned long val);
51
52#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
53#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
54#endif /* !__ASSEMBLY__ */
55
56#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
57#define PGDIR_MASK (~(PGDIR_SIZE-1))
58
59/*
60 * This is the lowest virtual address we can permit any user space
61 * mapping to be mapped at. This is particularly important for
62 * non-high vector CPUs.
63 */
64#define FIRST_USER_ADDRESS PAGE_SIZE
65
66#define FIRST_USER_PGD_NR 1
67#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
68
69/*
70 * section address mask and size definitions.
71 */
72#define SECTION_SHIFT 22
73#define SECTION_SIZE (1UL << SECTION_SHIFT)
74#define SECTION_MASK (~(SECTION_SIZE-1))
75
76#ifndef __ASSEMBLY__
77
78/*
79 * The pgprot_* and protection_map entries will be fixed up in runtime
80 * to include the cachable bits based on memory policy, as well as any
81 * architecture dependent bits.
82 */
83#define _PTE_DEFAULT (PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE)
84
85extern pgprot_t pgprot_user;
86extern pgprot_t pgprot_kernel;
87
88#define PAGE_NONE pgprot_user
89#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user | PTE_READ \
90 | PTE_WRITE)
91#define PAGE_SHARED_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \
92 | PTE_WRITE \
93 | PTE_EXEC)
94#define PAGE_COPY __pgprot(pgprot_val(pgprot_user | PTE_READ)
95#define PAGE_COPY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \
96 | PTE_EXEC)
97#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user | PTE_READ)
98#define PAGE_READONLY_EXEC __pgprot(pgprot_val(pgprot_user | PTE_READ \
99 | PTE_EXEC)
100#define PAGE_KERNEL pgprot_kernel
101#define PAGE_KERNEL_EXEC __pgprot(pgprot_val(pgprot_kernel | PTE_EXEC))
102
103#define __PAGE_NONE __pgprot(_PTE_DEFAULT)
104#define __PAGE_SHARED __pgprot(_PTE_DEFAULT | PTE_READ \
105 | PTE_WRITE)
106#define __PAGE_SHARED_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \
107 | PTE_WRITE \
108 | PTE_EXEC)
109#define __PAGE_COPY __pgprot(_PTE_DEFAULT | PTE_READ)
110#define __PAGE_COPY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \
111 | PTE_EXEC)
112#define __PAGE_READONLY __pgprot(_PTE_DEFAULT | PTE_READ)
113#define __PAGE_READONLY_EXEC __pgprot(_PTE_DEFAULT | PTE_READ \
114 | PTE_EXEC)
115
116#endif /* __ASSEMBLY__ */
117
118/*
119 * The table below defines the page protection levels that we insert into our
120 * Linux page table version. These get translated into the best that the
121 * architecture can perform. Note that on UniCore hardware:
122 * 1) We cannot do execute protection
123 * 2) If we could do execute protection, then read is implied
124 * 3) write implies read permissions
125 */
126#define __P000 __PAGE_NONE
127#define __P001 __PAGE_READONLY
128#define __P010 __PAGE_COPY
129#define __P011 __PAGE_COPY
130#define __P100 __PAGE_READONLY_EXEC
131#define __P101 __PAGE_READONLY_EXEC
132#define __P110 __PAGE_COPY_EXEC
133#define __P111 __PAGE_COPY_EXEC
134
135#define __S000 __PAGE_NONE
136#define __S001 __PAGE_READONLY
137#define __S010 __PAGE_SHARED
138#define __S011 __PAGE_SHARED
139#define __S100 __PAGE_READONLY_EXEC
140#define __S101 __PAGE_READONLY_EXEC
141#define __S110 __PAGE_SHARED_EXEC
142#define __S111 __PAGE_SHARED_EXEC
143
144#ifndef __ASSEMBLY__
145/*
146 * ZERO_PAGE is a global shared page that is always zero: used
147 * for zero-mapped memory areas etc..
148 */
149extern struct page *empty_zero_page;
150#define ZERO_PAGE(vaddr) (empty_zero_page)
151
152#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
153#define pfn_pte(pfn, prot) (__pte(((pfn) << PAGE_SHIFT) \
154 | pgprot_val(prot)))
155
156#define pte_none(pte) (!pte_val(pte))
157#define pte_clear(mm, addr, ptep) set_pte(ptep, __pte(0))
158#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
159#define pte_offset_kernel(dir, addr) (pmd_page_vaddr(*(dir)) \
160 + __pte_index(addr))
161
162#define pte_offset_map(dir, addr) (pmd_page_vaddr(*(dir)) \
163 + __pte_index(addr))
164#define pte_unmap(pte) do { } while (0)
165
166#define set_pte(ptep, pte) cpu_set_pte(ptep, pte)
167
168#define set_pte_at(mm, addr, ptep, pteval) \
169 do { \
170 set_pte(ptep, pteval); \
171 } while (0)
172
173/*
174 * The following only work if pte_present() is true.
175 * Undefined behaviour if not..
176 */
177#define pte_present(pte) (pte_val(pte) & PTE_PRESENT)
178#define pte_write(pte) (pte_val(pte) & PTE_WRITE)
179#define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY)
180#define pte_young(pte) (pte_val(pte) & PTE_YOUNG)
181#define pte_exec(pte) (pte_val(pte) & PTE_EXEC)
182#define pte_special(pte) (0)
183
184#define PTE_BIT_FUNC(fn, op) \
185static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
186
187PTE_BIT_FUNC(wrprotect, &= ~PTE_WRITE);
188PTE_BIT_FUNC(mkwrite, |= PTE_WRITE);
189PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY);
190PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY);
191PTE_BIT_FUNC(mkold, &= ~PTE_YOUNG);
192PTE_BIT_FUNC(mkyoung, |= PTE_YOUNG);
193
194static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
195
196/*
197 * Mark the prot value as uncacheable.
198 */
199#define pgprot_noncached(prot) \
200 __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
201#define pgprot_writecombine(prot) \
202 __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
203#define pgprot_dmacoherent(prot) \
204 __pgprot(pgprot_val(prot) & ~PTE_CACHEABLE)
205
206#define pmd_none(pmd) (!pmd_val(pmd))
207#define pmd_present(pmd) (pmd_val(pmd) & PMD_PRESENT)
208#define pmd_bad(pmd) (((pmd_val(pmd) & \
209 (PMD_PRESENT | PMD_TYPE_MASK)) \
210 != (PMD_PRESENT | PMD_TYPE_TABLE)))
211
212#define set_pmd(pmdpd, pmdval) \
213 do { \
214 *(pmdpd) = pmdval; \
215 } while (0)
216
217#define pmd_clear(pmdp) \
218 do { \
219 set_pmd(pmdp, __pmd(0));\
220 clean_pmd_entry(pmdp); \
221 } while (0)
222
223#define pmd_page_vaddr(pmd) ((pte_t *)__va(pmd_val(pmd) & PAGE_MASK))
224#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd)))
225
226/*
227 * Conversion functions: convert a page and protection to a page entry,
228 * and a page entry and page directory to the page they refer to.
229 */
230#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
231
232/* to find an entry in a page-table-directory */
233#define pgd_index(addr) ((addr) >> PGDIR_SHIFT)
234
235#define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr))
236
237/* to find an entry in a kernel page-table-directory */
238#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
239
240/* Find an entry in the third-level page table.. */
241#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
242
243static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
244{
245 const unsigned long mask = PTE_EXEC | PTE_WRITE | PTE_READ;
246 pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
247 return pte;
248}
249
250extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
251
252/*
253 * Encode and decode a swap entry. Swap entries are stored in the Linux
254 * page tables as follows:
255 *
256 * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
257 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
258 * <--------------- offset --------------> <--- type --> 0 0 0 0 0
259 *
260 * This gives us up to 127 swap files and 32GB per swap file. Note that
261 * the offset field is always non-zero.
262 */
263#define __SWP_TYPE_SHIFT 5
264#define __SWP_TYPE_BITS 7
265#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
266#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
267
268#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) \
269 & __SWP_TYPE_MASK)
270#define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT)
271#define __swp_entry(type, offset) ((swp_entry_t) { \
272 ((type) << __SWP_TYPE_SHIFT) | \
273 ((offset) << __SWP_OFFSET_SHIFT) })
274
275#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
276#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })
277
278/*
279 * It is an error for the kernel to have more swap files than we can
280 * encode in the PTEs. This ensures that we know when MAX_SWAPFILES
281 * is increased beyond what we presently support.
282 */
283#define MAX_SWAPFILES_CHECK() \
284 BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
285
286/*
287 * Encode and decode a file entry. File entries are stored in the Linux
288 * page tables as follows:
289 *
290 * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
291 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
292 * <----------------------- offset ----------------------> 1 0 0 0
293 */
294#define pte_file(pte) (pte_val(pte) & PTE_FILE)
295#define pte_to_pgoff(x) (pte_val(x) >> 4)
296#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE)
297
298#define PTE_FILE_MAX_BITS 28
299
300/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
301/* FIXME: this is not correct */
302#define kern_addr_valid(addr) (1)
303
304#include <asm-generic/pgtable.h>
305
306/*
307 * remap a physical page `pfn' of size `size' with page protection `prot'
308 * into virtual address `from'
309 */
310#define io_remap_pfn_range(vma, from, pfn, size, prot) \
311 remap_pfn_range(vma, from, pfn, size, prot)
312
313#define pgtable_cache_init() do { } while (0)
314
315#endif /* !__ASSEMBLY__ */
316
317#endif /* __UNICORE_PGTABLE_H__ */
diff --git a/arch/unicore32/include/asm/processor.h b/arch/unicore32/include/asm/processor.h
new file mode 100644
index 00000000000..e11cb078657
--- /dev/null
+++ b/arch/unicore32/include/asm/processor.h
@@ -0,0 +1,92 @@
1/*
2 * linux/arch/unicore32/include/asm/processor.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_PROCESSOR_H__
14#define __UNICORE_PROCESSOR_H__
15
16/*
17 * Default implementation of macro that returns current
18 * instruction pointer ("program counter").
19 */
20#define current_text_addr() ({ __label__ _l; _l: &&_l; })
21
22#ifdef __KERNEL__
23
24#include <asm/ptrace.h>
25#include <asm/types.h>
26
27#ifdef __KERNEL__
28#define STACK_TOP TASK_SIZE
29#define STACK_TOP_MAX TASK_SIZE
30#endif
31
32struct debug_entry {
33 u32 address;
34 u32 insn;
35};
36
37struct debug_info {
38 int nsaved;
39 struct debug_entry bp[2];
40};
41
42struct thread_struct {
43 /* fault info */
44 unsigned long address;
45 unsigned long trap_no;
46 unsigned long error_code;
47 /* debugging */
48 struct debug_info debug;
49};
50
51#define INIT_THREAD { }
52
53#define start_thread(regs, pc, sp) \
54({ \
55 unsigned long *stack = (unsigned long *)sp; \
56 set_fs(USER_DS); \
57 memset(regs->uregs, 0, sizeof(regs->uregs)); \
58 regs->UCreg_asr = USER_MODE; \
59 regs->UCreg_pc = pc & ~1; /* pc */ \
60 regs->UCreg_sp = sp; /* sp */ \
61 regs->UCreg_02 = stack[2]; /* r2 (envp) */ \
62 regs->UCreg_01 = stack[1]; /* r1 (argv) */ \
63 regs->UCreg_00 = stack[0]; /* r0 (argc) */ \
64})
65
66/* Forward declaration, a strange C thing */
67struct task_struct;
68
69/* Free all resources held by a thread. */
70extern void release_thread(struct task_struct *);
71
72/* Prepare to copy thread state - unlazy all lazy status */
73#define prepare_to_copy(tsk) do { } while (0)
74
75unsigned long get_wchan(struct task_struct *p);
76
77#define cpu_relax() barrier()
78
79/*
80 * Create a new kernel thread
81 */
82extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
83
84#define task_pt_regs(p) \
85 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
86
87#define KSTK_EIP(tsk) (task_pt_regs(tsk)->UCreg_pc)
88#define KSTK_ESP(tsk) (task_pt_regs(tsk)->UCreg_sp)
89
90#endif
91
92#endif /* __UNICORE_PROCESSOR_H__ */
diff --git a/arch/unicore32/include/asm/ptrace.h b/arch/unicore32/include/asm/ptrace.h
new file mode 100644
index 00000000000..b9caf9b0997
--- /dev/null
+++ b/arch/unicore32/include/asm/ptrace.h
@@ -0,0 +1,133 @@
1/*
2 * linux/arch/unicore32/include/asm/ptrace.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_PTRACE_H__
13#define __UNICORE_PTRACE_H__
14
15#define PTRACE_GET_THREAD_AREA 22
16
17/*
18 * PSR bits
19 */
20#define USER_MODE 0x00000010
21#define REAL_MODE 0x00000011
22#define INTR_MODE 0x00000012
23#define PRIV_MODE 0x00000013
24#define ABRT_MODE 0x00000017
25#define EXTN_MODE 0x0000001b
26#define SUSR_MODE 0x0000001f
27#define MODE_MASK 0x0000001f
28#define PSR_R_BIT 0x00000040
29#define PSR_I_BIT 0x00000080
30#define PSR_V_BIT 0x10000000
31#define PSR_C_BIT 0x20000000
32#define PSR_Z_BIT 0x40000000
33#define PSR_S_BIT 0x80000000
34
35/*
36 * Groups of PSR bits
37 */
38#define PSR_f 0xff000000 /* Flags */
39#define PSR_c 0x000000ff /* Control */
40
41#ifndef __ASSEMBLY__
42
43/*
44 * This struct defines the way the registers are stored on the
45 * stack during a system call. Note that sizeof(struct pt_regs)
46 * has to be a multiple of 8.
47 */
48struct pt_regs {
49 unsigned long uregs[34];
50};
51
52#define UCreg_asr uregs[32]
53#define UCreg_pc uregs[31]
54#define UCreg_lr uregs[30]
55#define UCreg_sp uregs[29]
56#define UCreg_ip uregs[28]
57#define UCreg_fp uregs[27]
58#define UCreg_26 uregs[26]
59#define UCreg_25 uregs[25]
60#define UCreg_24 uregs[24]
61#define UCreg_23 uregs[23]
62#define UCreg_22 uregs[22]
63#define UCreg_21 uregs[21]
64#define UCreg_20 uregs[20]
65#define UCreg_19 uregs[19]
66#define UCreg_18 uregs[18]
67#define UCreg_17 uregs[17]
68#define UCreg_16 uregs[16]
69#define UCreg_15 uregs[15]
70#define UCreg_14 uregs[14]
71#define UCreg_13 uregs[13]
72#define UCreg_12 uregs[12]
73#define UCreg_11 uregs[11]
74#define UCreg_10 uregs[10]
75#define UCreg_09 uregs[9]
76#define UCreg_08 uregs[8]
77#define UCreg_07 uregs[7]
78#define UCreg_06 uregs[6]
79#define UCreg_05 uregs[5]
80#define UCreg_04 uregs[4]
81#define UCreg_03 uregs[3]
82#define UCreg_02 uregs[2]
83#define UCreg_01 uregs[1]
84#define UCreg_00 uregs[0]
85#define UCreg_ORIG_00 uregs[33]
86
87#ifdef __KERNEL__
88
89#define user_mode(regs) \
90 (processor_mode(regs) == USER_MODE)
91
92#define processor_mode(regs) \
93 ((regs)->UCreg_asr & MODE_MASK)
94
95#define interrupts_enabled(regs) \
96 (!((regs)->UCreg_asr & PSR_I_BIT))
97
98#define fast_interrupts_enabled(regs) \
99 (!((regs)->UCreg_asr & PSR_R_BIT))
100
101/* Are the current registers suitable for user mode?
102 * (used to maintain security in signal handlers)
103 */
104static inline int valid_user_regs(struct pt_regs *regs)
105{
106 unsigned long mode = regs->UCreg_asr & MODE_MASK;
107
108 /*
109 * Always clear the R (REAL) bits
110 */
111 regs->UCreg_asr &= ~(PSR_R_BIT);
112
113 if ((regs->UCreg_asr & PSR_I_BIT) == 0) {
114 if (mode == USER_MODE)
115 return 1;
116 }
117
118 /*
119 * Force ASR to something logical...
120 */
121 regs->UCreg_asr &= PSR_f | USER_MODE;
122
123 return 0;
124}
125
126#define instruction_pointer(regs) ((regs)->UCreg_pc)
127
128#endif /* __KERNEL__ */
129
130#endif /* __ASSEMBLY__ */
131
132#endif
133
diff --git a/arch/unicore32/include/asm/sigcontext.h b/arch/unicore32/include/asm/sigcontext.h
new file mode 100644
index 00000000000..6a2d7671c05
--- /dev/null
+++ b/arch/unicore32/include/asm/sigcontext.h
@@ -0,0 +1,29 @@
1/*
2 * linux/arch/unicore32/include/asm/sigcontext.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_SIGCONTEXT_H__
13#define __UNICORE_SIGCONTEXT_H__
14
15#include <asm/ptrace.h>
16/*
17 * Signal context structure - contains all info to do with the state
18 * before the signal handler was invoked. Note: only add new entries
19 * to the end of the structure.
20 */
21struct sigcontext {
22 unsigned long trap_no;
23 unsigned long error_code;
24 unsigned long oldmask;
25 unsigned long fault_address;
26 struct pt_regs regs;
27};
28
29#endif
diff --git a/arch/unicore32/include/asm/stacktrace.h b/arch/unicore32/include/asm/stacktrace.h
new file mode 100644
index 00000000000..76edc65a587
--- /dev/null
+++ b/arch/unicore32/include/asm/stacktrace.h
@@ -0,0 +1,31 @@
1/*
2 * linux/arch/unicore32/include/asm/stacktrace.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_STACKTRACE_H__
14#define __UNICORE_STACKTRACE_H__
15
16struct stackframe {
17 unsigned long fp;
18 unsigned long sp;
19 unsigned long lr;
20 unsigned long pc;
21};
22
23#ifdef CONFIG_FRAME_POINTER
24extern int unwind_frame(struct stackframe *frame);
25#else
26#define unwind_frame(f) (-EINVAL)
27#endif
28extern void walk_stackframe(struct stackframe *frame,
29 int (*fn)(struct stackframe *, void *), void *data);
30
31#endif /* __UNICORE_STACKTRACE_H__ */
diff --git a/arch/unicore32/include/asm/string.h b/arch/unicore32/include/asm/string.h
new file mode 100644
index 00000000000..55264c84369
--- /dev/null
+++ b/arch/unicore32/include/asm/string.h
@@ -0,0 +1,38 @@
1/*
2 * linux/arch/unicore32/include/asm/string.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_STRING_H__
13#define __UNICORE_STRING_H__
14
15/*
16 * We don't do inline string functions, since the
17 * optimised inline asm versions are not small.
18 */
19
20#define __HAVE_ARCH_STRRCHR
21extern char *strrchr(const char *s, int c);
22
23#define __HAVE_ARCH_STRCHR
24extern char *strchr(const char *s, int c);
25
26#define __HAVE_ARCH_MEMCPY
27extern void *memcpy(void *, const void *, __kernel_size_t);
28
29#define __HAVE_ARCH_MEMMOVE
30extern void *memmove(void *, const void *, __kernel_size_t);
31
32#define __HAVE_ARCH_MEMCHR
33extern void *memchr(const void *, int, __kernel_size_t);
34
35#define __HAVE_ARCH_MEMSET
36extern void *memset(void *, int, __kernel_size_t);
37
38#endif
diff --git a/arch/unicore32/include/asm/suspend.h b/arch/unicore32/include/asm/suspend.h
new file mode 100644
index 00000000000..88a9c0f32b2
--- /dev/null
+++ b/arch/unicore32/include/asm/suspend.h
@@ -0,0 +1,30 @@
1/*
2 * linux/arch/unicore32/include/asm/suspend.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_SUSPEND_H__
14#define __UNICORE_SUSPEND_H__
15
16#ifndef __ASSEMBLY__
17static inline int arch_prepare_suspend(void) { return 0; }
18
19#include <asm/ptrace.h>
20
21struct swsusp_arch_regs {
22 struct cpu_context_save cpu_context; /* cpu context */
23#ifdef CONFIG_UNICORE_FPU_F64
24 struct fp_state fpstate __attribute__((aligned(8)));
25#endif
26};
27#endif
28
29#endif /* __UNICORE_SUSPEND_H__ */
30
diff --git a/arch/unicore32/include/asm/system.h b/arch/unicore32/include/asm/system.h
new file mode 100644
index 00000000000..246b71c17fd
--- /dev/null
+++ b/arch/unicore32/include/asm/system.h
@@ -0,0 +1,161 @@
1/*
2 * linux/arch/unicore32/include/asm/system.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_SYSTEM_H__
13#define __UNICORE_SYSTEM_H__
14
15#ifdef __KERNEL__
16
17/*
18 * CR1 bits (CP#0 CR1)
19 */
20#define CR_M (1 << 0) /* MMU enable */
21#define CR_A (1 << 1) /* Alignment abort enable */
22#define CR_D (1 << 2) /* Dcache enable */
23#define CR_I (1 << 3) /* Icache enable */
24#define CR_B (1 << 4) /* Dcache write mechanism: write back */
25#define CR_T (1 << 5) /* Burst enable */
26#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
27
28#ifndef __ASSEMBLY__
29
30#include <linux/linkage.h>
31#include <linux/irqflags.h>
32
33struct thread_info;
34struct task_struct;
35
36struct pt_regs;
37
38void die(const char *msg, struct pt_regs *regs, int err);
39
40struct siginfo;
41void uc32_notify_die(const char *str, struct pt_regs *regs,
42 struct siginfo *info, unsigned long err, unsigned long trap);
43
44void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
45 struct pt_regs *),
46 int sig, int code, const char *name);
47
48#define xchg(ptr, x) \
49 ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
50
51extern asmlinkage void __backtrace(void);
52extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
53
54struct mm_struct;
55extern void show_pte(struct mm_struct *mm, unsigned long addr);
56extern void __show_regs(struct pt_regs *);
57
58extern int cpu_architecture(void);
59extern void cpu_init(void);
60
61#define vectors_high() (cr_alignment & CR_V)
62
63#define isb() __asm__ __volatile__ ("" : : : "memory")
64#define dsb() __asm__ __volatile__ ("" : : : "memory")
65#define dmb() __asm__ __volatile__ ("" : : : "memory")
66
67#define mb() barrier()
68#define rmb() barrier()
69#define wmb() barrier()
70#define smp_mb() barrier()
71#define smp_rmb() barrier()
72#define smp_wmb() barrier()
73#define read_barrier_depends() do { } while (0)
74#define smp_read_barrier_depends() do { } while (0)
75
76#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
77#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
78
79extern unsigned long cr_no_alignment; /* defined in entry-unicore.S */
80extern unsigned long cr_alignment; /* defined in entry-unicore.S */
81
82static inline unsigned int get_cr(void)
83{
84 unsigned int val;
85 asm("movc %0, p0.c1, #0" : "=r" (val) : : "cc");
86 return val;
87}
88
89static inline void set_cr(unsigned int val)
90{
91 asm volatile("movc p0.c1, %0, #0 @set CR"
92 : : "r" (val) : "cc");
93 isb();
94}
95
96extern void adjust_cr(unsigned long mask, unsigned long set);
97
98/*
99 * switch_to(prev, next) should switch from task `prev' to `next'
100 * `prev' will never be the same as `next'. schedule() itself
101 * contains the memory barrier to tell GCC not to cache `current'.
102 */
103extern struct task_struct *__switch_to(struct task_struct *,
104 struct thread_info *, struct thread_info *);
105extern void panic(const char *fmt, ...);
106
107#define switch_to(prev, next, last) \
108do { \
109 last = __switch_to(prev, \
110 task_thread_info(prev), task_thread_info(next)); \
111} while (0)
112
113static inline unsigned long
114__xchg(unsigned long x, volatile void *ptr, int size)
115{
116 unsigned long ret;
117
118 switch (size) {
119 case 1:
120 asm volatile("@ __xchg1\n"
121 " swapb %0, %1, [%2]"
122 : "=&r" (ret)
123 : "r" (x), "r" (ptr)
124 : "memory", "cc");
125 break;
126 case 4:
127 asm volatile("@ __xchg4\n"
128 " swapw %0, %1, [%2]"
129 : "=&r" (ret)
130 : "r" (x), "r" (ptr)
131 : "memory", "cc");
132 break;
133 default:
134 panic("xchg: bad data size: ptr 0x%p, size %d\n",
135 ptr, size);
136 }
137
138 return ret;
139}
140
141#include <asm-generic/cmpxchg-local.h>
142
143/*
144 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
145 * them available.
146 */
147#define cmpxchg_local(ptr, o, n) \
148 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
149 (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
150#define cmpxchg64_local(ptr, o, n) \
151 __cmpxchg64_local_generic((ptr), (o), (n))
152
153#include <asm-generic/cmpxchg.h>
154
155#endif /* __ASSEMBLY__ */
156
157#define arch_align_stack(x) (x)
158
159#endif /* __KERNEL__ */
160
161#endif
diff --git a/arch/unicore32/include/asm/thread_info.h b/arch/unicore32/include/asm/thread_info.h
new file mode 100644
index 00000000000..c270e9e0486
--- /dev/null
+++ b/arch/unicore32/include/asm/thread_info.h
@@ -0,0 +1,154 @@
1/*
2 * linux/arch/unicore32/include/asm/thread_info.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_THREAD_INFO_H__
13#define __UNICORE_THREAD_INFO_H__
14
15#ifdef __KERNEL__
16
17#include <linux/compiler.h>
18#include <asm/fpstate.h>
19
20#define THREAD_SIZE_ORDER 1
21#define THREAD_SIZE 8192
22#define THREAD_START_SP (THREAD_SIZE - 8)
23
24#ifndef __ASSEMBLY__
25
26struct task_struct;
27struct exec_domain;
28
29#include <asm/types.h>
30
31typedef struct {
32 unsigned long seg;
33} mm_segment_t;
34
35struct cpu_context_save {
36 __u32 r4;
37 __u32 r5;
38 __u32 r6;
39 __u32 r7;
40 __u32 r8;
41 __u32 r9;
42 __u32 r10;
43 __u32 r11;
44 __u32 r12;
45 __u32 r13;
46 __u32 r14;
47 __u32 r15;
48 __u32 r16;
49 __u32 r17;
50 __u32 r18;
51 __u32 r19;
52 __u32 r20;
53 __u32 r21;
54 __u32 r22;
55 __u32 r23;
56 __u32 r24;
57 __u32 r25;
58 __u32 r26;
59 __u32 fp;
60 __u32 sp;
61 __u32 pc;
62};
63
64/*
65 * low level task data that entry.S needs immediate access to.
66 * __switch_to() assumes cpu_context follows immediately after cpu_domain.
67 */
68struct thread_info {
69 unsigned long flags; /* low level flags */
70 int preempt_count; /* 0 => preemptable */
71 /* <0 => bug */
72 mm_segment_t addr_limit; /* address limit */
73 struct task_struct *task; /* main task structure */
74 struct exec_domain *exec_domain; /* execution domain */
75 __u32 cpu; /* cpu */
76 struct cpu_context_save cpu_context; /* cpu context */
77 __u32 syscall; /* syscall number */
78 __u8 used_cp[16]; /* thread used copro */
79#ifdef CONFIG_UNICORE_FPU_F64
80 struct fp_state fpstate __attribute__((aligned(8)));
81#endif
82 struct restart_block restart_block;
83};
84
85#define INIT_THREAD_INFO(tsk) \
86{ \
87 .task = &tsk, \
88 .exec_domain = &default_exec_domain, \
89 .flags = 0, \
90 .preempt_count = INIT_PREEMPT_COUNT, \
91 .addr_limit = KERNEL_DS, \
92 .restart_block = { \
93 .fn = do_no_restart_syscall, \
94 }, \
95}
96
97#define init_thread_info (init_thread_union.thread_info)
98#define init_stack (init_thread_union.stack)
99
100/*
101 * how to get the thread information struct from C
102 */
103static inline struct thread_info *current_thread_info(void) __attribute_const__;
104
105static inline struct thread_info *current_thread_info(void)
106{
107 register unsigned long sp asm ("sp");
108 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
109}
110
111#define thread_saved_pc(tsk) \
112 ((unsigned long)(task_thread_info(tsk)->cpu_context.pc))
113#define thread_saved_sp(tsk) \
114 ((unsigned long)(task_thread_info(tsk)->cpu_context.sp))
115#define thread_saved_fp(tsk) \
116 ((unsigned long)(task_thread_info(tsk)->cpu_context.fp))
117
118#endif
119
120/*
121 * We use bit 30 of the preempt_count to indicate that kernel
122 * preemption is occurring. See <asm/hardirq.h>.
123 */
124#define PREEMPT_ACTIVE 0x40000000
125
126/*
127 * thread information flags:
128 * TIF_SYSCALL_TRACE - syscall trace active
129 * TIF_SIGPENDING - signal pending
130 * TIF_NEED_RESCHED - rescheduling necessary
131 * TIF_NOTIFY_RESUME - callback before returning to user
132 */
133#define TIF_SIGPENDING 0
134#define TIF_NEED_RESCHED 1
135#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
136#define TIF_SYSCALL_TRACE 8
137#define TIF_MEMDIE 18
138#define TIF_FREEZE 19
139#define TIF_RESTORE_SIGMASK 20
140
141#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
142#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
143#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
144#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
145#define _TIF_FREEZE (1 << TIF_FREEZE)
146#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
147
148/*
149 * Change these and you break ASM code in entry-common.S
150 */
151#define _TIF_WORK_MASK 0x000000ff
152
153#endif /* __KERNEL__ */
154#endif /* __UNICORE_THREAD_INFO_H__ */
diff --git a/arch/unicore32/include/asm/timex.h b/arch/unicore32/include/asm/timex.h
new file mode 100644
index 00000000000..faf16ba4654
--- /dev/null
+++ b/arch/unicore32/include/asm/timex.h
@@ -0,0 +1,34 @@
1/*
2 * linux/arch/unicore32/include/asm/timex.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __UNICORE_TIMEX_H__
14#define __UNICORE_TIMEX_H__
15
16#ifdef CONFIG_ARCH_FPGA
17
18/* in FPGA, APB clock is 33M, and OST clock is 32K, */
19/* so, 1M is selected for timer interrupt correctly */
20#define CLOCK_TICK_RATE (32*1024)
21
22#endif
23
24#if defined(CONFIG_PUV3_DB0913) \
25 || defined(CONFIG_PUV3_NB0916) \
26 || defined(CONFIG_PUV3_SMW0919)
27
28#define CLOCK_TICK_RATE (14318000)
29
30#endif
31
32#include <asm-generic/timex.h>
33
34#endif
diff --git a/arch/unicore32/include/asm/tlb.h b/arch/unicore32/include/asm/tlb.h
new file mode 100644
index 00000000000..9cca15cdae9
--- /dev/null
+++ b/arch/unicore32/include/asm/tlb.h
@@ -0,0 +1,28 @@
1/*
2 * linux/arch/unicore32/include/asm/tlb.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_TLB_H__
13#define __UNICORE_TLB_H__
14
15#define tlb_start_vma(tlb, vma) do { } while (0)
16#define tlb_end_vma(tlb, vma) do { } while (0)
17#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
18#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
19
20#define __pte_free_tlb(tlb, pte, addr) \
21 do { \
22 pgtable_page_dtor(pte); \
23 tlb_remove_page((tlb), (pte)); \
24 } while (0)
25
26#include <asm-generic/tlb.h>
27
28#endif
diff --git a/arch/unicore32/include/asm/tlbflush.h b/arch/unicore32/include/asm/tlbflush.h
new file mode 100644
index 00000000000..e446ac8bb9e
--- /dev/null
+++ b/arch/unicore32/include/asm/tlbflush.h
@@ -0,0 +1,195 @@
1/*
2 * linux/arch/unicore32/include/asm/tlbflush.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_TLBFLUSH_H__
13#define __UNICORE_TLBFLUSH_H__
14
15#ifndef __ASSEMBLY__
16
17#include <linux/sched.h>
18
19extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long,
20 struct vm_area_struct *);
21extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
22
23/*
24 * TLB Management
25 * ==============
26 *
27 * The arch/unicore/mm/tlb-*.S files implement these methods.
28 *
29 * The TLB specific code is expected to perform whatever tests it
30 * needs to determine if it should invalidate the TLB for each
31 * call. Start addresses are inclusive and end addresses are
32 * exclusive; it is safe to round these addresses down.
33 *
34 * flush_tlb_all()
35 *
36 * Invalidate the entire TLB.
37 *
38 * flush_tlb_mm(mm)
39 *
40 * Invalidate all TLB entries in a particular address
41 * space.
42 * - mm - mm_struct describing address space
43 *
44 * flush_tlb_range(mm,start,end)
45 *
46 * Invalidate a range of TLB entries in the specified
47 * address space.
48 * - mm - mm_struct describing address space
49 * - start - start address (may not be aligned)
50 * - end - end address (exclusive, may not be aligned)
51 *
52 * flush_tlb_page(vaddr,vma)
53 *
54 * Invalidate the specified page in the specified address range.
55 * - vaddr - virtual address (may not be aligned)
56 * - vma - vma_struct describing address range
57 *
58 * flush_kern_tlb_page(kaddr)
59 *
60 * Invalidate the TLB entry for the specified page. The address
61 * will be in the kernels virtual memory space. Current uses
62 * only require the D-TLB to be invalidated.
63 * - kaddr - Kernel virtual memory address
64 */
65
66static inline void local_flush_tlb_all(void)
67{
68 const int zero = 0;
69
70 /* TLB invalidate all */
71 asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop"
72 : : "r" (zero) : "cc");
73}
74
75static inline void local_flush_tlb_mm(struct mm_struct *mm)
76{
77 const int zero = 0;
78
79 if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
80 /* TLB invalidate all */
81 asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop"
82 : : "r" (zero) : "cc");
83 }
84 put_cpu();
85}
86
87static inline void
88local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
89{
90 if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
91#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
92 /* iTLB invalidate page */
93 asm("movc p0.c6, %0, #5; nop; nop; nop; nop; nop; nop; nop; nop"
94 : : "r" (uaddr & PAGE_MASK) : "cc");
95 /* dTLB invalidate page */
96 asm("movc p0.c6, %0, #3; nop; nop; nop; nop; nop; nop; nop; nop"
97 : : "r" (uaddr & PAGE_MASK) : "cc");
98#else
99 /* TLB invalidate all */
100 asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop"
101 : : "r" (uaddr & PAGE_MASK) : "cc");
102#endif
103 }
104}
105
106static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
107{
108#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
109 /* iTLB invalidate page */
110 asm("movc p0.c6, %0, #5; nop; nop; nop; nop; nop; nop; nop; nop"
111 : : "r" (kaddr & PAGE_MASK) : "cc");
112 /* dTLB invalidate page */
113 asm("movc p0.c6, %0, #3; nop; nop; nop; nop; nop; nop; nop; nop"
114 : : "r" (kaddr & PAGE_MASK) : "cc");
115#else
116 /* TLB invalidate all */
117 asm("movc p0.c6, %0, #6; nop; nop; nop; nop; nop; nop; nop; nop"
118 : : "r" (kaddr & PAGE_MASK) : "cc");
119#endif
120}
121
122/*
123 * flush_pmd_entry
124 *
125 * Flush a PMD entry (word aligned, or double-word aligned) to
126 * RAM if the TLB for the CPU we are running on requires this.
127 * This is typically used when we are creating PMD entries.
128 *
129 * clean_pmd_entry
130 *
131 * Clean (but don't drain the write buffer) if the CPU requires
132 * these operations. This is typically used when we are removing
133 * PMD entries.
134 */
135static inline void flush_pmd_entry(pmd_t *pmd)
136{
137#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
138 /* flush dcache line, see dcacheline_flush in proc-macros.S */
139 asm("mov r1, %0 << #20\n"
140 "ldw r2, =_stext\n"
141 "add r2, r2, r1 >> #20\n"
142 "ldw r1, [r2+], #0x0000\n"
143 "ldw r1, [r2+], #0x1000\n"
144 "ldw r1, [r2+], #0x2000\n"
145 "ldw r1, [r2+], #0x3000\n"
146 : : "r" (pmd) : "r1", "r2");
147#else
148 /* flush dcache all */
149 asm("movc p0.c5, %0, #14; nop; nop; nop; nop; nop; nop; nop; nop"
150 : : "r" (pmd) : "cc");
151#endif
152}
153
154static inline void clean_pmd_entry(pmd_t *pmd)
155{
156#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
157 /* clean dcache line */
158 asm("movc p0.c5, %0, #11; nop; nop; nop; nop; nop; nop; nop; nop"
159 : : "r" (__pa(pmd) & ~(L1_CACHE_BYTES - 1)) : "cc");
160#else
161 /* clean dcache all */
162 asm("movc p0.c5, %0, #10; nop; nop; nop; nop; nop; nop; nop; nop"
163 : : "r" (pmd) : "cc");
164#endif
165}
166
167/*
168 * Convert calls to our calling convention.
169 */
170#define local_flush_tlb_range(vma, start, end) \
171 __cpu_flush_user_tlb_range(start, end, vma)
172#define local_flush_tlb_kernel_range(s, e) \
173 __cpu_flush_kern_tlb_range(s, e)
174
175#define flush_tlb_all local_flush_tlb_all
176#define flush_tlb_mm local_flush_tlb_mm
177#define flush_tlb_page local_flush_tlb_page
178#define flush_tlb_kernel_page local_flush_tlb_kernel_page
179#define flush_tlb_range local_flush_tlb_range
180#define flush_tlb_kernel_range local_flush_tlb_kernel_range
181
182/*
183 * if PG_dcache_clean is not set for the page, we need to ensure that any
184 * cache entries for the kernels virtual memory range are written
185 * back to the page.
186 */
187extern void update_mmu_cache(struct vm_area_struct *vma,
188 unsigned long addr, pte_t *ptep);
189
190extern void do_bad_area(unsigned long addr, unsigned int fsr,
191 struct pt_regs *regs);
192
193#endif
194
195#endif
diff --git a/arch/unicore32/include/asm/traps.h b/arch/unicore32/include/asm/traps.h
new file mode 100644
index 00000000000..66e17a724bf
--- /dev/null
+++ b/arch/unicore32/include/asm/traps.h
@@ -0,0 +1,21 @@
1/*
2 * linux/arch/unicore32/include/asm/traps.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_TRAP_H__
13#define __UNICORE_TRAP_H__
14
15extern void __init early_trap_init(void);
16extern void dump_backtrace_entry(unsigned long where,
17 unsigned long from, unsigned long frame);
18
19extern void do_DataAbort(unsigned long addr, unsigned int fsr,
20 struct pt_regs *regs);
21#endif
diff --git a/arch/unicore32/include/asm/uaccess.h b/arch/unicore32/include/asm/uaccess.h
new file mode 100644
index 00000000000..2acda503a6d
--- /dev/null
+++ b/arch/unicore32/include/asm/uaccess.h
@@ -0,0 +1,47 @@
1/*
2 * linux/arch/unicore32/include/asm/uaccess.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_UACCESS_H__
13#define __UNICORE_UACCESS_H__
14
15#include <linux/thread_info.h>
16#include <linux/errno.h>
17
18#include <asm/memory.h>
19#include <asm/system.h>
20
21#define __copy_from_user __copy_from_user
22#define __copy_to_user __copy_to_user
23#define __strncpy_from_user __strncpy_from_user
24#define __strnlen_user __strnlen_user
25#define __clear_user __clear_user
26
27#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
28#define __user_ok(addr, size) (((size) <= TASK_SIZE) \
29 && ((addr) <= TASK_SIZE - (size)))
30#define __access_ok(addr, size) (__kernel_ok || __user_ok((addr), (size)))
31
32extern unsigned long __must_check
33__copy_from_user(void *to, const void __user *from, unsigned long n);
34extern unsigned long __must_check
35__copy_to_user(void __user *to, const void *from, unsigned long n);
36extern unsigned long __must_check
37__clear_user(void __user *addr, unsigned long n);
38extern unsigned long __must_check
39__strncpy_from_user(char *to, const char __user *from, unsigned long count);
40extern unsigned long
41__strnlen_user(const char __user *s, long n);
42
43#include <asm-generic/uaccess.h>
44
45extern int fixup_exception(struct pt_regs *regs);
46
47#endif /* __UNICORE_UACCESS_H__ */
diff --git a/arch/unicore32/include/asm/unistd.h b/arch/unicore32/include/asm/unistd.h
new file mode 100644
index 00000000000..9b242801996
--- /dev/null
+++ b/arch/unicore32/include/asm/unistd.h
@@ -0,0 +1,18 @@
1/*
2 * linux/arch/unicore32/include/asm/unistd.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#if !defined(__UNICORE_UNISTD_H__) || defined(__SYSCALL)
13#define __UNICORE_UNISTD_H__
14
15/* Use the standard ABI for syscalls. */
16#include <asm-generic/unistd.h>
17
18#endif /* __UNICORE_UNISTD_H__ */
diff --git a/arch/unicore32/include/mach/PKUnity.h b/arch/unicore32/include/mach/PKUnity.h
new file mode 100644
index 00000000000..a18bdc3810e
--- /dev/null
+++ b/arch/unicore32/include/mach/PKUnity.h
@@ -0,0 +1,108 @@
1/*
2 * linux/arch/unicore32/include/mach/PKUnity.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13/* Be sure that virtual mapping is defined right */
14#ifndef __MACH_PUV3_HARDWARE_H__
15#error You must include hardware.h not PKUnity.h
16#endif
17
18#include "bitfield.h"
19
20/*
21 * Memory Definitions
22 */
23#define PKUNITY_SDRAM_BASE 0x00000000 /* 0x00000000 - 0x7FFFFFFF 2GB */
24#define PKUNITY_MMIO_BASE 0x80000000 /* 0x80000000 - 0xFFFFFFFF 2GB */
25
26/*
27 * PKUNITY Memory Map Addresses: 0x0D000000 - 0x0EFFFFFF (32MB)
28 * 0x0D000000 - 0x0DFFFFFF 16MB: for UVC
29 * 0x0E000000 - 0x0EFFFFFF 16MB: for UNIGFX
30 */
31#define PKUNITY_UVC_MMAP_BASE 0x0D000000
32#define PKUNITY_UVC_MMAP_SIZE 0x01000000 /* 16MB */
33#define PKUNITY_UNIGFX_MMAP_BASE 0x0E000000
34#define PKUNITY_UNIGFX_MMAP_SIZE 0x01000000 /* 16MB */
35
36/*
37 * PKUNITY System Bus Addresses (PCI): 0x80000000 - 0xBFFFFFFF (1GB)
38 * 0x80000000 - 0x8000000B 12B PCI Configuration regs
39 * 0x80010000 - 0x80010250 592B PCI Bridge Base
40 * 0x80030000 - 0x8003FFFF 64KB PCI Legacy IO
41 * 0x90000000 - 0x97FFFFFF 128MB PCI AHB-PCI MEM-mapping
42 * 0x98000000 - 0x9FFFFFFF 128MB PCI PCI-AHB MEM-mapping
43 */
44#define PKUNITY_PCI_BASE io_p2v(0x80000000) /* 0x80000000 - 0xBFFFFFFF 1GB */
45#include "regs-pci.h"
46
47#define PKUNITY_PCICFG_BASE (PKUNITY_PCI_BASE + 0x0)
48#define PKUNITY_PCIBRI_BASE (PKUNITY_PCI_BASE + 0x00010000)
49#define PKUNITY_PCILIO_BASE (PKUNITY_PCI_BASE + 0x00030000)
50#define PKUNITY_PCIMEM_BASE (PKUNITY_PCI_BASE + 0x10000000)
51#define PKUNITY_PCIAHB_BASE (PKUNITY_PCI_BASE + 0x18000000)
52
53/*
54 * PKUNITY System Bus Addresses (AHB): 0xC0000000 - 0xEDFFFFFF (640MB)
55 */
56#define PKUNITY_AHB_BASE io_p2v(0xC0000000)
57
58/* AHB-0 is DDR2 SDRAM */
59/* AHB-1 is PCI Space */
60#define PKUNITY_ARBITER_BASE (PKUNITY_AHB_BASE + 0x000000) /* AHB-2 */
61#define PKUNITY_DDR2CTRL_BASE (PKUNITY_AHB_BASE + 0x100000) /* AHB-3 */
62#define PKUNITY_DMAC_BASE (PKUNITY_AHB_BASE + 0x200000) /* AHB-4 */
63#include "regs-dmac.h"
64#define PKUNITY_UMAL_BASE (PKUNITY_AHB_BASE + 0x300000) /* AHB-5 */
65#include "regs-umal.h"
66#define PKUNITY_USB_BASE (PKUNITY_AHB_BASE + 0x400000) /* AHB-6 */
67#define PKUNITY_SATA_BASE (PKUNITY_AHB_BASE + 0x500000) /* AHB-7 */
68#define PKUNITY_SMC_BASE (PKUNITY_AHB_BASE + 0x600000) /* AHB-8 */
69/* AHB-9 is for APB bridge */
70#define PKUNITY_MME_BASE (PKUNITY_AHB_BASE + 0x700000) /* AHB-10 */
71#define PKUNITY_UNIGFX_BASE (PKUNITY_AHB_BASE + 0x800000) /* AHB-11 */
72#include "regs-unigfx.h"
73#define PKUNITY_NAND_BASE (PKUNITY_AHB_BASE + 0x900000) /* AHB-12 */
74#include "regs-nand.h"
75#define PKUNITY_H264D_BASE (PKUNITY_AHB_BASE + 0xA00000) /* AHB-13 */
76#define PKUNITY_H264E_BASE (PKUNITY_AHB_BASE + 0xB00000) /* AHB-14 */
77
78/*
79 * PKUNITY Peripheral Bus Addresses (APB): 0xEE000000 - 0xEFFFFFFF (128MB)
80 */
81#define PKUNITY_APB_BASE io_p2v(0xEE000000)
82
83#define PKUNITY_UART0_BASE (PKUNITY_APB_BASE + 0x000000) /* APB-0 */
84#define PKUNITY_UART1_BASE (PKUNITY_APB_BASE + 0x100000) /* APB-1 */
85#include "regs-uart.h"
86#define PKUNITY_I2C_BASE (PKUNITY_APB_BASE + 0x200000) /* APB-2 */
87#include "regs-i2c.h"
88#define PKUNITY_SPI_BASE (PKUNITY_APB_BASE + 0x300000) /* APB-3 */
89#include "regs-spi.h"
90#define PKUNITY_AC97_BASE (PKUNITY_APB_BASE + 0x400000) /* APB-4 */
91#include "regs-ac97.h"
92#define PKUNITY_GPIO_BASE (PKUNITY_APB_BASE + 0x500000) /* APB-5 */
93#include "regs-gpio.h"
94#define PKUNITY_INTC_BASE (PKUNITY_APB_BASE + 0x600000) /* APB-6 */
95#include "regs-intc.h"
96#define PKUNITY_RTC_BASE (PKUNITY_APB_BASE + 0x700000) /* APB-7 */
97#include "regs-rtc.h"
98#define PKUNITY_OST_BASE (PKUNITY_APB_BASE + 0x800000) /* APB-8 */
99#include "regs-ost.h"
100#define PKUNITY_RESETC_BASE (PKUNITY_APB_BASE + 0x900000) /* APB-9 */
101#include "regs-resetc.h"
102#define PKUNITY_PM_BASE (PKUNITY_APB_BASE + 0xA00000) /* APB-10 */
103#include "regs-pm.h"
104#define PKUNITY_PS2_BASE (PKUNITY_APB_BASE + 0xB00000) /* APB-11 */
105#include "regs-ps2.h"
106#define PKUNITY_SDC_BASE (PKUNITY_APB_BASE + 0xC00000) /* APB-12 */
107#include "regs-sdc.h"
108
diff --git a/arch/unicore32/include/mach/bitfield.h b/arch/unicore32/include/mach/bitfield.h
new file mode 100644
index 00000000000..128a70281ef
--- /dev/null
+++ b/arch/unicore32/include/mach/bitfield.h
@@ -0,0 +1,24 @@
1/*
2 * linux/arch/unicore32/include/mach/bitfield.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __MACH_PUV3_BITFIELD_H__
13#define __MACH_PUV3_BITFIELD_H__
14
15#ifndef __ASSEMBLY__
16#define UData(Data) ((unsigned long) (Data))
17#else
18#define UData(Data) (Data)
19#endif
20
21#define FIELD(val, vmask, vshift) (((val) & ((UData(1) << (vmask)) - 1)) << (vshift))
22#define FMASK(vmask, vshift) (((UData(1) << (vmask)) - 1) << (vshift))
23
24#endif /* __MACH_PUV3_BITFIELD_H__ */
diff --git a/arch/unicore32/include/mach/dma.h b/arch/unicore32/include/mach/dma.h
new file mode 100644
index 00000000000..d655c1b6e08
--- /dev/null
+++ b/arch/unicore32/include/mach/dma.h
@@ -0,0 +1,48 @@
1/*
2 * linux/arch/unicore32/include/mach/dma.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __MACH_PUV3_DMA_H__
13#define __MACH_PUV3_DMA_H__
14
15/*
16 * The PKUnity has six internal DMA channels.
17 */
18#define MAX_DMA_CHANNELS 6
19
20typedef enum {
21 DMA_PRIO_HIGH = 0,
22 DMA_PRIO_MEDIUM = 1,
23 DMA_PRIO_LOW = 2
24} puv3_dma_prio;
25
26/*
27 * DMA registration
28 */
29
30extern int puv3_request_dma(char *name,
31 puv3_dma_prio prio,
32 void (*irq_handler)(int, void *),
33 void (*err_handler)(int, void *),
34 void *data);
35
36extern void puv3_free_dma(int dma_ch);
37
38static inline void puv3_stop_dma(int ch)
39{
40 writel(readl(DMAC_CONFIG(ch)) & ~DMAC_CONFIG_EN, DMAC_CONFIG(ch));
41}
42
43static inline void puv3_resume_dma(int ch)
44{
45 writel(readl(DMAC_CONFIG(ch)) | DMAC_CONFIG_EN, DMAC_CONFIG(ch));
46}
47
48#endif /* __MACH_PUV3_DMA_H__ */
diff --git a/arch/unicore32/include/mach/hardware.h b/arch/unicore32/include/mach/hardware.h
new file mode 100644
index 00000000000..930bea6e129
--- /dev/null
+++ b/arch/unicore32/include/mach/hardware.h
@@ -0,0 +1,38 @@
1/*
2 * linux/arch/unicore32/include/mach/hardware.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This file contains the hardware definitions for PKUnity architecture
13 */
14
15#ifndef __MACH_PUV3_HARDWARE_H__
16#define __MACH_PUV3_HARDWARE_H__
17
18#include "PKUnity.h"
19
20#ifndef __ASSEMBLY__
21#define io_p2v(x) (void __iomem *)((x) - PKUNITY_MMIO_BASE)
22#define io_v2p(x) (phys_addr_t)((x) + PKUNITY_MMIO_BASE)
23#else
24#define io_p2v(x) ((x) - PKUNITY_MMIO_BASE)
25#define io_v2p(x) ((x) + PKUNITY_MMIO_BASE)
26#endif
27
28#define PCIBIOS_MIN_IO 0x4000 /* should lower than 64KB */
29#define PCIBIOS_MIN_MEM io_v2p(PKUNITY_PCIMEM_BASE)
30
31/*
32 * We override the standard dma-mask routines for bouncing.
33 */
34#define HAVE_ARCH_PCI_SET_DMA_MASK
35
36#define pcibios_assign_all_busses() 1
37
38#endif /* __MACH_PUV3_HARDWARE_H__ */
diff --git a/arch/unicore32/include/mach/map.h b/arch/unicore32/include/mach/map.h
new file mode 100644
index 00000000000..55c93657374
--- /dev/null
+++ b/arch/unicore32/include/mach/map.h
@@ -0,0 +1,20 @@
1/*
2 * linux/arch/unicore32/include/mach/map.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Page table mapping constructs and function prototypes
13 */
14#define MT_DEVICE 0
15#define MT_DEVICE_CACHED 2
16#define MT_KUSER 7
17#define MT_HIGH_VECTORS 8
18#define MT_MEMORY 9
19#define MT_ROM 10
20
diff --git a/arch/unicore32/include/mach/memory.h b/arch/unicore32/include/mach/memory.h
new file mode 100644
index 00000000000..0bf21c94471
--- /dev/null
+++ b/arch/unicore32/include/mach/memory.h
@@ -0,0 +1,58 @@
1/*
2 * linux/arch/unicore32/include/mach/memory.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __MACH_PUV3_MEMORY_H__
13#define __MACH_PUV3_MEMORY_H__
14
15#include <mach/hardware.h>
16
17/* Physical DRAM offset. */
18#define PHYS_OFFSET UL(0x00000000)
19/* The base address of exception vectors. */
20#define VECTORS_BASE UL(0xffff0000)
21/* The base address of kuser area. */
22#define KUSER_BASE UL(0x80000000)
23
24#ifdef __ASSEMBLY__
25/* The byte offset of the kernel image in RAM from the start of RAM. */
26#define KERNEL_IMAGE_START 0x00408000
27#endif
28
29#if !defined(__ASSEMBLY__) && defined(CONFIG_PCI)
30
31void puv3_pci_adjust_zones(unsigned long *size, unsigned long *holes);
32
33#define arch_adjust_zones(size, holes) \
34 puv3_pci_adjust_zones(size, holes)
35
36#endif
37
38/*
39 * PCI controller in PKUnity-3 masks highest 5-bit for upstream channel,
40 * so we must limit the DMA allocation within 128M physical memory for
41 * supporting PCI devices.
42 */
43#define PCI_DMA_THRESHOLD (PHYS_OFFSET + SZ_128M - 1)
44
45#define is_pcibus_device(dev) (dev && \
46 (strncmp(dev->bus->name, "pci", 3) == 0))
47
48#define __virt_to_pcibus(x) (__virt_to_phys((x) + PKUNITY_PCIAHB_BASE))
49#define __pcibus_to_virt(x) (__phys_to_virt(x) - PKUNITY_PCIAHB_BASE)
50
51/* kuser area */
52#define KUSER_VECPAGE_BASE (KUSER_BASE + UL(0x3fff0000))
53#define KUSER_UNIGFX_BASE (PAGE_OFFSET + PKUNITY_UNIGFX_MMAP_BASE)
54/* kuser_vecpage (0xbfff0000) is ro, and vectors page (0xffff0000) is rw */
55#define kuser_vecpage_to_vectors(x) ((x) - (KUSER_VECPAGE_BASE) \
56 + (VECTORS_BASE))
57
58#endif
diff --git a/arch/unicore32/include/mach/ocd.h b/arch/unicore32/include/mach/ocd.h
new file mode 100644
index 00000000000..189fd71bfa3
--- /dev/null
+++ b/arch/unicore32/include/mach/ocd.h
@@ -0,0 +1,36 @@
1/*
2 * linux/arch/unicore32/include/mach/ocd.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __MACH_PUV3_OCD_H__
14#define __MACH_PUV3_OCD_H__
15
16#if defined(CONFIG_DEBUG_OCD)
17static inline void ocd_putc(unsigned int c)
18{
19 int status, i = 0x2000000;
20
21 do {
22 if (--i < 0)
23 return;
24
25 asm volatile ("movc %0, p1.c0, #0" : "=r" (status));
26 } while (status & 2);
27
28 asm("movc p1.c1, %0, #1" : : "r" (c));
29}
30
31#define putc(ch) ocd_putc(ch)
32#else
33#define putc(ch)
34#endif
35
36#endif
diff --git a/arch/unicore32/include/mach/pm.h b/arch/unicore32/include/mach/pm.h
new file mode 100644
index 00000000000..4dcd34ae194
--- /dev/null
+++ b/arch/unicore32/include/mach/pm.h
@@ -0,0 +1,43 @@
1/*
2 * linux/arch/unicore/include/mach/pm.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __PUV3_PM_H__
13#define __PUV3_PM_H__
14
15#include <linux/suspend.h>
16
17struct puv3_cpu_pm_fns {
18 int save_count;
19 void (*save)(unsigned long *);
20 void (*restore)(unsigned long *);
21 int (*valid)(suspend_state_t state);
22 void (*enter)(suspend_state_t state);
23 int (*prepare)(void);
24 void (*finish)(void);
25};
26
27extern struct puv3_cpu_pm_fns *puv3_cpu_pm_fns;
28
29/* sleep.S */
30extern void puv3_cpu_suspend(unsigned int);
31
32extern void puv3_cpu_resume(void);
33
34extern int puv3_pm_enter(suspend_state_t state);
35
36/* Defined in hibernate_asm.S */
37extern int restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist);
38
39/* References to section boundaries */
40extern const void __nosave_begin, __nosave_end;
41
42extern struct pbe *restore_pblist;
43#endif
diff --git a/arch/unicore32/include/mach/regs-ac97.h b/arch/unicore32/include/mach/regs-ac97.h
new file mode 100644
index 00000000000..b7563e9d650
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-ac97.h
@@ -0,0 +1,32 @@
1/*
2 * PKUnity AC97 Registers
3 */
4
5#define PKUNITY_AC97_CONR (PKUNITY_AC97_BASE + 0x0000)
6#define PKUNITY_AC97_OCR (PKUNITY_AC97_BASE + 0x0004)
7#define PKUNITY_AC97_ICR (PKUNITY_AC97_BASE + 0x0008)
8#define PKUNITY_AC97_CRAC (PKUNITY_AC97_BASE + 0x000C)
9#define PKUNITY_AC97_INTR (PKUNITY_AC97_BASE + 0x0010)
10#define PKUNITY_AC97_INTRSTAT (PKUNITY_AC97_BASE + 0x0014)
11#define PKUNITY_AC97_INTRCLEAR (PKUNITY_AC97_BASE + 0x0018)
12#define PKUNITY_AC97_ENABLE (PKUNITY_AC97_BASE + 0x001C)
13#define PKUNITY_AC97_OUT_FIFO (PKUNITY_AC97_BASE + 0x0020)
14#define PKUNITY_AC97_IN_FIFO (PKUNITY_AC97_BASE + 0x0030)
15
16#define AC97_CODEC_REG(v) FIELD((v), 7, 16)
17#define AC97_CODEC_VAL(v) FIELD((v), 16, 0)
18#define AC97_CODEC_WRITECOMPLETE FIELD(1, 1, 2)
19
20/*
21 * VAR PLAY SAMPLE RATE
22 */
23#define AC97_CMD_VPSAMPLE (FIELD(3, 2, 16) | FIELD(3, 2, 0))
24
25/*
26 * FIX CAPTURE SAMPLE RATE
27 */
28#define AC97_CMD_FCSAMPLE FIELD(7, 3, 0)
29
30#define AC97_CMD_RESET FIELD(1, 1, 0)
31#define AC97_CMD_ENABLE FIELD(1, 1, 0)
32#define AC97_CMD_DISABLE FIELD(0, 1, 0)
diff --git a/arch/unicore32/include/mach/regs-dmac.h b/arch/unicore32/include/mach/regs-dmac.h
new file mode 100644
index 00000000000..66de9e7d1c8
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-dmac.h
@@ -0,0 +1,81 @@
1/*
2 * PKUnity Direct Memory Access Controller (DMAC)
3 */
4
5/*
6 * Interrupt Status Reg DMAC_ISR.
7 */
8#define DMAC_ISR (PKUNITY_DMAC_BASE + 0x0020)
9/*
10 * Interrupt Transfer Complete Status Reg DMAC_ITCSR.
11 */
12#define DMAC_ITCSR (PKUNITY_DMAC_BASE + 0x0050)
13/*
14 * Interrupt Transfer Complete Clear Reg DMAC_ITCCR.
15 */
16#define DMAC_ITCCR (PKUNITY_DMAC_BASE + 0x0060)
17/*
18 * Interrupt Error Status Reg DMAC_IESR.
19 */
20#define DMAC_IESR (PKUNITY_DMAC_BASE + 0x0080)
21/*
22 * Interrupt Error Clear Reg DMAC_IECR.
23 */
24#define DMAC_IECR (PKUNITY_DMAC_BASE + 0x0090)
25/*
26 * Enable Channels Reg DMAC_ENCH.
27 */
28#define DMAC_ENCH (PKUNITY_DMAC_BASE + 0x00B0)
29
30/*
31 * DMA control reg. Space [byte]
32 */
33#define DMASp 0x00000100
34
35/*
36 * Source Addr DMAC_SRCADDR(ch).
37 */
38#define DMAC_SRCADDR(ch) (PKUNITY_DMAC_BASE + (ch)*DMASp + 0x00)
39/*
40 * Destination Addr DMAC_DESTADDR(ch).
41 */
42#define DMAC_DESTADDR(ch) (PKUNITY_DMAC_BASE + (ch)*DMASp + 0x04)
43/*
44 * Control Reg DMAC_CONTROL(ch).
45 */
46#define DMAC_CONTROL(ch) (PKUNITY_DMAC_BASE + (ch)*DMASp + 0x0C)
47/*
48 * Configuration Reg DMAC_CONFIG(ch).
49 */
50#define DMAC_CONFIG(ch) (PKUNITY_DMAC_BASE + (ch)*DMASp + 0x10)
51
52#define DMAC_IR_MASK FMASK(6, 0)
53/*
54 * select channel (ch)
55 */
56#define DMAC_CHANNEL(ch) FIELD(1, 1, (ch))
57
58#define DMAC_CONTROL_SIZE_BYTE(v) (FIELD((v), 12, 14) | \
59 FIELD(0, 3, 9) | FIELD(0, 3, 6))
60#define DMAC_CONTROL_SIZE_HWORD(v) (FIELD((v) >> 1, 12, 14) | \
61 FIELD(1, 3, 9) | FIELD(1, 3, 6))
62#define DMAC_CONTROL_SIZE_WORD(v) (FIELD((v) >> 2, 12, 14) | \
63 FIELD(2, 3, 9) | FIELD(2, 3, 6))
64#define DMAC_CONTROL_DI FIELD(1, 1, 13)
65#define DMAC_CONTROL_SI FIELD(1, 1, 12)
66#define DMAC_CONTROL_BURST_1BYTE (FIELD(0, 3, 3) | FIELD(0, 3, 0))
67#define DMAC_CONTROL_BURST_4BYTE (FIELD(3, 3, 3) | FIELD(3, 3, 0))
68#define DMAC_CONTROL_BURST_8BYTE (FIELD(5, 3, 3) | FIELD(5, 3, 0))
69#define DMAC_CONTROL_BURST_16BYTE (FIELD(7, 3, 3) | FIELD(7, 3, 0))
70
71#define DMAC_CONFIG_UART0_WR (FIELD(2, 4, 11) | FIELD(1, 2, 1))
72#define DMAC_CONFIG_UART0_RD (FIELD(2, 4, 7) | FIELD(2, 2, 1))
73#define DMAC_CONFIG_UART1_WR (FIELD(3, 4, 11) | FIELD(1, 2, 1))
74#define DMAC_CONFIG_UART1RD (FIELD(3, 4, 7) | FIELD(2, 2, 1))
75#define DMAC_CONFIG_AC97WR (FIELD(4, 4, 11) | FIELD(1, 2, 1))
76#define DMAC_CONFIG_AC97RD (FIELD(4, 4, 7) | FIELD(2, 2, 1))
77#define DMAC_CONFIG_MMCWR (FIELD(7, 4, 11) | FIELD(1, 2, 1))
78#define DMAC_CONFIG_MMCRD (FIELD(7, 4, 7) | FIELD(2, 2, 1))
79#define DMAC_CONFIG_MASKITC FIELD(1, 1, 4)
80#define DMAC_CONFIG_MASKIE FIELD(1, 1, 3)
81#define DMAC_CONFIG_EN FIELD(1, 1, 0)
diff --git a/arch/unicore32/include/mach/regs-gpio.h b/arch/unicore32/include/mach/regs-gpio.h
new file mode 100644
index 00000000000..0273b861ef9
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-gpio.h
@@ -0,0 +1,70 @@
1/*
2 * PKUnity General-Purpose Input/Output (GPIO) Registers
3 */
4
5/*
6 * Voltage Status Reg GPIO_GPLR.
7 */
8#define GPIO_GPLR (PKUNITY_GPIO_BASE + 0x0000)
9/*
10 * Pin Direction Reg GPIO_GPDR.
11 */
12#define GPIO_GPDR (PKUNITY_GPIO_BASE + 0x0004)
13/*
14 * Output Pin Set Reg GPIO_GPSR.
15 */
16#define GPIO_GPSR (PKUNITY_GPIO_BASE + 0x0008)
17/*
18 * Output Pin Clear Reg GPIO_GPCR.
19 */
20#define GPIO_GPCR (PKUNITY_GPIO_BASE + 0x000C)
21/*
22 * Raise Edge Detect Reg GPIO_GRER.
23 */
24#define GPIO_GRER (PKUNITY_GPIO_BASE + 0x0010)
25/*
26 * Fall Edge Detect Reg GPIO_GFER.
27 */
28#define GPIO_GFER (PKUNITY_GPIO_BASE + 0x0014)
29/*
30 * Edge Status Reg GPIO_GEDR.
31 */
32#define GPIO_GEDR (PKUNITY_GPIO_BASE + 0x0018)
33/*
34 * Sepcial Voltage Detect Reg GPIO_GPIR.
35 */
36#define GPIO_GPIR (PKUNITY_GPIO_BASE + 0x0020)
37
38#define GPIO_MIN (0)
39#define GPIO_MAX (27)
40
41#define GPIO_GPIO(Nb) (0x00000001 << (Nb)) /* GPIO [0..27] */
42#define GPIO_GPIO0 GPIO_GPIO(0) /* GPIO [0] */
43#define GPIO_GPIO1 GPIO_GPIO(1) /* GPIO [1] */
44#define GPIO_GPIO2 GPIO_GPIO(2) /* GPIO [2] */
45#define GPIO_GPIO3 GPIO_GPIO(3) /* GPIO [3] */
46#define GPIO_GPIO4 GPIO_GPIO(4) /* GPIO [4] */
47#define GPIO_GPIO5 GPIO_GPIO(5) /* GPIO [5] */
48#define GPIO_GPIO6 GPIO_GPIO(6) /* GPIO [6] */
49#define GPIO_GPIO7 GPIO_GPIO(7) /* GPIO [7] */
50#define GPIO_GPIO8 GPIO_GPIO(8) /* GPIO [8] */
51#define GPIO_GPIO9 GPIO_GPIO(9) /* GPIO [9] */
52#define GPIO_GPIO10 GPIO_GPIO(10) /* GPIO [10] */
53#define GPIO_GPIO11 GPIO_GPIO(11) /* GPIO [11] */
54#define GPIO_GPIO12 GPIO_GPIO(12) /* GPIO [12] */
55#define GPIO_GPIO13 GPIO_GPIO(13) /* GPIO [13] */
56#define GPIO_GPIO14 GPIO_GPIO(14) /* GPIO [14] */
57#define GPIO_GPIO15 GPIO_GPIO(15) /* GPIO [15] */
58#define GPIO_GPIO16 GPIO_GPIO(16) /* GPIO [16] */
59#define GPIO_GPIO17 GPIO_GPIO(17) /* GPIO [17] */
60#define GPIO_GPIO18 GPIO_GPIO(18) /* GPIO [18] */
61#define GPIO_GPIO19 GPIO_GPIO(19) /* GPIO [19] */
62#define GPIO_GPIO20 GPIO_GPIO(20) /* GPIO [20] */
63#define GPIO_GPIO21 GPIO_GPIO(21) /* GPIO [21] */
64#define GPIO_GPIO22 GPIO_GPIO(22) /* GPIO [22] */
65#define GPIO_GPIO23 GPIO_GPIO(23) /* GPIO [23] */
66#define GPIO_GPIO24 GPIO_GPIO(24) /* GPIO [24] */
67#define GPIO_GPIO25 GPIO_GPIO(25) /* GPIO [25] */
68#define GPIO_GPIO26 GPIO_GPIO(26) /* GPIO [26] */
69#define GPIO_GPIO27 GPIO_GPIO(27) /* GPIO [27] */
70
diff --git a/arch/unicore32/include/mach/regs-i2c.h b/arch/unicore32/include/mach/regs-i2c.h
new file mode 100644
index 00000000000..463d108f8bf
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-i2c.h
@@ -0,0 +1,63 @@
1/*
2 * PKUnity Inter-integrated Circuit (I2C) Registers
3 */
4
5/*
6 * Control Reg I2C_CON.
7 */
8#define I2C_CON (PKUNITY_I2C_BASE + 0x0000)
9/*
10 * Target Address Reg I2C_TAR.
11 */
12#define I2C_TAR (PKUNITY_I2C_BASE + 0x0004)
13/*
14 * Data buffer and command Reg I2C_DATACMD.
15 */
16#define I2C_DATACMD (PKUNITY_I2C_BASE + 0x0010)
17/*
18 * Enable Reg I2C_ENABLE.
19 */
20#define I2C_ENABLE (PKUNITY_I2C_BASE + 0x006C)
21/*
22 * Status Reg I2C_STATUS.
23 */
24#define I2C_STATUS (PKUNITY_I2C_BASE + 0x0070)
25/*
26 * Tx FIFO Length Reg I2C_TXFLR.
27 */
28#define I2C_TXFLR (PKUNITY_I2C_BASE + 0x0074)
29/*
30 * Rx FIFO Length Reg I2C_RXFLR.
31 */
32#define I2C_RXFLR (PKUNITY_I2C_BASE + 0x0078)
33/*
34 * Enable Status Reg I2C_ENSTATUS.
35 */
36#define I2C_ENSTATUS (PKUNITY_I2C_BASE + 0x009C)
37
38#define I2C_CON_MASTER FIELD(1, 1, 0)
39#define I2C_CON_SPEED_STD FIELD(1, 2, 1)
40#define I2C_CON_SPEED_FAST FIELD(2, 2, 1)
41#define I2C_CON_RESTART FIELD(1, 1, 5)
42#define I2C_CON_SLAVEDISABLE FIELD(1, 1, 6)
43
44#define I2C_DATACMD_READ FIELD(1, 1, 8)
45#define I2C_DATACMD_WRITE FIELD(0, 1, 8)
46#define I2C_DATACMD_DAT_MASK FMASK(8, 0)
47#define I2C_DATACMD_DAT(v) FIELD((v), 8, 0)
48
49#define I2C_ENABLE_ENABLE FIELD(1, 1, 0)
50#define I2C_ENABLE_DISABLE FIELD(0, 1, 0)
51
52#define I2C_STATUS_RFF FIELD(1, 1, 4)
53#define I2C_STATUS_RFNE FIELD(1, 1, 3)
54#define I2C_STATUS_TFE FIELD(1, 1, 2)
55#define I2C_STATUS_TFNF FIELD(1, 1, 1)
56#define I2C_STATUS_ACTIVITY FIELD(1, 1, 0)
57
58#define I2C_ENSTATUS_ENABLE FIELD(1, 1, 0)
59
60#define I2C_TAR_THERMAL 0x4f
61#define I2C_TAR_SPD 0x50
62#define I2C_TAR_PWIC 0x55
63#define I2C_TAR_EEPROM 0x57
diff --git a/arch/unicore32/include/mach/regs-intc.h b/arch/unicore32/include/mach/regs-intc.h
new file mode 100644
index 00000000000..25648f89cbd
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-intc.h
@@ -0,0 +1,28 @@
1/*
2 * PKUNITY Interrupt Controller (INTC) Registers
3 */
4/*
5 * INTC Level Reg INTC_ICLR.
6 */
7#define INTC_ICLR (PKUNITY_INTC_BASE + 0x0000)
8/*
9 * INTC Mask Reg INTC_ICMR.
10 */
11#define INTC_ICMR (PKUNITY_INTC_BASE + 0x0004)
12/*
13 * INTC Pending Reg INTC_ICPR.
14 */
15#define INTC_ICPR (PKUNITY_INTC_BASE + 0x0008)
16/*
17 * INTC IRQ Pending Reg INTC_ICIP.
18 */
19#define INTC_ICIP (PKUNITY_INTC_BASE + 0x000C)
20/*
21 * INTC REAL Pending Reg INTC_ICFP.
22 */
23#define INTC_ICFP (PKUNITY_INTC_BASE + 0x0010)
24/*
25 * INTC Control Reg INTC_ICCR.
26 */
27#define INTC_ICCR (PKUNITY_INTC_BASE + 0x0014)
28
diff --git a/arch/unicore32/include/mach/regs-nand.h b/arch/unicore32/include/mach/regs-nand.h
new file mode 100644
index 00000000000..a7c5563bb55
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-nand.h
@@ -0,0 +1,79 @@
1/*
2 * PKUnity NAND Controller Registers
3 */
4/*
5 * ID Reg. 0 NAND_IDR0
6 */
7#define NAND_IDR0 (PKUNITY_NAND_BASE + 0x0000)
8/*
9 * ID Reg. 1 NAND_IDR1
10 */
11#define NAND_IDR1 (PKUNITY_NAND_BASE + 0x0004)
12/*
13 * ID Reg. 2 NAND_IDR2
14 */
15#define NAND_IDR2 (PKUNITY_NAND_BASE + 0x0008)
16/*
17 * ID Reg. 3 NAND_IDR3
18 */
19#define NAND_IDR3 (PKUNITY_NAND_BASE + 0x000C)
20/*
21 * Page Address Reg 0 NAND_PAR0
22 */
23#define NAND_PAR0 (PKUNITY_NAND_BASE + 0x0010)
24/*
25 * Page Address Reg 1 NAND_PAR1
26 */
27#define NAND_PAR1 (PKUNITY_NAND_BASE + 0x0014)
28/*
29 * Page Address Reg 2 NAND_PAR2
30 */
31#define NAND_PAR2 (PKUNITY_NAND_BASE + 0x0018)
32/*
33 * ECC Enable Reg NAND_ECCEN
34 */
35#define NAND_ECCEN (PKUNITY_NAND_BASE + 0x001C)
36/*
37 * Buffer Reg NAND_BUF
38 */
39#define NAND_BUF (PKUNITY_NAND_BASE + 0x0020)
40/*
41 * ECC Status Reg NAND_ECCSR
42 */
43#define NAND_ECCSR (PKUNITY_NAND_BASE + 0x0024)
44/*
45 * Command Reg NAND_CMD
46 */
47#define NAND_CMD (PKUNITY_NAND_BASE + 0x0028)
48/*
49 * DMA Configure Reg NAND_DMACR
50 */
51#define NAND_DMACR (PKUNITY_NAND_BASE + 0x002C)
52/*
53 * Interrupt Reg NAND_IR
54 */
55#define NAND_IR (PKUNITY_NAND_BASE + 0x0030)
56/*
57 * Interrupt Mask Reg NAND_IMR
58 */
59#define NAND_IMR (PKUNITY_NAND_BASE + 0x0034)
60/*
61 * Chip Enable Reg NAND_CHIPEN
62 */
63#define NAND_CHIPEN (PKUNITY_NAND_BASE + 0x0038)
64/*
65 * Address Reg NAND_ADDR
66 */
67#define NAND_ADDR (PKUNITY_NAND_BASE + 0x003C)
68
69/*
70 * Command bits NAND_CMD_CMD_MASK
71 */
72#define NAND_CMD_CMD_MASK FMASK(4, 4)
73#define NAND_CMD_CMD_READPAGE FIELD(0x0, 4, 4)
74#define NAND_CMD_CMD_ERASEBLOCK FIELD(0x6, 4, 4)
75#define NAND_CMD_CMD_READSTATUS FIELD(0x7, 4, 4)
76#define NAND_CMD_CMD_WRITEPAGE FIELD(0x8, 4, 4)
77#define NAND_CMD_CMD_READID FIELD(0x9, 4, 4)
78#define NAND_CMD_CMD_RESET FIELD(0xf, 4, 4)
79
diff --git a/arch/unicore32/include/mach/regs-ost.h b/arch/unicore32/include/mach/regs-ost.h
new file mode 100644
index 00000000000..7b91fe698ee
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-ost.h
@@ -0,0 +1,92 @@
1/*
2 * PKUnity Operating System Timer (OST) Registers
3 */
4/*
5 * Match Reg 0 OST_OSMR0
6 */
7#define OST_OSMR0 (PKUNITY_OST_BASE + 0x0000)
8/*
9 * Match Reg 1 OST_OSMR1
10 */
11#define OST_OSMR1 (PKUNITY_OST_BASE + 0x0004)
12/*
13 * Match Reg 2 OST_OSMR2
14 */
15#define OST_OSMR2 (PKUNITY_OST_BASE + 0x0008)
16/*
17 * Match Reg 3 OST_OSMR3
18 */
19#define OST_OSMR3 (PKUNITY_OST_BASE + 0x000C)
20/*
21 * Counter Reg OST_OSCR
22 */
23#define OST_OSCR (PKUNITY_OST_BASE + 0x0010)
24/*
25 * Status Reg OST_OSSR
26 */
27#define OST_OSSR (PKUNITY_OST_BASE + 0x0014)
28/*
29 * Watchdog Enable Reg OST_OWER
30 */
31#define OST_OWER (PKUNITY_OST_BASE + 0x0018)
32/*
33 * Interrupt Enable Reg OST_OIER
34 */
35#define OST_OIER (PKUNITY_OST_BASE + 0x001C)
36/*
37 * PWM Pulse Width Control Reg OST_PWMPWCR
38 */
39#define OST_PWMPWCR (PKUNITY_OST_BASE + 0x0080)
40/*
41 * PWM Duty Cycle Control Reg OST_PWMDCCR
42 */
43#define OST_PWMDCCR (PKUNITY_OST_BASE + 0x0084)
44/*
45 * PWM Period Control Reg OST_PWMPCR
46 */
47#define OST_PWMPCR (PKUNITY_OST_BASE + 0x0088)
48
49/*
50 * Match detected 0 OST_OSSR_M0
51 */
52#define OST_OSSR_M0 FIELD(1, 1, 0)
53/*
54 * Match detected 1 OST_OSSR_M1
55 */
56#define OST_OSSR_M1 FIELD(1, 1, 1)
57/*
58 * Match detected 2 OST_OSSR_M2
59 */
60#define OST_OSSR_M2 FIELD(1, 1, 2)
61/*
62 * Match detected 3 OST_OSSR_M3
63 */
64#define OST_OSSR_M3 FIELD(1, 1, 3)
65
66/*
67 * Interrupt enable 0 OST_OIER_E0
68 */
69#define OST_OIER_E0 FIELD(1, 1, 0)
70/*
71 * Interrupt enable 1 OST_OIER_E1
72 */
73#define OST_OIER_E1 FIELD(1, 1, 1)
74/*
75 * Interrupt enable 2 OST_OIER_E2
76 */
77#define OST_OIER_E2 FIELD(1, 1, 2)
78/*
79 * Interrupt enable 3 OST_OIER_E3
80 */
81#define OST_OIER_E3 FIELD(1, 1, 3)
82
83/*
84 * Watchdog Match Enable OST_OWER_WME
85 */
86#define OST_OWER_WME FIELD(1, 1, 0)
87
88/*
89 * PWM Full Duty Cycle OST_PWMDCCR_FDCYCLE
90 */
91#define OST_PWMDCCR_FDCYCLE FIELD(1, 1, 10)
92
diff --git a/arch/unicore32/include/mach/regs-pci.h b/arch/unicore32/include/mach/regs-pci.h
new file mode 100644
index 00000000000..6a9341686bf
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-pci.h
@@ -0,0 +1,94 @@
1/*
2 * PKUnity AHB-PCI Bridge Registers
3 */
4
5/*
6 * AHB/PCI fixed physical address for pci addess configuration
7 */
8/*
9 * PCICFG Bridge Base Reg.
10 */
11#define PCICFG_BRIBASE (PKUNITY_PCICFG_BASE + 0x0000)
12/*
13 * PCICFG Address Reg.
14 */
15#define PCICFG_ADDR (PKUNITY_PCICFG_BASE + 0x0004)
16/*
17 * PCICFG Address Reg.
18 */
19#define PCICFG_DATA (PKUNITY_PCICFG_BASE + 0x0008)
20
21/*
22 * PCI Bridge configuration space
23 */
24#define PCIBRI_ID (PKUNITY_PCIBRI_BASE + 0x0000)
25#define PCIBRI_CMD (PKUNITY_PCIBRI_BASE + 0x0004)
26#define PCIBRI_CLASS (PKUNITY_PCIBRI_BASE + 0x0008)
27#define PCIBRI_LTR (PKUNITY_PCIBRI_BASE + 0x000C)
28#define PCIBRI_BAR0 (PKUNITY_PCIBRI_BASE + 0x0010)
29#define PCIBRI_BAR1 (PKUNITY_PCIBRI_BASE + 0x0014)
30#define PCIBRI_BAR2 (PKUNITY_PCIBRI_BASE + 0x0018)
31#define PCIBRI_BAR3 (PKUNITY_PCIBRI_BASE + 0x001C)
32#define PCIBRI_BAR4 (PKUNITY_PCIBRI_BASE + 0x0020)
33#define PCIBRI_BAR5 (PKUNITY_PCIBRI_BASE + 0x0024)
34
35#define PCIBRI_PCICTL0 (PKUNITY_PCIBRI_BASE + 0x0100)
36#define PCIBRI_PCIBAR0 (PKUNITY_PCIBRI_BASE + 0x0104)
37#define PCIBRI_PCIAMR0 (PKUNITY_PCIBRI_BASE + 0x0108)
38#define PCIBRI_PCITAR0 (PKUNITY_PCIBRI_BASE + 0x010C)
39#define PCIBRI_PCICTL1 (PKUNITY_PCIBRI_BASE + 0x0110)
40#define PCIBRI_PCIBAR1 (PKUNITY_PCIBRI_BASE + 0x0114)
41#define PCIBRI_PCIAMR1 (PKUNITY_PCIBRI_BASE + 0x0118)
42#define PCIBRI_PCITAR1 (PKUNITY_PCIBRI_BASE + 0x011C)
43#define PCIBRI_PCICTL2 (PKUNITY_PCIBRI_BASE + 0x0120)
44#define PCIBRI_PCIBAR2 (PKUNITY_PCIBRI_BASE + 0x0124)
45#define PCIBRI_PCIAMR2 (PKUNITY_PCIBRI_BASE + 0x0128)
46#define PCIBRI_PCITAR2 (PKUNITY_PCIBRI_BASE + 0x012C)
47#define PCIBRI_PCICTL3 (PKUNITY_PCIBRI_BASE + 0x0130)
48#define PCIBRI_PCIBAR3 (PKUNITY_PCIBRI_BASE + 0x0134)
49#define PCIBRI_PCIAMR3 (PKUNITY_PCIBRI_BASE + 0x0138)
50#define PCIBRI_PCITAR3 (PKUNITY_PCIBRI_BASE + 0x013C)
51#define PCIBRI_PCICTL4 (PKUNITY_PCIBRI_BASE + 0x0140)
52#define PCIBRI_PCIBAR4 (PKUNITY_PCIBRI_BASE + 0x0144)
53#define PCIBRI_PCIAMR4 (PKUNITY_PCIBRI_BASE + 0x0148)
54#define PCIBRI_PCITAR4 (PKUNITY_PCIBRI_BASE + 0x014C)
55#define PCIBRI_PCICTL5 (PKUNITY_PCIBRI_BASE + 0x0150)
56#define PCIBRI_PCIBAR5 (PKUNITY_PCIBRI_BASE + 0x0154)
57#define PCIBRI_PCIAMR5 (PKUNITY_PCIBRI_BASE + 0x0158)
58#define PCIBRI_PCITAR5 (PKUNITY_PCIBRI_BASE + 0x015C)
59
60#define PCIBRI_AHBCTL0 (PKUNITY_PCIBRI_BASE + 0x0180)
61#define PCIBRI_AHBBAR0 (PKUNITY_PCIBRI_BASE + 0x0184)
62#define PCIBRI_AHBAMR0 (PKUNITY_PCIBRI_BASE + 0x0188)
63#define PCIBRI_AHBTAR0 (PKUNITY_PCIBRI_BASE + 0x018C)
64#define PCIBRI_AHBCTL1 (PKUNITY_PCIBRI_BASE + 0x0190)
65#define PCIBRI_AHBBAR1 (PKUNITY_PCIBRI_BASE + 0x0194)
66#define PCIBRI_AHBAMR1 (PKUNITY_PCIBRI_BASE + 0x0198)
67#define PCIBRI_AHBTAR1 (PKUNITY_PCIBRI_BASE + 0x019C)
68#define PCIBRI_AHBCTL2 (PKUNITY_PCIBRI_BASE + 0x01A0)
69#define PCIBRI_AHBBAR2 (PKUNITY_PCIBRI_BASE + 0x01A4)
70#define PCIBRI_AHBAMR2 (PKUNITY_PCIBRI_BASE + 0x01A8)
71#define PCIBRI_AHBTAR2 (PKUNITY_PCIBRI_BASE + 0x01AC)
72#define PCIBRI_AHBCTL3 (PKUNITY_PCIBRI_BASE + 0x01B0)
73#define PCIBRI_AHBBAR3 (PKUNITY_PCIBRI_BASE + 0x01B4)
74#define PCIBRI_AHBAMR3 (PKUNITY_PCIBRI_BASE + 0x01B8)
75#define PCIBRI_AHBTAR3 (PKUNITY_PCIBRI_BASE + 0x01BC)
76#define PCIBRI_AHBCTL4 (PKUNITY_PCIBRI_BASE + 0x01C0)
77#define PCIBRI_AHBBAR4 (PKUNITY_PCIBRI_BASE + 0x01C4)
78#define PCIBRI_AHBAMR4 (PKUNITY_PCIBRI_BASE + 0x01C8)
79#define PCIBRI_AHBTAR4 (PKUNITY_PCIBRI_BASE + 0x01CC)
80#define PCIBRI_AHBCTL5 (PKUNITY_PCIBRI_BASE + 0x01D0)
81#define PCIBRI_AHBBAR5 (PKUNITY_PCIBRI_BASE + 0x01D4)
82#define PCIBRI_AHBAMR5 (PKUNITY_PCIBRI_BASE + 0x01D8)
83#define PCIBRI_AHBTAR5 (PKUNITY_PCIBRI_BASE + 0x01DC)
84
85#define PCIBRI_CTLx_AT FIELD(1, 1, 2)
86#define PCIBRI_CTLx_PREF FIELD(1, 1, 1)
87#define PCIBRI_CTLx_MRL FIELD(1, 1, 0)
88
89#define PCIBRI_BARx_ADDR FIELD(0xFFFFFFFC, 30, 2)
90#define PCIBRI_BARx_IO FIELD(1, 1, 0)
91#define PCIBRI_BARx_MEM FIELD(0, 1, 0)
92
93#define PCIBRI_CMD_IO FIELD(1, 1, 0)
94#define PCIBRI_CMD_MEM FIELD(1, 1, 1)
diff --git a/arch/unicore32/include/mach/regs-pm.h b/arch/unicore32/include/mach/regs-pm.h
new file mode 100644
index 00000000000..854844aa8f4
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-pm.h
@@ -0,0 +1,126 @@
1/*
2 * PKUNITY Power Manager (PM) Registers
3 */
4/*
5 * PM Control Reg PM_PMCR
6 */
7#define PM_PMCR (PKUNITY_PM_BASE + 0x0000)
8/*
9 * PM General Conf. Reg PM_PGCR
10 */
11#define PM_PGCR (PKUNITY_PM_BASE + 0x0004)
12/*
13 * PM PLL Conf. Reg PM_PPCR
14 */
15#define PM_PPCR (PKUNITY_PM_BASE + 0x0008)
16/*
17 * PM Wakeup Enable Reg PM_PWER
18 */
19#define PM_PWER (PKUNITY_PM_BASE + 0x000C)
20/*
21 * PM GPIO Sleep Status Reg PM_PGSR
22 */
23#define PM_PGSR (PKUNITY_PM_BASE + 0x0010)
24/*
25 * PM Clock Gate Reg PM_PCGR
26 */
27#define PM_PCGR (PKUNITY_PM_BASE + 0x0014)
28/*
29 * PM SYS PLL Conf. Reg PM_PLLSYSCFG
30 */
31#define PM_PLLSYSCFG (PKUNITY_PM_BASE + 0x0018)
32/*
33 * PM DDR PLL Conf. Reg PM_PLLDDRCFG
34 */
35#define PM_PLLDDRCFG (PKUNITY_PM_BASE + 0x001C)
36/*
37 * PM VGA PLL Conf. Reg PM_PLLVGACFG
38 */
39#define PM_PLLVGACFG (PKUNITY_PM_BASE + 0x0020)
40/*
41 * PM Div Conf. Reg PM_DIVCFG
42 */
43#define PM_DIVCFG (PKUNITY_PM_BASE + 0x0024)
44/*
45 * PM SYS PLL Status Reg PM_PLLSYSSTATUS
46 */
47#define PM_PLLSYSSTATUS (PKUNITY_PM_BASE + 0x0028)
48/*
49 * PM DDR PLL Status Reg PM_PLLDDRSTATUS
50 */
51#define PM_PLLDDRSTATUS (PKUNITY_PM_BASE + 0x002C)
52/*
53 * PM VGA PLL Status Reg PM_PLLVGASTATUS
54 */
55#define PM_PLLVGASTATUS (PKUNITY_PM_BASE + 0x0030)
56/*
57 * PM Div Status Reg PM_DIVSTATUS
58 */
59#define PM_DIVSTATUS (PKUNITY_PM_BASE + 0x0034)
60/*
61 * PM Software Reset Reg PM_SWRESET
62 */
63#define PM_SWRESET (PKUNITY_PM_BASE + 0x0038)
64/*
65 * PM DDR2 PAD Start Reg PM_DDR2START
66 */
67#define PM_DDR2START (PKUNITY_PM_BASE + 0x003C)
68/*
69 * PM DDR2 PAD Status Reg PM_DDR2CAL0
70 */
71#define PM_DDR2CAL0 (PKUNITY_PM_BASE + 0x0040)
72/*
73 * PM PLL DFC Done Reg PM_PLLDFCDONE
74 */
75#define PM_PLLDFCDONE (PKUNITY_PM_BASE + 0x0044)
76
77#define PM_PMCR_SFB FIELD(1, 1, 0)
78#define PM_PMCR_IFB FIELD(1, 1, 1)
79#define PM_PMCR_CFBSYS FIELD(1, 1, 2)
80#define PM_PMCR_CFBDDR FIELD(1, 1, 3)
81#define PM_PMCR_CFBVGA FIELD(1, 1, 4)
82#define PM_PMCR_CFBDIVBCLK FIELD(1, 1, 5)
83
84/*
85 * GPIO 8~27 wake-up enable PM_PWER_GPIOHIGH
86 */
87#define PM_PWER_GPIOHIGH FIELD(1, 1, 8)
88/*
89 * RTC alarm wake-up enable PM_PWER_RTC
90 */
91#define PM_PWER_RTC FIELD(1, 1, 31)
92
93#define PM_PCGR_BCLK64DDR FIELD(1, 1, 0)
94#define PM_PCGR_BCLK64VGA FIELD(1, 1, 1)
95#define PM_PCGR_BCLKDDR FIELD(1, 1, 2)
96#define PM_PCGR_BCLKPCI FIELD(1, 1, 4)
97#define PM_PCGR_BCLKDMAC FIELD(1, 1, 5)
98#define PM_PCGR_BCLKUMAL FIELD(1, 1, 6)
99#define PM_PCGR_BCLKUSB FIELD(1, 1, 7)
100#define PM_PCGR_BCLKMME FIELD(1, 1, 10)
101#define PM_PCGR_BCLKNAND FIELD(1, 1, 11)
102#define PM_PCGR_BCLKH264E FIELD(1, 1, 12)
103#define PM_PCGR_BCLKVGA FIELD(1, 1, 13)
104#define PM_PCGR_BCLKH264D FIELD(1, 1, 14)
105#define PM_PCGR_VECLK FIELD(1, 1, 15)
106#define PM_PCGR_HECLK FIELD(1, 1, 16)
107#define PM_PCGR_HDCLK FIELD(1, 1, 17)
108#define PM_PCGR_NANDCLK FIELD(1, 1, 18)
109#define PM_PCGR_GECLK FIELD(1, 1, 19)
110#define PM_PCGR_VGACLK FIELD(1, 1, 20)
111#define PM_PCGR_PCICLK FIELD(1, 1, 21)
112#define PM_PCGR_SATACLK FIELD(1, 1, 25)
113
114/*
115 * [23:20]PM_DIVCFG_VGACLK(v)
116 */
117#define PM_DIVCFG_VGACLK_MASK FMASK(4, 20)
118#define PM_DIVCFG_VGACLK(v) FIELD((v), 4, 20)
119
120#define PM_SWRESET_USB FIELD(1, 1, 6)
121#define PM_SWRESET_VGADIV FIELD(1, 1, 26)
122#define PM_SWRESET_GEDIV FIELD(1, 1, 27)
123
124#define PM_PLLDFCDONE_SYSDFC FIELD(1, 1, 0)
125#define PM_PLLDFCDONE_DDRDFC FIELD(1, 1, 1)
126#define PM_PLLDFCDONE_VGADFC FIELD(1, 1, 2)
diff --git a/arch/unicore32/include/mach/regs-ps2.h b/arch/unicore32/include/mach/regs-ps2.h
new file mode 100644
index 00000000000..17d4e6dc006
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-ps2.h
@@ -0,0 +1,20 @@
1/*
2 * PKUnity PS2 Controller Registers
3 */
4/*
5 * the same as I8042_DATA_REG PS2_DATA
6 */
7#define PS2_DATA (PKUNITY_PS2_BASE + 0x0060)
8/*
9 * the same as I8042_COMMAND_REG PS2_COMMAND
10 */
11#define PS2_COMMAND (PKUNITY_PS2_BASE + 0x0064)
12/*
13 * the same as I8042_STATUS_REG PS2_STATUS
14 */
15#define PS2_STATUS (PKUNITY_PS2_BASE + 0x0064)
16/*
17 * counter reg PS2_CNT
18 */
19#define PS2_CNT (PKUNITY_PS2_BASE + 0x0068)
20
diff --git a/arch/unicore32/include/mach/regs-resetc.h b/arch/unicore32/include/mach/regs-resetc.h
new file mode 100644
index 00000000000..39900cf4c93
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-resetc.h
@@ -0,0 +1,34 @@
1/*
2 * PKUnity Reset Controller (RC) Registers
3 */
4/*
5 * Software Reset Register
6 */
7#define RESETC_SWRR (PKUNITY_RESETC_BASE + 0x0000)
8/*
9 * Reset Status Register
10 */
11#define RESETC_RSSR (PKUNITY_RESETC_BASE + 0x0004)
12
13/*
14 * Software Reset Bit
15 */
16#define RESETC_SWRR_SRB FIELD(1, 1, 0)
17
18/*
19 * Hardware Reset
20 */
21#define RESETC_RSSR_HWR FIELD(1, 1, 0)
22/*
23 * Software Reset
24 */
25#define RESETC_RSSR_SWR FIELD(1, 1, 1)
26/*
27 * Watchdog Reset
28 */
29#define RESETC_RSSR_WDR FIELD(1, 1, 2)
30/*
31 * Sleep Mode Reset
32 */
33#define RESETC_RSSR_SMR FIELD(1, 1, 3)
34
diff --git a/arch/unicore32/include/mach/regs-rtc.h b/arch/unicore32/include/mach/regs-rtc.h
new file mode 100644
index 00000000000..e94ca193271
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-rtc.h
@@ -0,0 +1,37 @@
1/*
2 * PKUnity Real-Time Clock (RTC) control registers
3 */
4/*
5 * RTC Alarm Reg RTC_RTAR
6 */
7#define RTC_RTAR (PKUNITY_RTC_BASE + 0x0000)
8/*
9 * RTC Count Reg RTC_RCNR
10 */
11#define RTC_RCNR (PKUNITY_RTC_BASE + 0x0004)
12/*
13 * RTC Trim Reg RTC_RTTR
14 */
15#define RTC_RTTR (PKUNITY_RTC_BASE + 0x0008)
16/*
17 * RTC Status Reg RTC_RTSR
18 */
19#define RTC_RTSR (PKUNITY_RTC_BASE + 0x0010)
20
21/*
22 * ALarm detected RTC_RTSR_AL
23 */
24#define RTC_RTSR_AL FIELD(1, 1, 0)
25/*
26 * 1 Hz clock detected RTC_RTSR_HZ
27 */
28#define RTC_RTSR_HZ FIELD(1, 1, 1)
29/*
30 * ALarm interrupt Enable RTC_RTSR_ALE
31 */
32#define RTC_RTSR_ALE FIELD(1, 1, 2)
33/*
34 * 1 Hz clock interrupt Enable RTC_RTSR_HZE
35 */
36#define RTC_RTSR_HZE FIELD(1, 1, 3)
37
diff --git a/arch/unicore32/include/mach/regs-sdc.h b/arch/unicore32/include/mach/regs-sdc.h
new file mode 100644
index 00000000000..1303ecf660b
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-sdc.h
@@ -0,0 +1,156 @@
1/*
2 * PKUnity Multi-Media Card and Security Digital Card (MMC/SD) Registers
3 */
4/*
5 * Clock Control Reg SDC_CCR
6 */
7#define SDC_CCR (PKUNITY_SDC_BASE + 0x0000)
8/*
9 * Software Reset Reg SDC_SRR
10 */
11#define SDC_SRR (PKUNITY_SDC_BASE + 0x0004)
12/*
13 * Argument Reg SDC_ARGUMENT
14 */
15#define SDC_ARGUMENT (PKUNITY_SDC_BASE + 0x0008)
16/*
17 * Command Reg SDC_COMMAND
18 */
19#define SDC_COMMAND (PKUNITY_SDC_BASE + 0x000C)
20/*
21 * Block Size Reg SDC_BLOCKSIZE
22 */
23#define SDC_BLOCKSIZE (PKUNITY_SDC_BASE + 0x0010)
24/*
25 * Block Cound Reg SDC_BLOCKCOUNT
26 */
27#define SDC_BLOCKCOUNT (PKUNITY_SDC_BASE + 0x0014)
28/*
29 * Transfer Mode Reg SDC_TMR
30 */
31#define SDC_TMR (PKUNITY_SDC_BASE + 0x0018)
32/*
33 * Response Reg. 0 SDC_RES0
34 */
35#define SDC_RES0 (PKUNITY_SDC_BASE + 0x001C)
36/*
37 * Response Reg. 1 SDC_RES1
38 */
39#define SDC_RES1 (PKUNITY_SDC_BASE + 0x0020)
40/*
41 * Response Reg. 2 SDC_RES2
42 */
43#define SDC_RES2 (PKUNITY_SDC_BASE + 0x0024)
44/*
45 * Response Reg. 3 SDC_RES3
46 */
47#define SDC_RES3 (PKUNITY_SDC_BASE + 0x0028)
48/*
49 * Read Timeout Control Reg SDC_RTCR
50 */
51#define SDC_RTCR (PKUNITY_SDC_BASE + 0x002C)
52/*
53 * Interrupt Status Reg SDC_ISR
54 */
55#define SDC_ISR (PKUNITY_SDC_BASE + 0x0030)
56/*
57 * Interrupt Status Mask Reg SDC_ISMR
58 */
59#define SDC_ISMR (PKUNITY_SDC_BASE + 0x0034)
60/*
61 * RX FIFO SDC_RXFIFO
62 */
63#define SDC_RXFIFO (PKUNITY_SDC_BASE + 0x0038)
64/*
65 * TX FIFO SDC_TXFIFO
66 */
67#define SDC_TXFIFO (PKUNITY_SDC_BASE + 0x003C)
68
69/*
70 * SD Clock Enable SDC_CCR_CLKEN
71 */
72#define SDC_CCR_CLKEN FIELD(1, 1, 2)
73/*
74 * [15:8] SDC_CCR_PDIV(v)
75 */
76#define SDC_CCR_PDIV(v) FIELD((v), 8, 8)
77
78/*
79 * Software reset enable SDC_SRR_ENABLE
80 */
81#define SDC_SRR_ENABLE FIELD(0, 1, 0)
82/*
83 * Software reset disable SDC_SRR_DISABLE
84 */
85#define SDC_SRR_DISABLE FIELD(1, 1, 0)
86
87/*
88 * Response type SDC_COMMAND_RESTYPE_MASK
89 */
90#define SDC_COMMAND_RESTYPE_MASK FMASK(2, 0)
91/*
92 * No response SDC_COMMAND_RESTYPE_NONE
93 */
94#define SDC_COMMAND_RESTYPE_NONE FIELD(0, 2, 0)
95/*
96 * 136-bit long response SDC_COMMAND_RESTYPE_LONG
97 */
98#define SDC_COMMAND_RESTYPE_LONG FIELD(1, 2, 0)
99/*
100 * 48-bit short response SDC_COMMAND_RESTYPE_SHORT
101 */
102#define SDC_COMMAND_RESTYPE_SHORT FIELD(2, 2, 0)
103/*
104 * 48-bit short and test if busy response SDC_COMMAND_RESTYPE_SHORTBUSY
105 */
106#define SDC_COMMAND_RESTYPE_SHORTBUSY FIELD(3, 2, 0)
107/*
108 * data ready SDC_COMMAND_DATAREADY
109 */
110#define SDC_COMMAND_DATAREADY FIELD(1, 1, 2)
111#define SDC_COMMAND_CMDEN FIELD(1, 1, 3)
112/*
113 * [10:5] SDC_COMMAND_CMDINDEX(v)
114 */
115#define SDC_COMMAND_CMDINDEX(v) FIELD((v), 6, 5)
116
117/*
118 * [10:0] SDC_BLOCKSIZE_BSMASK(v)
119 */
120#define SDC_BLOCKSIZE_BSMASK(v) FIELD((v), 11, 0)
121/*
122 * [11:0] SDC_BLOCKCOUNT_BCMASK(v)
123 */
124#define SDC_BLOCKCOUNT_BCMASK(v) FIELD((v), 12, 0)
125
126/*
127 * Data Width 1bit SDC_TMR_WTH_1BIT
128 */
129#define SDC_TMR_WTH_1BIT FIELD(0, 1, 0)
130/*
131 * Data Width 4bit SDC_TMR_WTH_4BIT
132 */
133#define SDC_TMR_WTH_4BIT FIELD(1, 1, 0)
134/*
135 * Read SDC_TMR_DIR_READ
136 */
137#define SDC_TMR_DIR_READ FIELD(0, 1, 1)
138/*
139 * Write SDC_TMR_DIR_WRITE
140 */
141#define SDC_TMR_DIR_WRITE FIELD(1, 1, 1)
142
143#define SDC_IR_MASK FMASK(13, 0)
144#define SDC_IR_RESTIMEOUT FIELD(1, 1, 0)
145#define SDC_IR_WRITECRC FIELD(1, 1, 1)
146#define SDC_IR_READCRC FIELD(1, 1, 2)
147#define SDC_IR_TXFIFOREAD FIELD(1, 1, 3)
148#define SDC_IR_RXFIFOWRITE FIELD(1, 1, 4)
149#define SDC_IR_READTIMEOUT FIELD(1, 1, 5)
150#define SDC_IR_DATACOMPLETE FIELD(1, 1, 6)
151#define SDC_IR_CMDCOMPLETE FIELD(1, 1, 7)
152#define SDC_IR_RXFIFOFULL FIELD(1, 1, 8)
153#define SDC_IR_RXFIFOEMPTY FIELD(1, 1, 9)
154#define SDC_IR_TXFIFOFULL FIELD(1, 1, 10)
155#define SDC_IR_TXFIFOEMPTY FIELD(1, 1, 11)
156#define SDC_IR_ENDCMDWITHRES FIELD(1, 1, 12)
diff --git a/arch/unicore32/include/mach/regs-spi.h b/arch/unicore32/include/mach/regs-spi.h
new file mode 100644
index 00000000000..de16895e2dc
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-spi.h
@@ -0,0 +1,98 @@
1/*
2 * PKUnity Serial Peripheral Interface (SPI) Registers
3 */
4/*
5 * Control reg. 0 SPI_CR0
6 */
7#define SPI_CR0 (PKUNITY_SPI_BASE + 0x0000)
8/*
9 * Control reg. 1 SPI_CR1
10 */
11#define SPI_CR1 (PKUNITY_SPI_BASE + 0x0004)
12/*
13 * Enable reg SPI_SSIENR
14 */
15#define SPI_SSIENR (PKUNITY_SPI_BASE + 0x0008)
16/*
17 * Status reg SPI_SR
18 */
19#define SPI_SR (PKUNITY_SPI_BASE + 0x0028)
20/*
21 * Interrupt Mask reg SPI_IMR
22 */
23#define SPI_IMR (PKUNITY_SPI_BASE + 0x002C)
24/*
25 * Interrupt Status reg SPI_ISR
26 */
27#define SPI_ISR (PKUNITY_SPI_BASE + 0x0030)
28
29/*
30 * Enable SPI Controller SPI_SSIENR_EN
31 */
32#define SPI_SSIENR_EN FIELD(1, 1, 0)
33
34/*
35 * SPI Busy SPI_SR_BUSY
36 */
37#define SPI_SR_BUSY FIELD(1, 1, 0)
38/*
39 * Transmit FIFO Not Full SPI_SR_TFNF
40 */
41#define SPI_SR_TFNF FIELD(1, 1, 1)
42/*
43 * Transmit FIFO Empty SPI_SR_TFE
44 */
45#define SPI_SR_TFE FIELD(1, 1, 2)
46/*
47 * Receive FIFO Not Empty SPI_SR_RFNE
48 */
49#define SPI_SR_RFNE FIELD(1, 1, 3)
50/*
51 * Receive FIFO Full SPI_SR_RFF
52 */
53#define SPI_SR_RFF FIELD(1, 1, 4)
54
55/*
56 * Trans. FIFO Empty Interrupt Status SPI_ISR_TXEIS
57 */
58#define SPI_ISR_TXEIS FIELD(1, 1, 0)
59/*
60 * Trans. FIFO Overflow Interrupt Status SPI_ISR_TXOIS
61 */
62#define SPI_ISR_TXOIS FIELD(1, 1, 1)
63/*
64 * Receiv. FIFO Underflow Interrupt Status SPI_ISR_RXUIS
65 */
66#define SPI_ISR_RXUIS FIELD(1, 1, 2)
67/*
68 * Receiv. FIFO Overflow Interrupt Status SPI_ISR_RXOIS
69 */
70#define SPI_ISR_RXOIS FIELD(1, 1, 3)
71/*
72 * Receiv. FIFO Full Interrupt Status SPI_ISR_RXFIS
73 */
74#define SPI_ISR_RXFIS FIELD(1, 1, 4)
75#define SPI_ISR_MSTIS FIELD(1, 1, 5)
76
77/*
78 * Trans. FIFO Empty Interrupt Mask SPI_IMR_TXEIM
79 */
80#define SPI_IMR_TXEIM FIELD(1, 1, 0)
81/*
82 * Trans. FIFO Overflow Interrupt Mask SPI_IMR_TXOIM
83 */
84#define SPI_IMR_TXOIM FIELD(1, 1, 1)
85/*
86 * Receiv. FIFO Underflow Interrupt Mask SPI_IMR_RXUIM
87 */
88#define SPI_IMR_RXUIM FIELD(1, 1, 2)
89/*
90 * Receiv. FIFO Overflow Interrupt Mask SPI_IMR_RXOIM
91 */
92#define SPI_IMR_RXOIM FIELD(1, 1, 3)
93/*
94 * Receiv. FIFO Full Interrupt Mask SPI_IMR_RXFIM
95 */
96#define SPI_IMR_RXFIM FIELD(1, 1, 4)
97#define SPI_IMR_MSTIM FIELD(1, 1, 5)
98
diff --git a/arch/unicore32/include/mach/regs-uart.h b/arch/unicore32/include/mach/regs-uart.h
new file mode 100644
index 00000000000..9fa6b1938b7
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-uart.h
@@ -0,0 +1,3 @@
1/*
2 * PKUnity Universal Asynchronous Receiver/Transmitter (UART) Registers
3 */
diff --git a/arch/unicore32/include/mach/regs-umal.h b/arch/unicore32/include/mach/regs-umal.h
new file mode 100644
index 00000000000..885bb62fee7
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-umal.h
@@ -0,0 +1,229 @@
1/*
2 * PKUnity Ultra Media Access Layer (UMAL) Ethernet MAC Registers
3 */
4
5/* MAC module of UMAL */
6/* UMAL's MAC module includes G/MII interface, several additional PHY
7 * interfaces, and MAC control sub-layer, which provides support for control
8 * frames (e.g. PAUSE frames).
9 */
10/*
11 * TX/RX reset and control UMAL_CFG1
12 */
13#define UMAL_CFG1 (PKUNITY_UMAL_BASE + 0x0000)
14/*
15 * MAC interface mode control UMAL_CFG2
16 */
17#define UMAL_CFG2 (PKUNITY_UMAL_BASE + 0x0004)
18/*
19 * Inter Packet/Frame Gap UMAL_IPGIFG
20 */
21#define UMAL_IPGIFG (PKUNITY_UMAL_BASE + 0x0008)
22/*
23 * Collision retry or backoff UMAL_HALFDUPLEX
24 */
25#define UMAL_HALFDUPLEX (PKUNITY_UMAL_BASE + 0x000c)
26/*
27 * Maximum Frame Length UMAL_MAXFRAME
28 */
29#define UMAL_MAXFRAME (PKUNITY_UMAL_BASE + 0x0010)
30/*
31 * Test Regsiter UMAL_TESTREG
32 */
33#define UMAL_TESTREG (PKUNITY_UMAL_BASE + 0x001c)
34/*
35 * MII Management Configure UMAL_MIICFG
36 */
37#define UMAL_MIICFG (PKUNITY_UMAL_BASE + 0x0020)
38/*
39 * MII Management Command UMAL_MIICMD
40 */
41#define UMAL_MIICMD (PKUNITY_UMAL_BASE + 0x0024)
42/*
43 * MII Management Address UMAL_MIIADDR
44 */
45#define UMAL_MIIADDR (PKUNITY_UMAL_BASE + 0x0028)
46/*
47 * MII Management Control UMAL_MIICTRL
48 */
49#define UMAL_MIICTRL (PKUNITY_UMAL_BASE + 0x002c)
50/*
51 * MII Management Status UMAL_MIISTATUS
52 */
53#define UMAL_MIISTATUS (PKUNITY_UMAL_BASE + 0x0030)
54/*
55 * MII Managment Indicator UMAL_MIIIDCT
56 */
57#define UMAL_MIIIDCT (PKUNITY_UMAL_BASE + 0x0034)
58/*
59 * Interface Control UMAL_IFCTRL
60 */
61#define UMAL_IFCTRL (PKUNITY_UMAL_BASE + 0x0038)
62/*
63 * Interface Status UMAL_IFSTATUS
64 */
65#define UMAL_IFSTATUS (PKUNITY_UMAL_BASE + 0x003c)
66/*
67 * MAC address (high 4 bytes) UMAL_STADDR1
68 */
69#define UMAL_STADDR1 (PKUNITY_UMAL_BASE + 0x0040)
70/*
71 * MAC address (low 2 bytes) UMAL_STADDR2
72 */
73#define UMAL_STADDR2 (PKUNITY_UMAL_BASE + 0x0044)
74
75/* FIFO MODULE OF UMAL */
76/* UMAL's FIFO module provides data queuing for increased system level
77 * throughput
78 */
79#define UMAL_FIFOCFG0 (PKUNITY_UMAL_BASE + 0x0048)
80#define UMAL_FIFOCFG1 (PKUNITY_UMAL_BASE + 0x004c)
81#define UMAL_FIFOCFG2 (PKUNITY_UMAL_BASE + 0x0050)
82#define UMAL_FIFOCFG3 (PKUNITY_UMAL_BASE + 0x0054)
83#define UMAL_FIFOCFG4 (PKUNITY_UMAL_BASE + 0x0058)
84#define UMAL_FIFOCFG5 (PKUNITY_UMAL_BASE + 0x005c)
85#define UMAL_FIFORAM0 (PKUNITY_UMAL_BASE + 0x0060)
86#define UMAL_FIFORAM1 (PKUNITY_UMAL_BASE + 0x0064)
87#define UMAL_FIFORAM2 (PKUNITY_UMAL_BASE + 0x0068)
88#define UMAL_FIFORAM3 (PKUNITY_UMAL_BASE + 0x006c)
89#define UMAL_FIFORAM4 (PKUNITY_UMAL_BASE + 0x0070)
90#define UMAL_FIFORAM5 (PKUNITY_UMAL_BASE + 0x0074)
91#define UMAL_FIFORAM6 (PKUNITY_UMAL_BASE + 0x0078)
92#define UMAL_FIFORAM7 (PKUNITY_UMAL_BASE + 0x007c)
93
94/* MAHBE MODUEL OF UMAL */
95/* UMAL's MAHBE module interfaces to the host system through 32-bit AHB Master
96 * and Slave ports.Registers within the M-AHBE provide Control and Status
97 * information concerning these transfers.
98 */
99/*
100 * Transmit Control UMAL_DMATxCtrl
101 */
102#define UMAL_DMATxCtrl (PKUNITY_UMAL_BASE + 0x0180)
103/*
104 * Pointer to TX Descripter UMAL_DMATxDescriptor
105 */
106#define UMAL_DMATxDescriptor (PKUNITY_UMAL_BASE + 0x0184)
107/*
108 * Status of Tx Packet Transfers UMAL_DMATxStatus
109 */
110#define UMAL_DMATxStatus (PKUNITY_UMAL_BASE + 0x0188)
111/*
112 * Receive Control UMAL_DMARxCtrl
113 */
114#define UMAL_DMARxCtrl (PKUNITY_UMAL_BASE + 0x018c)
115/*
116 * Pointer to Rx Descriptor UMAL_DMARxDescriptor
117 */
118#define UMAL_DMARxDescriptor (PKUNITY_UMAL_BASE + 0x0190)
119/*
120 * Status of Rx Packet Transfers UMAL_DMARxStatus
121 */
122#define UMAL_DMARxStatus (PKUNITY_UMAL_BASE + 0x0194)
123/*
124 * Interrupt Mask UMAL_DMAIntrMask
125 */
126#define UMAL_DMAIntrMask (PKUNITY_UMAL_BASE + 0x0198)
127/*
128 * Interrupts, read only UMAL_DMAInterrupt
129 */
130#define UMAL_DMAInterrupt (PKUNITY_UMAL_BASE + 0x019c)
131
132/*
133 * Commands for UMAL_CFG1 register
134 */
135#define UMAL_CFG1_TXENABLE FIELD(1, 1, 0)
136#define UMAL_CFG1_RXENABLE FIELD(1, 1, 2)
137#define UMAL_CFG1_TXFLOWCTL FIELD(1, 1, 4)
138#define UMAL_CFG1_RXFLOWCTL FIELD(1, 1, 5)
139#define UMAL_CFG1_CONFLPBK FIELD(1, 1, 8)
140#define UMAL_CFG1_RESET FIELD(1, 1, 31)
141#define UMAL_CFG1_CONFFLCTL (MAC_TX_FLOW_CTL | MAC_RX_FLOW_CTL)
142
143/*
144 * Commands for UMAL_CFG2 register
145 */
146#define UMAL_CFG2_FULLDUPLEX FIELD(1, 1, 0)
147#define UMAL_CFG2_CRCENABLE FIELD(1, 1, 1)
148#define UMAL_CFG2_PADCRC FIELD(1, 1, 2)
149#define UMAL_CFG2_LENGTHCHECK FIELD(1, 1, 4)
150#define UMAL_CFG2_MODEMASK FMASK(2, 8)
151#define UMAL_CFG2_NIBBLEMODE FIELD(1, 2, 8)
152#define UMAL_CFG2_BYTEMODE FIELD(2, 2, 8)
153#define UMAL_CFG2_PREAMBLENMASK FMASK(4, 12)
154#define UMAL_CFG2_DEFPREAMBLEN FIELD(7, 4, 12)
155#define UMAL_CFG2_FD100 (UMAL_CFG2_DEFPREAMBLEN | UMAL_CFG2_NIBBLEMODE \
156 | UMAL_CFG2_LENGTHCHECK | UMAL_CFG2_PADCRC \
157 | UMAL_CFG2_CRCENABLE | UMAL_CFG2_FULLDUPLEX)
158#define UMAL_CFG2_FD1000 (UMAL_CFG2_DEFPREAMBLEN | UMAL_CFG2_BYTEMODE \
159 | UMAL_CFG2_LENGTHCHECK | UMAL_CFG2_PADCRC \
160 | UMAL_CFG2_CRCENABLE | UMAL_CFG2_FULLDUPLEX)
161#define UMAL_CFG2_HD100 (UMAL_CFG2_DEFPREAMBLEN | UMAL_CFG2_NIBBLEMODE \
162 | UMAL_CFG2_LENGTHCHECK | UMAL_CFG2_PADCRC \
163 | UMAL_CFG2_CRCENABLE)
164
165/*
166 * Command for UMAL_IFCTRL register
167 */
168#define UMAL_IFCTRL_RESET FIELD(1, 1, 31)
169
170/*
171 * Command for UMAL_MIICFG register
172 */
173#define UMAL_MIICFG_RESET FIELD(1, 1, 31)
174
175/*
176 * Command for UMAL_MIICMD register
177 */
178#define UMAL_MIICMD_READ FIELD(1, 1, 0)
179
180/*
181 * Command for UMAL_MIIIDCT register
182 */
183#define UMAL_MIIIDCT_BUSY FIELD(1, 1, 0)
184#define UMAL_MIIIDCT_NOTVALID FIELD(1, 1, 2)
185
186/*
187 * Commands for DMATxCtrl regesters
188 */
189#define UMAL_DMA_Enable FIELD(1, 1, 0)
190
191/*
192 * Commands for DMARxCtrl regesters
193 */
194#define UMAL_DMAIntrMask_ENABLEHALFWORD FIELD(1, 1, 16)
195
196/*
197 * Command for DMARxStatus
198 */
199#define CLR_RX_BUS_ERR FIELD(1, 1, 3)
200#define CLR_RX_OVERFLOW FIELD(1, 1, 2)
201#define CLR_RX_PKT FIELD(1, 1, 0)
202
203/*
204 * Command for DMATxStatus
205 */
206#define CLR_TX_BUS_ERR FIELD(1, 1, 3)
207#define CLR_TX_UNDERRUN FIELD(1, 1, 1)
208#define CLR_TX_PKT FIELD(1, 1, 0)
209
210/*
211 * Commands for DMAIntrMask and DMAInterrupt register
212 */
213#define INT_RX_MASK FIELD(0xd, 4, 4)
214#define INT_TX_MASK FIELD(0xb, 4, 0)
215
216#define INT_RX_BUS_ERR FIELD(1, 1, 7)
217#define INT_RX_OVERFLOW FIELD(1, 1, 6)
218#define INT_RX_PKT FIELD(1, 1, 4)
219#define INT_TX_BUS_ERR FIELD(1, 1, 3)
220#define INT_TX_UNDERRUN FIELD(1, 1, 1)
221#define INT_TX_PKT FIELD(1, 1, 0)
222
223/*
224 * MARCOS of UMAL's descriptors
225 */
226#define UMAL_DESC_PACKETSIZE_EMPTY FIELD(1, 1, 31)
227#define UMAL_DESC_PACKETSIZE_NONEMPTY FIELD(0, 1, 31)
228#define UMAL_DESC_PACKETSIZE_SIZEMASK FMASK(12, 0)
229
diff --git a/arch/unicore32/include/mach/regs-unigfx.h b/arch/unicore32/include/mach/regs-unigfx.h
new file mode 100644
index 00000000000..faf8b287fcc
--- /dev/null
+++ b/arch/unicore32/include/mach/regs-unigfx.h
@@ -0,0 +1,200 @@
1/*
2 * PKUnity UNIGFX Registers
3 */
4
5#define UDE_BASE (PKUNITY_UNIGFX_BASE + 0x1400)
6#define UGE_BASE (PKUNITY_UNIGFX_BASE + 0x0000)
7
8/*
9 * command reg for UNIGFX DE
10 */
11/*
12 * control reg UDE_CFG
13 */
14#define UDE_CFG (UDE_BASE + 0x0000)
15/*
16 * framebuffer start address reg UDE_FSA
17 */
18#define UDE_FSA (UDE_BASE + 0x0004)
19/*
20 * line size reg UDE_LS
21 */
22#define UDE_LS (UDE_BASE + 0x0008)
23/*
24 * pitch size reg UDE_PS
25 */
26#define UDE_PS (UDE_BASE + 0x000C)
27/*
28 * horizontal active time reg UDE_HAT
29 */
30#define UDE_HAT (UDE_BASE + 0x0010)
31/*
32 * horizontal blank time reg UDE_HBT
33 */
34#define UDE_HBT (UDE_BASE + 0x0014)
35/*
36 * horizontal sync time reg UDE_HST
37 */
38#define UDE_HST (UDE_BASE + 0x0018)
39/*
40 * vertival active time reg UDE_VAT
41 */
42#define UDE_VAT (UDE_BASE + 0x001C)
43/*
44 * vertival blank time reg UDE_VBT
45 */
46#define UDE_VBT (UDE_BASE + 0x0020)
47/*
48 * vertival sync time reg UDE_VST
49 */
50#define UDE_VST (UDE_BASE + 0x0024)
51/*
52 * cursor position UDE_CXY
53 */
54#define UDE_CXY (UDE_BASE + 0x0028)
55/*
56 * cursor front color UDE_CC0
57 */
58#define UDE_CC0 (UDE_BASE + 0x002C)
59/*
60 * cursor background color UDE_CC1
61 */
62#define UDE_CC1 (UDE_BASE + 0x0030)
63/*
64 * video position UDE_VXY
65 */
66#define UDE_VXY (UDE_BASE + 0x0034)
67/*
68 * video start address reg UDE_VSA
69 */
70#define UDE_VSA (UDE_BASE + 0x0040)
71/*
72 * video size reg UDE_VS
73 */
74#define UDE_VS (UDE_BASE + 0x004C)
75
76/*
77 * command reg for UNIGFX GE
78 */
79/*
80 * src xy reg UGE_SRCXY
81 */
82#define UGE_SRCXY (UGE_BASE + 0x0000)
83/*
84 * dst xy reg UGE_DSTXY
85 */
86#define UGE_DSTXY (UGE_BASE + 0x0004)
87/*
88 * pitch reg UGE_PITCH
89 */
90#define UGE_PITCH (UGE_BASE + 0x0008)
91/*
92 * src start reg UGE_SRCSTART
93 */
94#define UGE_SRCSTART (UGE_BASE + 0x000C)
95/*
96 * dst start reg UGE_DSTSTART
97 */
98#define UGE_DSTSTART (UGE_BASE + 0x0010)
99/*
100 * width height reg UGE_WIDHEIGHT
101 */
102#define UGE_WIDHEIGHT (UGE_BASE + 0x0014)
103/*
104 * rop alpah reg UGE_ROPALPHA
105 */
106#define UGE_ROPALPHA (UGE_BASE + 0x0018)
107/*
108 * front color UGE_FCOLOR
109 */
110#define UGE_FCOLOR (UGE_BASE + 0x001C)
111/*
112 * background color UGE_BCOLOR
113 */
114#define UGE_BCOLOR (UGE_BASE + 0x0020)
115/*
116 * src color key for high value UGE_SCH
117 */
118#define UGE_SCH (UGE_BASE + 0x0024)
119/*
120 * dst color key for high value UGE_DCH
121 */
122#define UGE_DCH (UGE_BASE + 0x0028)
123/*
124 * src color key for low value UGE_SCL
125 */
126#define UGE_SCL (UGE_BASE + 0x002C)
127/*
128 * dst color key for low value UGE_DCL
129 */
130#define UGE_DCL (UGE_BASE + 0x0030)
131/*
132 * clip 0 reg UGE_CLIP0
133 */
134#define UGE_CLIP0 (UGE_BASE + 0x0034)
135/*
136 * clip 1 reg UGE_CLIP1
137 */
138#define UGE_CLIP1 (UGE_BASE + 0x0038)
139/*
140 * command reg UGE_COMMAND
141 */
142#define UGE_COMMAND (UGE_BASE + 0x003C)
143/*
144 * pattern 0 UGE_P0
145 */
146#define UGE_P0 (UGE_BASE + 0x0040)
147#define UGE_P1 (UGE_BASE + 0x0044)
148#define UGE_P2 (UGE_BASE + 0x0048)
149#define UGE_P3 (UGE_BASE + 0x004C)
150#define UGE_P4 (UGE_BASE + 0x0050)
151#define UGE_P5 (UGE_BASE + 0x0054)
152#define UGE_P6 (UGE_BASE + 0x0058)
153#define UGE_P7 (UGE_BASE + 0x005C)
154#define UGE_P8 (UGE_BASE + 0x0060)
155#define UGE_P9 (UGE_BASE + 0x0064)
156#define UGE_P10 (UGE_BASE + 0x0068)
157#define UGE_P11 (UGE_BASE + 0x006C)
158#define UGE_P12 (UGE_BASE + 0x0070)
159#define UGE_P13 (UGE_BASE + 0x0074)
160#define UGE_P14 (UGE_BASE + 0x0078)
161#define UGE_P15 (UGE_BASE + 0x007C)
162#define UGE_P16 (UGE_BASE + 0x0080)
163#define UGE_P17 (UGE_BASE + 0x0084)
164#define UGE_P18 (UGE_BASE + 0x0088)
165#define UGE_P19 (UGE_BASE + 0x008C)
166#define UGE_P20 (UGE_BASE + 0x0090)
167#define UGE_P21 (UGE_BASE + 0x0094)
168#define UGE_P22 (UGE_BASE + 0x0098)
169#define UGE_P23 (UGE_BASE + 0x009C)
170#define UGE_P24 (UGE_BASE + 0x00A0)
171#define UGE_P25 (UGE_BASE + 0x00A4)
172#define UGE_P26 (UGE_BASE + 0x00A8)
173#define UGE_P27 (UGE_BASE + 0x00AC)
174#define UGE_P28 (UGE_BASE + 0x00B0)
175#define UGE_P29 (UGE_BASE + 0x00B4)
176#define UGE_P30 (UGE_BASE + 0x00B8)
177#define UGE_P31 (UGE_BASE + 0x00BC)
178
179#define UDE_CFG_DST_MASK FMASK(2, 8)
180#define UDE_CFG_DST8 FIELD(0x0, 2, 8)
181#define UDE_CFG_DST16 FIELD(0x1, 2, 8)
182#define UDE_CFG_DST24 FIELD(0x2, 2, 8)
183#define UDE_CFG_DST32 FIELD(0x3, 2, 8)
184
185/*
186 * GDEN enable UDE_CFG_GDEN_ENABLE
187 */
188#define UDE_CFG_GDEN_ENABLE FIELD(1, 1, 3)
189/*
190 * VDEN enable UDE_CFG_VDEN_ENABLE
191 */
192#define UDE_CFG_VDEN_ENABLE FIELD(1, 1, 4)
193/*
194 * CDEN enable UDE_CFG_CDEN_ENABLE
195 */
196#define UDE_CFG_CDEN_ENABLE FIELD(1, 1, 5)
197/*
198 * TIMEUP enable UDE_CFG_TIMEUP_ENABLE
199 */
200#define UDE_CFG_TIMEUP_ENABLE FIELD(1, 1, 6)
diff --git a/arch/unicore32/include/mach/uncompress.h b/arch/unicore32/include/mach/uncompress.h
new file mode 100644
index 00000000000..142d3e7958a
--- /dev/null
+++ b/arch/unicore32/include/mach/uncompress.h
@@ -0,0 +1,34 @@
1/*
2 * linux/arch/unicore32/include/mach/uncompress.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#ifndef __MACH_PUV3_UNCOMPRESS_H__
14#define __MACH_PUV3_UNCOMPRESS_H__
15
16#include "hardware.h"
17#include "ocd.h"
18
19extern char input_data[];
20extern char input_data_end[];
21
22static void arch_decomp_puts(const char *ptr)
23{
24 char c;
25
26 while ((c = *ptr++) != '\0') {
27 if (c == '\n')
28 putc('\r');
29 putc(c);
30 }
31}
32#define ARCH_HAVE_DECOMP_PUTS
33
34#endif /* __MACH_PUV3_UNCOMPRESS_H__ */
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
new file mode 100644
index 00000000000..ec23a2fb2f5
--- /dev/null
+++ b/arch/unicore32/kernel/Makefile
@@ -0,0 +1,33 @@
1#
2# Makefile for the linux kernel.
3#
4
5# Object file lists.
6obj-y := dma.o elf.o entry.o process.o ptrace.o
7obj-y += setup.o signal.o sys.o stacktrace.o traps.o
8
9obj-$(CONFIG_MODULES) += ksyms.o module.o
10obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
11
12obj-$(CONFIG_CPU_FREQ) += cpu-ucv2.o
13obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
14
15# obj-y for architecture PKUnity v3
16obj-$(CONFIG_ARCH_PUV3) += clock.o irq.o time.o
17
18obj-$(CONFIG_PUV3_GPIO) += gpio.o
19obj-$(CONFIG_PUV3_RTC) += rtc.o
20obj-$(CONFIG_PUV3_PWM) += pwm.o
21obj-$(CONFIG_PUV3_PM) += pm.o sleep.o
22obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o
23
24obj-$(CONFIG_PCI) += pci.o
25
26# obj-y for specific machines
27obj-$(CONFIG_ARCH_PUV3) += puv3-core.o
28obj-$(CONFIG_PUV3_NB0916) += puv3-nb0916.o
29
30head-y := head.o
31obj-$(CONFIG_DEBUG_LL) += debug.o
32
33extra-y := $(head-y) init_task.o vmlinux.lds
diff --git a/arch/unicore32/kernel/asm-offsets.c b/arch/unicore32/kernel/asm-offsets.c
new file mode 100644
index 00000000000..ffcbe7536ca
--- /dev/null
+++ b/arch/unicore32/kernel/asm-offsets.c
@@ -0,0 +1,112 @@
1/*
2 * linux/arch/unicore32/kernel/asm-offsets.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * Generate definitions needed by assembly language modules.
9 * This code generates raw asm output which is post-processed to extract
10 * and format the required data.
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 version 2 as
14 * published by the Free Software Foundation.
15 */
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/dma-mapping.h>
19#include <linux/kbuild.h>
20#include <linux/suspend.h>
21#include <linux/thread_info.h>
22#include <asm/memory.h>
23#include <asm/suspend.h>
24
25/*
26 * GCC 3.0, 3.1: general bad code generation.
27 * GCC 3.2.0: incorrect function argument offset calculation.
28 * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
29 * (http://gcc.gnu.org/PR8896) and incorrect structure
30 * initialisation in fs/jffs2/erase.c
31 */
32#if (__GNUC__ < 4)
33#error Your compiler should upgrade to uc4
34#error Known good compilers: 4.2.2
35#endif
36
37int main(void)
38{
39 DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
40 BLANK();
41 DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
42 DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
43 DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit));
44 DEFINE(TI_TASK, offsetof(struct thread_info, task));
45 DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain));
46 DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
47 DEFINE(TI_CPU_SAVE, offsetof(struct thread_info, cpu_context));
48 DEFINE(TI_USED_CP, offsetof(struct thread_info, used_cp));
49#ifdef CONFIG_UNICORE_FPU_F64
50 DEFINE(TI_FPSTATE, offsetof(struct thread_info, fpstate));
51#endif
52 BLANK();
53 DEFINE(S_R0, offsetof(struct pt_regs, UCreg_00));
54 DEFINE(S_R1, offsetof(struct pt_regs, UCreg_01));
55 DEFINE(S_R2, offsetof(struct pt_regs, UCreg_02));
56 DEFINE(S_R3, offsetof(struct pt_regs, UCreg_03));
57 DEFINE(S_R4, offsetof(struct pt_regs, UCreg_04));
58 DEFINE(S_R5, offsetof(struct pt_regs, UCreg_05));
59 DEFINE(S_R6, offsetof(struct pt_regs, UCreg_06));
60 DEFINE(S_R7, offsetof(struct pt_regs, UCreg_07));
61 DEFINE(S_R8, offsetof(struct pt_regs, UCreg_08));
62 DEFINE(S_R9, offsetof(struct pt_regs, UCreg_09));
63 DEFINE(S_R10, offsetof(struct pt_regs, UCreg_10));
64 DEFINE(S_R11, offsetof(struct pt_regs, UCreg_11));
65 DEFINE(S_R12, offsetof(struct pt_regs, UCreg_12));
66 DEFINE(S_R13, offsetof(struct pt_regs, UCreg_13));
67 DEFINE(S_R14, offsetof(struct pt_regs, UCreg_14));
68 DEFINE(S_R15, offsetof(struct pt_regs, UCreg_15));
69 DEFINE(S_R16, offsetof(struct pt_regs, UCreg_16));
70 DEFINE(S_R17, offsetof(struct pt_regs, UCreg_17));
71 DEFINE(S_R18, offsetof(struct pt_regs, UCreg_18));
72 DEFINE(S_R19, offsetof(struct pt_regs, UCreg_19));
73 DEFINE(S_R20, offsetof(struct pt_regs, UCreg_20));
74 DEFINE(S_R21, offsetof(struct pt_regs, UCreg_21));
75 DEFINE(S_R22, offsetof(struct pt_regs, UCreg_22));
76 DEFINE(S_R23, offsetof(struct pt_regs, UCreg_23));
77 DEFINE(S_R24, offsetof(struct pt_regs, UCreg_24));
78 DEFINE(S_R25, offsetof(struct pt_regs, UCreg_25));
79 DEFINE(S_R26, offsetof(struct pt_regs, UCreg_26));
80 DEFINE(S_FP, offsetof(struct pt_regs, UCreg_fp));
81 DEFINE(S_IP, offsetof(struct pt_regs, UCreg_ip));
82 DEFINE(S_SP, offsetof(struct pt_regs, UCreg_sp));
83 DEFINE(S_LR, offsetof(struct pt_regs, UCreg_lr));
84 DEFINE(S_PC, offsetof(struct pt_regs, UCreg_pc));
85 DEFINE(S_PSR, offsetof(struct pt_regs, UCreg_asr));
86 DEFINE(S_OLD_R0, offsetof(struct pt_regs, UCreg_ORIG_00));
87 DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
88 BLANK();
89 DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));
90 DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags));
91 BLANK();
92 DEFINE(VM_EXEC, VM_EXEC);
93 BLANK();
94 DEFINE(PAGE_SZ, PAGE_SIZE);
95 BLANK();
96 DEFINE(SYS_ERROR0, 0x9f0000);
97 BLANK();
98 DEFINE(PBE_ADDRESS, offsetof(struct pbe, address));
99 DEFINE(PBE_ORIN_ADDRESS, offsetof(struct pbe, orig_address));
100 DEFINE(PBE_NEXT, offsetof(struct pbe, next));
101 DEFINE(SWSUSP_CPU, offsetof(struct swsusp_arch_regs, \
102 cpu_context));
103#ifdef CONFIG_UNICORE_FPU_F64
104 DEFINE(SWSUSP_FPSTATE, offsetof(struct swsusp_arch_regs, \
105 fpstate));
106#endif
107 BLANK();
108 DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL);
109 DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE);
110 DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE);
111 return 0;
112}
diff --git a/arch/unicore32/kernel/clock.c b/arch/unicore32/kernel/clock.c
new file mode 100644
index 00000000000..18d4563e6fa
--- /dev/null
+++ b/arch/unicore32/kernel/clock.c
@@ -0,0 +1,390 @@
1/*
2 * linux/arch/unicore32/kernel/clock.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/device.h>
16#include <linux/list.h>
17#include <linux/errno.h>
18#include <linux/err.h>
19#include <linux/string.h>
20#include <linux/clk.h>
21#include <linux/mutex.h>
22#include <linux/delay.h>
23#include <linux/io.h>
24
25#include <mach/hardware.h>
26
27/*
28 * Very simple clock implementation
29 */
30struct clk {
31 struct list_head node;
32 unsigned long rate;
33 const char *name;
34};
35
36static struct clk clk_ost_clk = {
37 .name = "OST_CLK",
38 .rate = CLOCK_TICK_RATE,
39};
40
41static struct clk clk_mclk_clk = {
42 .name = "MAIN_CLK",
43};
44
45static struct clk clk_bclk32_clk = {
46 .name = "BUS32_CLK",
47};
48
49static struct clk clk_ddr_clk = {
50 .name = "DDR_CLK",
51};
52
53static struct clk clk_vga_clk = {
54 .name = "VGA_CLK",
55};
56
57static LIST_HEAD(clocks);
58static DEFINE_MUTEX(clocks_mutex);
59
60struct clk *clk_get(struct device *dev, const char *id)
61{
62 struct clk *p, *clk = ERR_PTR(-ENOENT);
63
64 mutex_lock(&clocks_mutex);
65 list_for_each_entry(p, &clocks, node) {
66 if (strcmp(id, p->name) == 0) {
67 clk = p;
68 break;
69 }
70 }
71 mutex_unlock(&clocks_mutex);
72
73 return clk;
74}
75EXPORT_SYMBOL(clk_get);
76
77void clk_put(struct clk *clk)
78{
79}
80EXPORT_SYMBOL(clk_put);
81
82int clk_enable(struct clk *clk)
83{
84 return 0;
85}
86EXPORT_SYMBOL(clk_enable);
87
88void clk_disable(struct clk *clk)
89{
90}
91EXPORT_SYMBOL(clk_disable);
92
93unsigned long clk_get_rate(struct clk *clk)
94{
95 return clk->rate;
96}
97EXPORT_SYMBOL(clk_get_rate);
98
99struct {
100 unsigned long rate;
101 unsigned long cfg;
102 unsigned long div;
103} vga_clk_table[] = {
104 {.rate = 25175000, .cfg = 0x00002001, .div = 0x9},
105 {.rate = 31500000, .cfg = 0x00002001, .div = 0x7},
106 {.rate = 40000000, .cfg = 0x00003801, .div = 0x9},
107 {.rate = 49500000, .cfg = 0x00003801, .div = 0x7},
108 {.rate = 65000000, .cfg = 0x00002c01, .div = 0x4},
109 {.rate = 78750000, .cfg = 0x00002400, .div = 0x7},
110 {.rate = 108000000, .cfg = 0x00002c01, .div = 0x2},
111 {.rate = 106500000, .cfg = 0x00003c01, .div = 0x3},
112 {.rate = 50650000, .cfg = 0x00106400, .div = 0x9},
113 {.rate = 61500000, .cfg = 0x00106400, .div = 0xa},
114 {.rate = 85500000, .cfg = 0x00002800, .div = 0x6},
115};
116
117struct {
118 unsigned long mrate;
119 unsigned long prate;
120} mclk_clk_table[] = {
121 {.mrate = 500000000, .prate = 0x00109801},
122 {.mrate = 525000000, .prate = 0x00104C00},
123 {.mrate = 550000000, .prate = 0x00105000},
124 {.mrate = 575000000, .prate = 0x00105400},
125 {.mrate = 600000000, .prate = 0x00105800},
126 {.mrate = 625000000, .prate = 0x00105C00},
127 {.mrate = 650000000, .prate = 0x00106000},
128 {.mrate = 675000000, .prate = 0x00106400},
129 {.mrate = 700000000, .prate = 0x00106800},
130 {.mrate = 725000000, .prate = 0x00106C00},
131 {.mrate = 750000000, .prate = 0x00107000},
132 {.mrate = 775000000, .prate = 0x00107400},
133 {.mrate = 800000000, .prate = 0x00107800},
134};
135
136int clk_set_rate(struct clk *clk, unsigned long rate)
137{
138 if (clk == &clk_vga_clk) {
139 unsigned long pll_vgacfg, pll_vgadiv;
140 int ret, i;
141
142 /* lookup vga_clk_table */
143 ret = -EINVAL;
144 for (i = 0; i < ARRAY_SIZE(vga_clk_table); i++) {
145 if (rate == vga_clk_table[i].rate) {
146 pll_vgacfg = vga_clk_table[i].cfg;
147 pll_vgadiv = vga_clk_table[i].div;
148 ret = 0;
149 break;
150 }
151 }
152
153 if (ret)
154 return ret;
155
156 if (readl(PM_PLLVGACFG) == pll_vgacfg)
157 return 0;
158
159 /* set pll vga cfg reg. */
160 writel(pll_vgacfg, PM_PLLVGACFG);
161
162 writel(PM_PMCR_CFBVGA, PM_PMCR);
163 while ((readl(PM_PLLDFCDONE) & PM_PLLDFCDONE_VGADFC)
164 != PM_PLLDFCDONE_VGADFC)
165 udelay(100); /* about 1ms */
166
167 /* set div cfg reg. */
168 writel(readl(PM_PCGR) | PM_PCGR_VGACLK, PM_PCGR);
169
170 writel((readl(PM_DIVCFG) & ~PM_DIVCFG_VGACLK_MASK)
171 | PM_DIVCFG_VGACLK(pll_vgadiv), PM_DIVCFG);
172
173 writel(readl(PM_SWRESET) | PM_SWRESET_VGADIV, PM_SWRESET);
174 while ((readl(PM_SWRESET) & PM_SWRESET_VGADIV)
175 == PM_SWRESET_VGADIV)
176 udelay(100); /* 65536 bclk32, about 320us */
177
178 writel(readl(PM_PCGR) & ~PM_PCGR_VGACLK, PM_PCGR);
179 }
180#ifdef CONFIG_CPU_FREQ
181 if (clk == &clk_mclk_clk) {
182 u32 pll_rate, divstatus = PM_DIVSTATUS;
183 int ret, i;
184
185 /* lookup mclk_clk_table */
186 ret = -EINVAL;
187 for (i = 0; i < ARRAY_SIZE(mclk_clk_table); i++) {
188 if (rate == mclk_clk_table[i].mrate) {
189 pll_rate = mclk_clk_table[i].prate;
190 clk_mclk_clk.rate = mclk_clk_table[i].mrate;
191 ret = 0;
192 break;
193 }
194 }
195
196 if (ret)
197 return ret;
198
199 if (clk_mclk_clk.rate)
200 clk_bclk32_clk.rate = clk_mclk_clk.rate
201 / (((divstatus & 0x0000f000) >> 12) + 1);
202
203 /* set pll sys cfg reg. */
204 PM_PLLSYSCFG = pll_rate;
205
206 PM_PMCR = PM_PMCR_CFBSYS;
207 while ((PM_PLLDFCDONE & PM_PLLDFCDONE_SYSDFC)
208 != PM_PLLDFCDONE_SYSDFC)
209 udelay(100);
210 /* about 1ms */
211 }
212#endif
213 return 0;
214}
215EXPORT_SYMBOL(clk_set_rate);
216
217int clk_register(struct clk *clk)
218{
219 mutex_lock(&clocks_mutex);
220 list_add(&clk->node, &clocks);
221 mutex_unlock(&clocks_mutex);
222 printk(KERN_DEFAULT "PKUnity PM: %s %lu.%02luM\n", clk->name,
223 (clk->rate)/1000000, (clk->rate)/10000 % 100);
224 return 0;
225}
226EXPORT_SYMBOL(clk_register);
227
228void clk_unregister(struct clk *clk)
229{
230 mutex_lock(&clocks_mutex);
231 list_del(&clk->node);
232 mutex_unlock(&clocks_mutex);
233}
234EXPORT_SYMBOL(clk_unregister);
235
236struct {
237 unsigned long prate;
238 unsigned long rate;
239} pllrate_table[] = {
240 {.prate = 0x00002001, .rate = 250000000},
241 {.prate = 0x00104801, .rate = 250000000},
242 {.prate = 0x00104C01, .rate = 262500000},
243 {.prate = 0x00002401, .rate = 275000000},
244 {.prate = 0x00105001, .rate = 275000000},
245 {.prate = 0x00105401, .rate = 287500000},
246 {.prate = 0x00002801, .rate = 300000000},
247 {.prate = 0x00105801, .rate = 300000000},
248 {.prate = 0x00105C01, .rate = 312500000},
249 {.prate = 0x00002C01, .rate = 325000000},
250 {.prate = 0x00106001, .rate = 325000000},
251 {.prate = 0x00106401, .rate = 337500000},
252 {.prate = 0x00003001, .rate = 350000000},
253 {.prate = 0x00106801, .rate = 350000000},
254 {.prate = 0x00106C01, .rate = 362500000},
255 {.prate = 0x00003401, .rate = 375000000},
256 {.prate = 0x00107001, .rate = 375000000},
257 {.prate = 0x00107401, .rate = 387500000},
258 {.prate = 0x00003801, .rate = 400000000},
259 {.prate = 0x00107801, .rate = 400000000},
260 {.prate = 0x00107C01, .rate = 412500000},
261 {.prate = 0x00003C01, .rate = 425000000},
262 {.prate = 0x00108001, .rate = 425000000},
263 {.prate = 0x00108401, .rate = 437500000},
264 {.prate = 0x00004001, .rate = 450000000},
265 {.prate = 0x00108801, .rate = 450000000},
266 {.prate = 0x00108C01, .rate = 462500000},
267 {.prate = 0x00004401, .rate = 475000000},
268 {.prate = 0x00109001, .rate = 475000000},
269 {.prate = 0x00109401, .rate = 487500000},
270 {.prate = 0x00004801, .rate = 500000000},
271 {.prate = 0x00109801, .rate = 500000000},
272 {.prate = 0x00104C00, .rate = 525000000},
273 {.prate = 0x00002400, .rate = 550000000},
274 {.prate = 0x00105000, .rate = 550000000},
275 {.prate = 0x00105400, .rate = 575000000},
276 {.prate = 0x00002800, .rate = 600000000},
277 {.prate = 0x00105800, .rate = 600000000},
278 {.prate = 0x00105C00, .rate = 625000000},
279 {.prate = 0x00002C00, .rate = 650000000},
280 {.prate = 0x00106000, .rate = 650000000},
281 {.prate = 0x00106400, .rate = 675000000},
282 {.prate = 0x00003000, .rate = 700000000},
283 {.prate = 0x00106800, .rate = 700000000},
284 {.prate = 0x00106C00, .rate = 725000000},
285 {.prate = 0x00003400, .rate = 750000000},
286 {.prate = 0x00107000, .rate = 750000000},
287 {.prate = 0x00107400, .rate = 775000000},
288 {.prate = 0x00003800, .rate = 800000000},
289 {.prate = 0x00107800, .rate = 800000000},
290 {.prate = 0x00107C00, .rate = 825000000},
291 {.prate = 0x00003C00, .rate = 850000000},
292 {.prate = 0x00108000, .rate = 850000000},
293 {.prate = 0x00108400, .rate = 875000000},
294 {.prate = 0x00004000, .rate = 900000000},
295 {.prate = 0x00108800, .rate = 900000000},
296 {.prate = 0x00108C00, .rate = 925000000},
297 {.prate = 0x00004400, .rate = 950000000},
298 {.prate = 0x00109000, .rate = 950000000},
299 {.prate = 0x00109400, .rate = 975000000},
300 {.prate = 0x00004800, .rate = 1000000000},
301 {.prate = 0x00109800, .rate = 1000000000},
302};
303
304struct {
305 unsigned long prate;
306 unsigned long drate;
307} pddr_table[] = {
308 {.prate = 0x00100800, .drate = 44236800},
309 {.prate = 0x00100C00, .drate = 66355200},
310 {.prate = 0x00101000, .drate = 88473600},
311 {.prate = 0x00101400, .drate = 110592000},
312 {.prate = 0x00101800, .drate = 132710400},
313 {.prate = 0x00101C01, .drate = 154828800},
314 {.prate = 0x00102001, .drate = 176947200},
315 {.prate = 0x00102401, .drate = 199065600},
316 {.prate = 0x00102801, .drate = 221184000},
317 {.prate = 0x00102C01, .drate = 243302400},
318 {.prate = 0x00103001, .drate = 265420800},
319 {.prate = 0x00103401, .drate = 287539200},
320 {.prate = 0x00103801, .drate = 309657600},
321 {.prate = 0x00103C01, .drate = 331776000},
322 {.prate = 0x00104001, .drate = 353894400},
323};
324
325static int __init clk_init(void)
326{
327#ifdef CONFIG_PUV3_PM
328 u32 pllrate, divstatus = readl(PM_DIVSTATUS);
329 u32 pcgr_val = readl(PM_PCGR);
330 int i;
331
332 pcgr_val |= PM_PCGR_BCLKMME | PM_PCGR_BCLKH264E | PM_PCGR_BCLKH264D
333 | PM_PCGR_HECLK | PM_PCGR_HDCLK;
334 writel(pcgr_val, PM_PCGR);
335
336 pllrate = readl(PM_PLLSYSSTATUS);
337
338 /* lookup pmclk_table */
339 clk_mclk_clk.rate = 0;
340 for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
341 if (pllrate == pllrate_table[i].prate) {
342 clk_mclk_clk.rate = pllrate_table[i].rate;
343 break;
344 }
345 }
346
347 if (clk_mclk_clk.rate)
348 clk_bclk32_clk.rate = clk_mclk_clk.rate /
349 (((divstatus & 0x0000f000) >> 12) + 1);
350
351 pllrate = readl(PM_PLLDDRSTATUS);
352
353 /* lookup pddr_table */
354 clk_ddr_clk.rate = 0;
355 for (i = 0; i < ARRAY_SIZE(pddr_table); i++) {
356 if (pllrate == pddr_table[i].prate) {
357 clk_ddr_clk.rate = pddr_table[i].drate;
358 break;
359 }
360 }
361
362 pllrate = readl(PM_PLLVGASTATUS);
363
364 /* lookup pvga_table */
365 clk_vga_clk.rate = 0;
366 for (i = 0; i < ARRAY_SIZE(pllrate_table); i++) {
367 if (pllrate == pllrate_table[i].prate) {
368 clk_vga_clk.rate = pllrate_table[i].rate;
369 break;
370 }
371 }
372
373 if (clk_vga_clk.rate)
374 clk_vga_clk.rate = clk_vga_clk.rate /
375 (((divstatus & 0x00f00000) >> 20) + 1);
376
377 clk_register(&clk_vga_clk);
378#endif
379#ifdef CONFIG_ARCH_FPGA
380 clk_ddr_clk.rate = 33000000;
381 clk_mclk_clk.rate = 33000000;
382 clk_bclk32_clk.rate = 33000000;
383#endif
384 clk_register(&clk_ddr_clk);
385 clk_register(&clk_mclk_clk);
386 clk_register(&clk_bclk32_clk);
387 clk_register(&clk_ost_clk);
388 return 0;
389}
390core_initcall(clk_init);
diff --git a/arch/unicore32/kernel/cpu-ucv2.c b/arch/unicore32/kernel/cpu-ucv2.c
new file mode 100644
index 00000000000..4a99f62584c
--- /dev/null
+++ b/arch/unicore32/kernel/cpu-ucv2.c
@@ -0,0 +1,93 @@
1/*
2 * linux/arch/unicore32/kernel/cpu-ucv2.c: clock scaling for the UniCore-II
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/init.h>
17#include <linux/clk.h>
18#include <linux/cpufreq.h>
19
20#include <mach/hardware.h>
21
22static struct cpufreq_driver ucv2_driver;
23
24/* make sure that only the "userspace" governor is run
25 * -- anything else wouldn't make sense on this platform, anyway.
26 */
27int ucv2_verify_speed(struct cpufreq_policy *policy)
28{
29 if (policy->cpu)
30 return -EINVAL;
31
32 cpufreq_verify_within_limits(policy,
33 policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
34
35 return 0;
36}
37
38static unsigned int ucv2_getspeed(unsigned int cpu)
39{
40 struct clk *mclk = clk_get(NULL, "MAIN_CLK");
41
42 if (cpu)
43 return 0;
44 return clk_get_rate(mclk)/1000;
45}
46
47static int ucv2_target(struct cpufreq_policy *policy,
48 unsigned int target_freq,
49 unsigned int relation)
50{
51 unsigned int cur = ucv2_getspeed(0);
52 struct cpufreq_freqs freqs;
53 struct clk *mclk = clk_get(NULL, "MAIN_CLK");
54
55 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
56
57 if (!clk_set_rate(mclk, target_freq * 1000)) {
58 freqs.old = cur;
59 freqs.new = target_freq;
60 freqs.cpu = 0;
61 }
62
63 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
64
65 return 0;
66}
67
68static int __init ucv2_cpu_init(struct cpufreq_policy *policy)
69{
70 if (policy->cpu != 0)
71 return -EINVAL;
72 policy->cur = ucv2_getspeed(0);
73 policy->min = policy->cpuinfo.min_freq = 250000;
74 policy->max = policy->cpuinfo.max_freq = 1000000;
75 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
76 return 0;
77}
78
79static struct cpufreq_driver ucv2_driver = {
80 .flags = CPUFREQ_STICKY,
81 .verify = ucv2_verify_speed,
82 .target = ucv2_target,
83 .get = ucv2_getspeed,
84 .init = ucv2_cpu_init,
85 .name = "UniCore-II",
86};
87
88static int __init ucv2_cpufreq_init(void)
89{
90 return cpufreq_register_driver(&ucv2_driver);
91}
92
93arch_initcall(ucv2_cpufreq_init);
diff --git a/arch/unicore32/kernel/debug-macro.S b/arch/unicore32/kernel/debug-macro.S
new file mode 100644
index 00000000000..2711d6d87d8
--- /dev/null
+++ b/arch/unicore32/kernel/debug-macro.S
@@ -0,0 +1,89 @@
1/*
2 * linux/arch/unicore32/kernel/debug-macro.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Debugging macro include header
13 */
14#include <generated/asm-offsets.h>
15#include <mach/hardware.h>
16
17 .macro put_word_ocd, rd, rx=r16
181001: movc \rx, p1.c0, #0
19 cand.a \rx, #2
20 bne 1001b
21 movc p1.c1, \rd, #1
22 .endm
23
24#ifdef CONFIG_DEBUG_OCD
25 /* debug using UniCore On-Chip-Debugger */
26 .macro addruart, rx
27 .endm
28
29 .macro senduart, rd, rx
30 put_word_ocd \rd, \rx
31 .endm
32
33 .macro busyuart, rd, rx
34 .endm
35
36 .macro waituart, rd, rx
37 .endm
38#else
39#define UART_CLK_DEFAULT 3686400 * 20
40 /* Uartclk = MCLK/ 2, The MCLK on my board is 3686400 * 40 */
41#define BAUD_RATE_DEFAULT 115200
42 /* The baud rate of the serial port */
43
44#define UART_DIVISOR_DEFAULT (UART_CLK_DEFAULT \
45 / (16 * BAUD_RATE_DEFAULT) - 1)
46
47 .macro addruart,rx
48 mrc p0, #0, \rx, c1, c0
49 tst \rx, #1 @ MMU enabled?
50 moveq \rx, #0xee000000 @ physical base address
51 movne \rx, #0x6e000000 @ virtual address
52
53 @ We probe for the active serial port here
54 @ However, now we assume UART0 is active: epip4d
55 @ We assume r1 and r2 can be clobbered.
56
57 movl r2, #UART_DIVISOR_DEFAULT
58 mov r1, #0x80
59 str r1, [\rx, #UART_LCR_OFFSET]
60 and r1, r2, #0xff00
61 mov r1, r1, lsr #8
62 str r1, [\rx, #UART_DLH_OFFSET]
63 and r1, r2, #0xff
64 str r1, [\rx, #UART_DLL_OFFSET]
65 mov r1, #0x7
66 str r1, [\rx, #UART_FCR_OFFSET]
67 mov r1, #0x3
68 str r1, [\rx, #UART_LCR_OFFSET]
69 mov r1, #0x0
70 str r1, [\rx, #UART_IER_OFFSET]
71 .endm
72
73 .macro senduart,rd,rx
74 str \rd, [\rx, #UART_THR_OFFSET]
75 .endm
76
77 .macro waituart,rd,rx
781001: ldr \rd, [\rx, #UART_LSR_OFFSET]
79 tst \rd, #UART_LSR_THRE
80 beq 1001b
81 .endm
82
83 .macro busyuart,rd,rx
841001: ldr \rd, [\rx, #UART_LSR_OFFSET]
85 tst \rd, #UART_LSR_TEMT
86 bne 1001b
87 .endm
88#endif
89
diff --git a/arch/unicore32/kernel/debug.S b/arch/unicore32/kernel/debug.S
new file mode 100644
index 00000000000..029fd12f6ab
--- /dev/null
+++ b/arch/unicore32/kernel/debug.S
@@ -0,0 +1,85 @@
1/*
2 * linux/arch/unicore32/kernel/debug.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * 32-bit debugging code
13 */
14#include <linux/linkage.h>
15#include <asm/assembler.h>
16
17 .text
18
19/*
20 * Some debugging routines (useful if you've got MM problems and
21 * printk isn't working). For DEBUGGING ONLY!!! Do not leave
22 * references to these in a production kernel!
23 */
24#include "debug-macro.S"
25
26/*
27 * Useful debugging routines
28 */
29ENTRY(printhex8)
30 mov r1, #8
31 b printhex
32ENDPROC(printhex8)
33
34ENTRY(printhex4)
35 mov r1, #4
36 b printhex
37ENDPROC(printhex4)
38
39ENTRY(printhex2)
40 mov r1, #2
41printhex: adr r2, hexbuf
42 add r3, r2, r1
43 mov r1, #0
44 stb r1, [r3]
451: and r1, r0, #15
46 mov r0, r0 >> #4
47 csub.a r1, #10
48 beg 2f
49 add r1, r1, #'0' - 'a' + 10
502: add r1, r1, #'a' - 10
51 stb.w r1, [r3+], #-1
52 cxor.a r3, r2
53 bne 1b
54 mov r0, r2
55 b printascii
56ENDPROC(printhex2)
57
58 .ltorg
59
60ENTRY(printascii)
61 addruart r3
62 b 2f
631: waituart r2, r3
64 senduart r1, r3
65 busyuart r2, r3
66 cxor.a r1, #'\n'
67 cmoveq r1, #'\r'
68 beq 1b
692: cxor.a r0, #0
70 beq 3f
71 ldb.w r1, [r0]+, #1
72 cxor.a r1, #0
73 bne 1b
743: mov pc, lr
75ENDPROC(printascii)
76
77ENTRY(printch)
78 addruart r3
79 mov r1, r0
80 mov r0, #0
81 b 1b
82ENDPROC(printch)
83
84hexbuf: .space 16
85
diff --git a/arch/unicore32/kernel/dma.c b/arch/unicore32/kernel/dma.c
new file mode 100644
index 00000000000..ae441bc3122
--- /dev/null
+++ b/arch/unicore32/kernel/dma.c
@@ -0,0 +1,183 @@
1/*
2 * linux/arch/unicore32/kernel/dma.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/errno.h>
19#include <linux/io.h>
20
21#include <asm/system.h>
22#include <asm/irq.h>
23#include <mach/hardware.h>
24#include <mach/dma.h>
25
26struct dma_channel {
27 char *name;
28 puv3_dma_prio prio;
29 void (*irq_handler)(int, void *);
30 void (*err_handler)(int, void *);
31 void *data;
32};
33
34static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
35
36int puv3_request_dma(char *name, puv3_dma_prio prio,
37 void (*irq_handler)(int, void *),
38 void (*err_handler)(int, void *),
39 void *data)
40{
41 unsigned long flags;
42 int i, found = 0;
43
44 /* basic sanity checks */
45 if (!name)
46 return -EINVAL;
47
48 local_irq_save(flags);
49
50 do {
51 /* try grabbing a DMA channel with the requested priority */
52 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
53 if ((dma_channels[i].prio == prio) &&
54 !dma_channels[i].name) {
55 found = 1;
56 break;
57 }
58 }
59 /* if requested prio group is full, try a hier priority */
60 } while (!found && prio--);
61
62 if (found) {
63 dma_channels[i].name = name;
64 dma_channels[i].irq_handler = irq_handler;
65 dma_channels[i].err_handler = err_handler;
66 dma_channels[i].data = data;
67 } else {
68 printk(KERN_WARNING "No more available DMA channels for %s\n",
69 name);
70 i = -ENODEV;
71 }
72
73 local_irq_restore(flags);
74 return i;
75}
76EXPORT_SYMBOL(puv3_request_dma);
77
78void puv3_free_dma(int dma_ch)
79{
80 unsigned long flags;
81
82 if (!dma_channels[dma_ch].name) {
83 printk(KERN_CRIT
84 "%s: trying to free channel %d which is already freed\n",
85 __func__, dma_ch);
86 return;
87 }
88
89 local_irq_save(flags);
90 dma_channels[dma_ch].name = NULL;
91 dma_channels[dma_ch].err_handler = NULL;
92 local_irq_restore(flags);
93}
94EXPORT_SYMBOL(puv3_free_dma);
95
96static irqreturn_t dma_irq_handler(int irq, void *dev_id)
97{
98 int i, dint;
99
100 dint = readl(DMAC_ITCSR);
101 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
102 if (dint & DMAC_CHANNEL(i)) {
103 struct dma_channel *channel = &dma_channels[i];
104
105 /* Clear TC interrupt of channel i */
106 writel(DMAC_CHANNEL(i), DMAC_ITCCR);
107 writel(0, DMAC_ITCCR);
108
109 if (channel->name && channel->irq_handler) {
110 channel->irq_handler(i, channel->data);
111 } else {
112 /*
113 * IRQ for an unregistered DMA channel:
114 * let's clear the interrupts and disable it.
115 */
116 printk(KERN_WARNING "spurious IRQ for"
117 " DMA channel %d\n", i);
118 }
119 }
120 }
121 return IRQ_HANDLED;
122}
123
124static irqreturn_t dma_err_handler(int irq, void *dev_id)
125{
126 int i, dint;
127
128 dint = readl(DMAC_IESR);
129 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
130 if (dint & DMAC_CHANNEL(i)) {
131 struct dma_channel *channel = &dma_channels[i];
132
133 /* Clear Err interrupt of channel i */
134 writel(DMAC_CHANNEL(i), DMAC_IECR);
135 writel(0, DMAC_IECR);
136
137 if (channel->name && channel->err_handler) {
138 channel->err_handler(i, channel->data);
139 } else {
140 /*
141 * IRQ for an unregistered DMA channel:
142 * let's clear the interrupts and disable it.
143 */
144 printk(KERN_WARNING "spurious IRQ for"
145 " DMA channel %d\n", i);
146 }
147 }
148 }
149 return IRQ_HANDLED;
150}
151
152int __init puv3_init_dma(void)
153{
154 int i, ret;
155
156 /* dma channel priorities on v8 processors:
157 * ch 0 - 1 <--> (0) DMA_PRIO_HIGH
158 * ch 2 - 3 <--> (1) DMA_PRIO_MEDIUM
159 * ch 4 - 5 <--> (2) DMA_PRIO_LOW
160 */
161 for (i = 0; i < MAX_DMA_CHANNELS; i++) {
162 puv3_stop_dma(i);
163 dma_channels[i].name = NULL;
164 dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
165 }
166
167 ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
168 if (ret) {
169 printk(KERN_CRIT "Can't register IRQ for DMA\n");
170 return ret;
171 }
172
173 ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
174 if (ret) {
175 printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
176 free_irq(IRQ_DMA, "DMA");
177 return ret;
178 }
179
180 return 0;
181}
182
183postcore_initcall(puv3_init_dma);
diff --git a/arch/unicore32/kernel/early_printk.c b/arch/unicore32/kernel/early_printk.c
new file mode 100644
index 00000000000..3922255f1fa
--- /dev/null
+++ b/arch/unicore32/kernel/early_printk.c
@@ -0,0 +1,59 @@
1/*
2 * linux/arch/unicore32/kernel/early_printk.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/console.h>
13#include <linux/init.h>
14#include <linux/string.h>
15#include <mach/ocd.h>
16
17/* On-Chip-Debugger functions */
18
19static void early_ocd_write(struct console *con, const char *s, unsigned n)
20{
21 while (*s && n-- > 0) {
22 if (*s == '\n')
23 ocd_putc((int)'\r');
24 ocd_putc((int)*s);
25 s++;
26 }
27}
28
29static struct console early_ocd_console = {
30 .name = "earlyocd",
31 .write = early_ocd_write,
32 .flags = CON_PRINTBUFFER,
33 .index = -1,
34};
35
36/* Direct interface for emergencies */
37static struct console *early_console = &early_ocd_console;
38
39static int __initdata keep_early;
40
41static int __init setup_early_printk(char *buf)
42{
43 if (!buf)
44 return 0;
45
46 if (strstr(buf, "keep"))
47 keep_early = 1;
48
49 if (!strncmp(buf, "ocd", 3))
50 early_console = &early_ocd_console;
51
52 if (keep_early)
53 early_console->flags &= ~CON_BOOT;
54 else
55 early_console->flags |= CON_BOOT;
56 register_console(early_console);
57 return 0;
58}
59early_param("earlyprintk", setup_early_printk);
diff --git a/arch/unicore32/kernel/elf.c b/arch/unicore32/kernel/elf.c
new file mode 100644
index 00000000000..0a176734fef
--- /dev/null
+++ b/arch/unicore32/kernel/elf.c
@@ -0,0 +1,38 @@
1/*
2 * linux/arch/unicore32/kernel/elf.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/personality.h>
15#include <linux/binfmts.h>
16#include <linux/elf.h>
17
18int elf_check_arch(const struct elf32_hdr *x)
19{
20 /* Make sure it's an UniCore executable */
21 if (x->e_machine != EM_UNICORE)
22 return 0;
23
24 /* Make sure the entry address is reasonable */
25 if (x->e_entry & 3)
26 return 0;
27
28 return 1;
29}
30EXPORT_SYMBOL(elf_check_arch);
31
32void elf_set_personality(const struct elf32_hdr *x)
33{
34 unsigned int personality = PER_LINUX;
35
36 set_personality(personality);
37}
38EXPORT_SYMBOL(elf_set_personality);
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
new file mode 100644
index 00000000000..00a259f9819
--- /dev/null
+++ b/arch/unicore32/kernel/entry.S
@@ -0,0 +1,824 @@
1/*
2 * linux/arch/unicore32/kernel/entry.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Low-level vector interface routines
13 */
14#include <linux/init.h>
15#include <linux/linkage.h>
16#include <asm/assembler.h>
17#include <asm/errno.h>
18#include <asm/thread_info.h>
19#include <asm/memory.h>
20#include <asm/unistd.h>
21#include <generated/asm-offsets.h>
22#include "debug-macro.S"
23
24@
25@ Most of the stack format comes from struct pt_regs, but with
26@ the addition of 8 bytes for storing syscall args 5 and 6.
27@
28#define S_OFF 8
29
30/*
31 * The SWI code relies on the fact that R0 is at the bottom of the stack
32 * (due to slow/fast restore user regs).
33 */
34#if S_R0 != 0
35#error "Please fix"
36#endif
37
38 .macro zero_fp
39#ifdef CONFIG_FRAME_POINTER
40 mov fp, #0
41#endif
42 .endm
43
44 .macro alignment_trap, rtemp
45#ifdef CONFIG_ALIGNMENT_TRAP
46 ldw \rtemp, .LCcralign
47 ldw \rtemp, [\rtemp]
48 movc p0.c1, \rtemp, #0
49#endif
50 .endm
51
52 .macro load_user_sp_lr, rd, rtemp, offset = 0
53 mov \rtemp, asr
54 xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE)
55 mov.a asr, \rtemp @ switch to the SUSR mode
56
57 ldw sp, [\rd+], #\offset @ load sp_user
58 ldw lr, [\rd+], #\offset + 4 @ load lr_user
59
60 xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE)
61 mov.a asr, \rtemp @ switch back to the PRIV mode
62 .endm
63
64 .macro priv_exit, rpsr
65 mov.a bsr, \rpsr
66 ldm.w (r0 - r15), [sp]+
67 ldm.b (r16 - pc), [sp]+ @ load r0 - pc, asr
68 .endm
69
70 .macro restore_user_regs, fast = 0, offset = 0
71 ldw r1, [sp+], #\offset + S_PSR @ get calling asr
72 ldw lr, [sp+], #\offset + S_PC @ get pc
73 mov.a bsr, r1 @ save in bsr_priv
74 .if \fast
75 add sp, sp, #\offset + S_R1 @ r0 is syscall return value
76 ldm.w (r1 - r15), [sp]+ @ get calling r1 - r15
77 ldur (r16 - lr), [sp]+ @ get calling r16 - lr
78 .else
79 ldm.w (r0 - r15), [sp]+ @ get calling r0 - r15
80 ldur (r16 - lr), [sp]+ @ get calling r16 - lr
81 .endif
82 nop
83 add sp, sp, #S_FRAME_SIZE - S_R16
84 mov.a pc, lr @ return
85 @ and move bsr_priv into asr
86 .endm
87
88 .macro get_thread_info, rd
89 mov \rd, sp >> #13
90 mov \rd, \rd << #13
91 .endm
92
93 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
94 ldw \base, =(PKUNITY_INTC_BASE)
95 ldw \irqstat, [\base+], #0xC @ INTC_ICIP
96 ldw \tmp, [\base+], #0x4 @ INTC_ICMR
97 and.a \irqstat, \irqstat, \tmp
98 beq 1001f
99 cntlz \irqnr, \irqstat
100 rsub \irqnr, \irqnr, #31
1011001: /* EQ will be set if no irqs pending */
102 .endm
103
104#ifdef CONFIG_DEBUG_LL
105 .macro printreg, reg, temp
106 adr \temp, 901f
107 stm (r0-r3), [\temp]+
108 stw lr, [\temp+], #0x10
109 mov r0, \reg
110 b.l printhex8
111 mov r0, #':'
112 b.l printch
113 mov r0, pc
114 b.l printhex8
115 adr r0, 902f
116 b.l printascii
117 adr \temp, 901f
118 ldm (r0-r3), [\temp]+
119 ldw lr, [\temp+], #0x10
120 b 903f
121901: .word 0, 0, 0, 0, 0 @ r0-r3, lr
122902: .asciz ": epip4d\n"
123 .align
124903:
125 .endm
126#endif
127
128/*
129 * These are the registers used in the syscall handler, and allow us to
130 * have in theory up to 7 arguments to a function - r0 to r6.
131 *
132 * Note that tbl == why is intentional.
133 *
134 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
135 */
136scno .req r21 @ syscall number
137tbl .req r22 @ syscall table pointer
138why .req r22 @ Linux syscall (!= 0)
139tsk .req r23 @ current thread_info
140
141/*
142 * Interrupt handling. Preserves r17, r18, r19
143 */
144 .macro intr_handler
1451: get_irqnr_and_base r0, r6, r5, lr
146 beq 2f
147 mov r1, sp
148 @
149 @ routine called with r0 = irq number, r1 = struct pt_regs *
150 @
151 adr lr, 1b
152 b asm_do_IRQ
1532:
154 .endm
155
156/*
157 * PRIV mode handlers
158 */
159 .macro priv_entry
160 sub sp, sp, #(S_FRAME_SIZE - 4)
161 stm (r1 - r15), [sp]+
162 add r5, sp, #S_R15
163 stm (r16 - r28), [r5]+
164
165 ldm (r1 - r3), [r0]+
166 add r5, sp, #S_SP - 4 @ here for interlock avoidance
167 mov r4, #-1 @ "" "" "" ""
168 add r0, sp, #(S_FRAME_SIZE - 4)
169 stw.w r1, [sp+], #-4 @ save the "real" r0 copied
170 @ from the exception stack
171
172 mov r1, lr
173
174 @
175 @ We are now ready to fill in the remaining blanks on the stack:
176 @
177 @ r0 - sp_priv
178 @ r1 - lr_priv
179 @ r2 - lr_<exception>, already fixed up for correct return/restart
180 @ r3 - bsr_<exception>
181 @ r4 - orig_r0 (see pt_regs definition in ptrace.h)
182 @
183 stm (r0 - r4), [r5]+
184 .endm
185
186/*
187 * User mode handlers
188 *
189 */
190 .macro user_entry
191 sub sp, sp, #S_FRAME_SIZE
192 stm (r1 - r15), [sp+]
193 add r4, sp, #S_R16
194 stm (r16 - r28), [r4]+
195
196 ldm (r1 - r3), [r0]+
197 add r0, sp, #S_PC @ here for interlock avoidance
198 mov r4, #-1 @ "" "" "" ""
199
200 stw r1, [sp] @ save the "real" r0 copied
201 @ from the exception stack
202
203 @
204 @ We are now ready to fill in the remaining blanks on the stack:
205 @
206 @ r2 - lr_<exception>, already fixed up for correct return/restart
207 @ r3 - bsr_<exception>
208 @ r4 - orig_r0 (see pt_regs definition in ptrace.h)
209 @
210 @ Also, separately save sp_user and lr_user
211 @
212 stm (r2 - r4), [r0]+
213 stur (sp, lr), [r0-]
214
215 @
216 @ Enable the alignment trap while in kernel mode
217 @
218 alignment_trap r0
219
220 @
221 @ Clear FP to mark the first stack frame
222 @
223 zero_fp
224 .endm
225
226 .text
227
228@
229@ __invalid - generic code for failed exception
230@ (re-entrant version of handlers)
231@
232__invalid:
233 sub sp, sp, #S_FRAME_SIZE
234 stm (r1 - r15), [sp+]
235 add r1, sp, #S_R16
236 stm (r16 - r28, sp, lr), [r1]+
237
238 zero_fp
239
240 ldm (r4 - r6), [r0]+
241 add r0, sp, #S_PC @ here for interlock avoidance
242 mov r7, #-1 @ "" "" "" ""
243 stw r4, [sp] @ save preserved r0
244 stm (r5 - r7), [r0]+ @ lr_<exception>,
245 @ asr_<exception>, "old_r0"
246
247 mov r0, sp
248 mov r1, asr
249 b bad_mode
250ENDPROC(__invalid)
251
252 .align 5
253__dabt_priv:
254 priv_entry
255
256 @
257 @ get ready to re-enable interrupts if appropriate
258 @
259 mov r17, asr
260 cand.a r3, #PSR_I_BIT
261 bne 1f
262 andn r17, r17, #PSR_I_BIT
2631:
264
265 @
266 @ Call the processor-specific abort handler:
267 @
268 @ r2 - aborted context pc
269 @ r3 - aborted context asr
270 @
271 @ The abort handler must return the aborted address in r0, and
272 @ the fault status register in r1.
273 @
274 movc r1, p0.c3, #0 @ get FSR
275 movc r0, p0.c4, #0 @ get FAR
276
277 @
278 @ set desired INTR state, then call main handler
279 @
280 mov.a asr, r17
281 mov r2, sp
282 b.l do_DataAbort
283
284 @
285 @ INTRs off again before pulling preserved data off the stack
286 @
287 disable_irq r0
288
289 @
290 @ restore BSR and restart the instruction
291 @
292 ldw r2, [sp+], #S_PSR
293 priv_exit r2 @ return from exception
294ENDPROC(__dabt_priv)
295
296 .align 5
297__intr_priv:
298 priv_entry
299
300 intr_handler
301
302 mov r0, #0 @ epip4d
303 movc p0.c5, r0, #14
304 nop; nop; nop; nop; nop; nop; nop; nop
305
306 ldw r4, [sp+], #S_PSR @ irqs are already disabled
307
308 priv_exit r4 @ return from exception
309ENDPROC(__intr_priv)
310
311 .ltorg
312
313 .align 5
314__extn_priv:
315 priv_entry
316
317 mov r0, sp @ struct pt_regs *regs
318 mov r1, asr
319 b bad_mode @ not supported
320ENDPROC(__extn_priv)
321
322 .align 5
323__pabt_priv:
324 priv_entry
325
326 @
327 @ re-enable interrupts if appropriate
328 @
329 mov r17, asr
330 cand.a r3, #PSR_I_BIT
331 bne 1f
332 andn r17, r17, #PSR_I_BIT
3331:
334
335 @
336 @ set args, then call main handler
337 @
338 @ r0 - address of faulting instruction
339 @ r1 - pointer to registers on stack
340 @
341 mov r0, r2 @ pass address of aborted instruction
342 mov r1, #5
343 mov.a asr, r17
344 mov r2, sp @ regs
345 b.l do_PrefetchAbort @ call abort handler
346
347 @
348 @ INTRs off again before pulling preserved data off the stack
349 @
350 disable_irq r0
351
352 @
353 @ restore BSR and restart the instruction
354 @
355 ldw r2, [sp+], #S_PSR
356 priv_exit r2 @ return from exception
357ENDPROC(__pabt_priv)
358
359 .align 5
360.LCcralign:
361 .word cr_alignment
362
363 .align 5
364__dabt_user:
365 user_entry
366
367#ifdef CONFIG_UNICORE_FPU_F64
368 cff ip, s31
369 cand.a ip, #0x08000000 @ FPU execption traps?
370 beq 209f
371
372 ldw ip, [sp+], #S_PC
373 add ip, ip, #4
374 stw ip, [sp+], #S_PC
375 @
376 @ fall through to the emulation code, which returns using r19 if
377 @ it has emulated the instruction, or the more conventional lr
378 @ if we are to treat this as a real extended instruction
379 @
380 @ r0 - instruction
381 @
3821: ldw.u r0, [r2]
383 adr r19, ret_from_exception
384 adr lr, 209f
385 @
386 @ fallthrough to call do_uc_f64
387 @
388/*
389 * Check whether the instruction is a co-processor instruction.
390 * If yes, we need to call the relevant co-processor handler.
391 *
392 * Note that we don't do a full check here for the co-processor
393 * instructions; all instructions with bit 27 set are well
394 * defined. The only instructions that should fault are the
395 * co-processor instructions.
396 *
397 * Emulators may wish to make use of the following registers:
398 * r0 = instruction opcode.
399 * r2 = PC
400 * r19 = normal "successful" return address
401 * r20 = this threads thread_info structure.
402 * lr = unrecognised instruction return address
403 */
404 get_thread_info r20 @ get current thread
405 and r8, r0, #0x00003c00 @ mask out CP number
406 mov r7, #1
407 stb r7, [r20+], #TI_USED_CP + 2 @ set appropriate used_cp[]
408
409 @ F64 hardware support entry point.
410 @ r0 = faulted instruction
411 @ r19 = return address
412 @ r20 = fp_state
413 enable_irq r4
414 add r20, r20, #TI_FPSTATE @ r20 = workspace
415 cff r1, s31 @ get fpu FPSCR
416 andn r2, r1, #0x08000000
417 ctf r2, s31 @ clear 27 bit
418 mov r2, sp @ nothing stacked - regdump is at TOS
419 mov lr, r19 @ setup for a return to the user code
420
421 @ Now call the C code to package up the bounce to the support code
422 @ r0 holds the trigger instruction
423 @ r1 holds the FPSCR value
424 @ r2 pointer to register dump
425 b ucf64_exchandler
426209:
427#endif
428 @
429 @ Call the processor-specific abort handler:
430 @
431 @ r2 - aborted context pc
432 @ r3 - aborted context asr
433 @
434 @ The abort handler must return the aborted address in r0, and
435 @ the fault status register in r1.
436 @
437 movc r1, p0.c3, #0 @ get FSR
438 movc r0, p0.c4, #0 @ get FAR
439
440 @
441 @ INTRs on, then call the main handler
442 @
443 enable_irq r2
444 mov r2, sp
445 adr lr, ret_from_exception
446 b do_DataAbort
447ENDPROC(__dabt_user)
448
449 .align 5
450__intr_user:
451 user_entry
452
453 get_thread_info tsk
454
455 intr_handler
456
457 mov why, #0
458 b ret_to_user
459ENDPROC(__intr_user)
460
461 .ltorg
462
463 .align 5
464__extn_user:
465 user_entry
466
467 mov r0, sp
468 mov r1, asr
469 b bad_mode
470ENDPROC(__extn_user)
471
472 .align 5
473__pabt_user:
474 user_entry
475
476 mov r0, r2 @ pass address of aborted instruction.
477 mov r1, #5
478 enable_irq r1 @ Enable interrupts
479 mov r2, sp @ regs
480 b.l do_PrefetchAbort @ call abort handler
481 /* fall through */
482/*
483 * This is the return code to user mode for abort handlers
484 */
485ENTRY(ret_from_exception)
486 get_thread_info tsk
487 mov why, #0
488 b ret_to_user
489ENDPROC(__pabt_user)
490ENDPROC(ret_from_exception)
491
492/*
493 * Register switch for UniCore V2 processors
494 * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
495 * previous and next are guaranteed not to be the same.
496 */
497ENTRY(__switch_to)
498 add ip, r1, #TI_CPU_SAVE
499 stm.w (r4 - r15), [ip]+
500 stm.w (r16 - r27, sp, lr), [ip]+
501
502#ifdef CONFIG_UNICORE_FPU_F64
503 add ip, r1, #TI_FPSTATE
504 sfm.w (f0 - f7 ), [ip]+
505 sfm.w (f8 - f15), [ip]+
506 sfm.w (f16 - f23), [ip]+
507 sfm.w (f24 - f31), [ip]+
508 cff r4, s31
509 stw r4, [ip]
510
511 add ip, r2, #TI_FPSTATE
512 lfm.w (f0 - f7 ), [ip]+
513 lfm.w (f8 - f15), [ip]+
514 lfm.w (f16 - f23), [ip]+
515 lfm.w (f24 - f31), [ip]+
516 ldw r4, [ip]
517 ctf r4, s31
518#endif
519 add ip, r2, #TI_CPU_SAVE
520 ldm.w (r4 - r15), [ip]+
521 ldm (r16 - r27, sp, pc), [ip]+ @ Load all regs saved previously
522ENDPROC(__switch_to)
523
524 .align 5
525/*
526 * This is the fast syscall return path. We do as little as
527 * possible here, and this includes saving r0 back into the PRIV
528 * stack.
529 */
530ret_fast_syscall:
531 disable_irq r1 @ disable interrupts
532 ldw r1, [tsk+], #TI_FLAGS
533 cand.a r1, #_TIF_WORK_MASK
534 bne fast_work_pending
535
536 @ fast_restore_user_regs
537 restore_user_regs fast = 1, offset = S_OFF
538
539/*
540 * Ok, we need to do extra processing, enter the slow path.
541 */
542fast_work_pending:
543 stw.w r0, [sp+], #S_R0+S_OFF @ returned r0
544work_pending:
545 cand.a r1, #_TIF_NEED_RESCHED
546 bne work_resched
547 cand.a r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
548 beq no_work_pending
549 mov r0, sp @ 'regs'
550 mov r2, why @ 'syscall'
551 cand.a r1, #_TIF_SIGPENDING @ delivering a signal?
552 cmovne why, #0 @ prevent further restarts
553 b.l do_notify_resume
554 b ret_slow_syscall @ Check work again
555
556work_resched:
557 b.l schedule
558/*
559 * "slow" syscall return path. "why" tells us if this was a real syscall.
560 */
561ENTRY(ret_to_user)
562ret_slow_syscall:
563 disable_irq r1 @ disable interrupts
564 get_thread_info tsk @ epip4d, one path error?!
565 ldw r1, [tsk+], #TI_FLAGS
566 cand.a r1, #_TIF_WORK_MASK
567 bne work_pending
568no_work_pending:
569 @ slow_restore_user_regs
570 restore_user_regs fast = 0, offset = 0
571ENDPROC(ret_to_user)
572
573/*
574 * This is how we return from a fork.
575 */
576ENTRY(ret_from_fork)
577 b.l schedule_tail
578 get_thread_info tsk
579 ldw r1, [tsk+], #TI_FLAGS @ check for syscall tracing
580 mov why, #1
581 cand.a r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
582 beq ret_slow_syscall
583 mov r1, sp
584 mov r0, #1 @ trace exit [IP = 1]
585 b.l syscall_trace
586 b ret_slow_syscall
587ENDPROC(ret_from_fork)
588
589/*=============================================================================
590 * SWI handler
591 *-----------------------------------------------------------------------------
592 */
593 .align 5
594ENTRY(vector_swi)
595 sub sp, sp, #S_FRAME_SIZE
596 stm (r0 - r15), [sp]+ @ Calling r0 - r15
597 add r8, sp, #S_R16
598 stm (r16 - r28), [r8]+ @ Calling r16 - r28
599 add r8, sp, #S_PC
600 stur (sp, lr), [r8-] @ Calling sp, lr
601 mov r8, bsr @ called from non-REAL mode
602 stw lr, [sp+], #S_PC @ Save calling PC
603 stw r8, [sp+], #S_PSR @ Save ASR
604 stw r0, [sp+], #S_OLD_R0 @ Save OLD_R0
605 zero_fp
606
607 /*
608 * Get the system call number.
609 */
610 sub ip, lr, #4
611 ldw.u scno, [ip] @ get SWI instruction
612
613#ifdef CONFIG_ALIGNMENT_TRAP
614 ldw ip, __cr_alignment
615 ldw ip, [ip]
616 movc p0.c1, ip, #0 @ update control register
617#endif
618 enable_irq ip
619
620 get_thread_info tsk
621 ldw tbl, =sys_call_table @ load syscall table pointer
622
623 andn scno, scno, #0xff000000 @ mask off SWI op-code
624 andn scno, scno, #0x00ff0000 @ mask off SWI op-code
625
626 stm.w (r4, r5), [sp-] @ push fifth and sixth args
627 ldw ip, [tsk+], #TI_FLAGS @ check for syscall tracing
628 cand.a ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
629 bne __sys_trace
630
631 csub.a scno, #__NR_syscalls @ check upper syscall limit
632 adr lr, ret_fast_syscall @ return address
633 bea 1f
634 ldw pc, [tbl+], scno << #2 @ call sys_* routine
6351:
636 add r1, sp, #S_OFF
6372: mov why, #0 @ no longer a real syscall
638 b sys_ni_syscall @ not private func
639
640 /*
641 * This is the really slow path. We're going to be doing
642 * context switches, and waiting for our parent to respond.
643 */
644__sys_trace:
645 mov r2, scno
646 add r1, sp, #S_OFF
647 mov r0, #0 @ trace entry [IP = 0]
648 b.l syscall_trace
649
650 adr lr, __sys_trace_return @ return address
651 mov scno, r0 @ syscall number (possibly new)
652 add r1, sp, #S_R0 + S_OFF @ pointer to regs
653 csub.a scno, #__NR_syscalls @ check upper syscall limit
654 bea 2b
655 ldm (r0 - r3), [r1]+ @ have to reload r0 - r3
656 ldw pc, [tbl+], scno << #2 @ call sys_* routine
657
658__sys_trace_return:
659 stw.w r0, [sp+], #S_R0 + S_OFF @ save returned r0
660 mov r2, scno
661 mov r1, sp
662 mov r0, #1 @ trace exit [IP = 1]
663 b.l syscall_trace
664 b ret_slow_syscall
665
666 .align 5
667#ifdef CONFIG_ALIGNMENT_TRAP
668 .type __cr_alignment, #object
669__cr_alignment:
670 .word cr_alignment
671#endif
672 .ltorg
673
674ENTRY(sys_execve)
675 add r3, sp, #S_OFF
676 b __sys_execve
677ENDPROC(sys_execve)
678
679ENTRY(sys_clone)
680 add ip, sp, #S_OFF
681 stw ip, [sp+], #4
682 b __sys_clone
683ENDPROC(sys_clone)
684
685ENTRY(sys_rt_sigreturn)
686 add r0, sp, #S_OFF
687 mov why, #0 @ prevent syscall restart handling
688 b __sys_rt_sigreturn
689ENDPROC(sys_rt_sigreturn)
690
691ENTRY(sys_sigaltstack)
692 ldw r2, [sp+], #S_OFF + S_SP
693 b do_sigaltstack
694ENDPROC(sys_sigaltstack)
695
696 __INIT
697
698/*
699 * Vector stubs.
700 *
701 * This code is copied to 0xffff0200 so we can use branches in the
702 * vectors, rather than ldr's. Note that this code must not
703 * exceed 0x300 bytes.
704 *
705 * Common stub entry macro:
706 * Enter in INTR mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC
707 *
708 * SP points to a minimal amount of processor-private memory, the address
709 * of which is copied into r0 for the mode specific abort handler.
710 */
711 .macro vector_stub, name, mode
712 .align 5
713
714vector_\name:
715 @
716 @ Save r0, lr_<exception> (parent PC) and bsr_<exception>
717 @ (parent ASR)
718 @
719 stw r0, [sp]
720 stw lr, [sp+], #4 @ save r0, lr
721 mov lr, bsr
722 stw lr, [sp+], #8 @ save bsr
723
724 @
725 @ Prepare for PRIV mode. INTRs remain disabled.
726 @
727 mov r0, asr
728 xor r0, r0, #(\mode ^ PRIV_MODE)
729 mov.a bsr, r0
730
731 @
732 @ the branch table must immediately follow this code
733 @
734 and lr, lr, #0x03
735 add lr, lr, #1
736 mov r0, sp
737 ldw lr, [pc+], lr << #2
738 mov.a pc, lr @ branch to handler in PRIV mode
739ENDPROC(vector_\name)
740 .align 2
741 @ handler addresses follow this label
742 .endm
743
744 .globl __stubs_start
745__stubs_start:
746/*
747 * Interrupt dispatcher
748 */
749 vector_stub intr, INTR_MODE
750
751 .long __intr_user @ 0 (USER)
752 .long __invalid @ 1
753 .long __invalid @ 2
754 .long __intr_priv @ 3 (PRIV)
755
756/*
757 * Data abort dispatcher
758 * Enter in ABT mode, bsr = USER ASR, lr = USER PC
759 */
760 vector_stub dabt, ABRT_MODE
761
762 .long __dabt_user @ 0 (USER)
763 .long __invalid @ 1
764 .long __invalid @ 2 (INTR)
765 .long __dabt_priv @ 3 (PRIV)
766
767/*
768 * Prefetch abort dispatcher
769 * Enter in ABT mode, bsr = USER ASR, lr = USER PC
770 */
771 vector_stub pabt, ABRT_MODE
772
773 .long __pabt_user @ 0 (USER)
774 .long __invalid @ 1
775 .long __invalid @ 2 (INTR)
776 .long __pabt_priv @ 3 (PRIV)
777
778/*
779 * Undef instr entry dispatcher
780 * Enter in EXTN mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC
781 */
782 vector_stub extn, EXTN_MODE
783
784 .long __extn_user @ 0 (USER)
785 .long __invalid @ 1
786 .long __invalid @ 2 (INTR)
787 .long __extn_priv @ 3 (PRIV)
788
789/*
790 * We group all the following data together to optimise
791 * for CPUs with separate I & D caches.
792 */
793 .align 5
794
795.LCvswi:
796 .word vector_swi
797
798 .globl __stubs_end
799__stubs_end:
800
801 .equ stubs_offset, __vectors_start + 0x200 - __stubs_start
802
803 .globl __vectors_start
804__vectors_start:
805 jepriv SYS_ERROR0
806 b vector_extn + stubs_offset
807 ldw pc, .LCvswi + stubs_offset
808 b vector_pabt + stubs_offset
809 b vector_dabt + stubs_offset
810 jepriv SYS_ERROR0
811 b vector_intr + stubs_offset
812 jepriv SYS_ERROR0
813
814 .globl __vectors_end
815__vectors_end:
816
817 .data
818
819 .globl cr_alignment
820 .globl cr_no_alignment
821cr_alignment:
822 .space 4
823cr_no_alignment:
824 .space 4
diff --git a/arch/unicore32/kernel/fpu-ucf64.c b/arch/unicore32/kernel/fpu-ucf64.c
new file mode 100644
index 00000000000..282a60ac82b
--- /dev/null
+++ b/arch/unicore32/kernel/fpu-ucf64.c
@@ -0,0 +1,126 @@
1/*
2 * linux/arch/unicore32/kernel/fpu-ucf64.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/signal.h>
16#include <linux/sched.h>
17#include <linux/init.h>
18
19#include <asm/fpu-ucf64.h>
20
21/*
22 * A special flag to tell the normalisation code not to normalise.
23 */
24#define F64_NAN_FLAG 0x100
25
26/*
27 * A bit pattern used to indicate the initial (unset) value of the
28 * exception mask, in case nothing handles an instruction. This
29 * doesn't include the NAN flag, which get masked out before
30 * we check for an error.
31 */
32#define F64_EXCEPTION_ERROR ((u32)-1 & ~F64_NAN_FLAG)
33
34/*
35 * Since we aren't building with -mfpu=f64, we need to code
36 * these instructions using their MRC/MCR equivalents.
37 */
38#define f64reg(_f64_) #_f64_
39
40#define cff(_f64_) ({ \
41 u32 __v; \
42 asm("cff %0, " f64reg(_f64_) "@ fmrx %0, " #_f64_ \
43 : "=r" (__v) : : "cc"); \
44 __v; \
45 })
46
47#define ctf(_f64_, _var_) \
48 asm("ctf %0, " f64reg(_f64_) "@ fmxr " #_f64_ ", %0" \
49 : : "r" (_var_) : "cc")
50
51/*
52 * Raise a SIGFPE for the current process.
53 * sicode describes the signal being raised.
54 */
55void ucf64_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
56{
57 siginfo_t info;
58
59 memset(&info, 0, sizeof(info));
60
61 info.si_signo = SIGFPE;
62 info.si_code = sicode;
63 info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
64
65 /*
66 * This is the same as NWFPE, because it's not clear what
67 * this is used for
68 */
69 current->thread.error_code = 0;
70 current->thread.trap_no = 6;
71
72 send_sig_info(SIGFPE, &info, current);
73}
74
75/*
76 * Handle exceptions of UniCore-F64.
77 */
78void ucf64_exchandler(u32 inst, u32 fpexc, struct pt_regs *regs)
79{
80 u32 tmp = fpexc;
81 u32 exc = F64_EXCEPTION_ERROR & fpexc;
82
83 pr_debug("UniCore-F64: instruction %08x fpscr %08x\n",
84 inst, fpexc);
85
86 if (exc & FPSCR_CMPINSTR_BIT) {
87 if (exc & FPSCR_CON)
88 tmp |= FPSCR_CON;
89 else
90 tmp &= ~(FPSCR_CON);
91 exc &= ~(FPSCR_CMPINSTR_BIT | FPSCR_CON);
92 } else {
93 pr_debug(KERN_ERR "UniCore-F64 Error: unhandled exceptions\n");
94 pr_debug(KERN_ERR "UniCore-F64 FPSCR 0x%08x INST 0x%08x\n",
95 cff(FPSCR), inst);
96
97 ucf64_raise_sigfpe(0, regs);
98 return;
99 }
100
101 /*
102 * Update the FPSCR with the additional exception flags.
103 * Comparison instructions always return at least one of
104 * these flags set.
105 */
106 tmp &= ~(FPSCR_TRAP | FPSCR_IOS | FPSCR_OFS | FPSCR_UFS |
107 FPSCR_IXS | FPSCR_HIS | FPSCR_IOC | FPSCR_OFC |
108 FPSCR_UFC | FPSCR_IXC | FPSCR_HIC);
109
110 tmp |= exc;
111 ctf(FPSCR, tmp);
112}
113
114/*
115 * F64 support code initialisation.
116 */
117static int __init ucf64_init(void)
118{
119 ctf(FPSCR, 0x0); /* FPSCR_UFE | FPSCR_NDE perhaps better */
120
121 printk(KERN_INFO "Enable UniCore-F64 support.\n");
122
123 return 0;
124}
125
126late_initcall(ucf64_init);
diff --git a/arch/unicore32/kernel/gpio.c b/arch/unicore32/kernel/gpio.c
new file mode 100644
index 00000000000..cb12ec39552
--- /dev/null
+++ b/arch/unicore32/kernel/gpio.c
@@ -0,0 +1,122 @@
1/*
2 * linux/arch/unicore32/kernel/gpio.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13/* in FPGA, no GPIO support */
14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/gpio.h>
18#include <mach/hardware.h>
19
20#ifdef CONFIG_LEDS
21#include <linux/leds.h>
22#include <linux/platform_device.h>
23
24static const struct gpio_led puv3_gpio_leds[] = {
25 { .name = "cpuhealth", .gpio = GPO_CPU_HEALTH, .active_low = 0,
26 .default_trigger = "heartbeat", },
27 { .name = "hdd_led", .gpio = GPO_HDD_LED, .active_low = 1,
28 .default_trigger = "ide-disk", },
29};
30
31static const struct gpio_led_platform_data puv3_gpio_led_data = {
32 .num_leds = ARRAY_SIZE(puv3_gpio_leds),
33 .leds = (void *) puv3_gpio_leds,
34};
35
36static struct platform_device puv3_gpio_gpio_leds = {
37 .name = "leds-gpio",
38 .id = -1,
39 .dev = {
40 .platform_data = (void *) &puv3_gpio_led_data,
41 }
42};
43
44static int __init puv3_gpio_leds_init(void)
45{
46 platform_device_register(&puv3_gpio_gpio_leds);
47 return 0;
48}
49
50device_initcall(puv3_gpio_leds_init);
51#endif
52
53static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset)
54{
55 return readl(GPIO_GPLR) & GPIO_GPIO(offset);
56}
57
58static void puv3_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
59{
60 if (value)
61 writel(GPIO_GPIO(offset), GPIO_GPSR);
62 else
63 writel(GPIO_GPIO(offset), GPIO_GPCR);
64}
65
66static int puv3_direction_input(struct gpio_chip *chip, unsigned offset)
67{
68 unsigned long flags;
69
70 local_irq_save(flags);
71 writel(readl(GPIO_GPDR) & ~GPIO_GPIO(offset), GPIO_GPDR);
72 local_irq_restore(flags);
73 return 0;
74}
75
76static int puv3_direction_output(struct gpio_chip *chip, unsigned offset,
77 int value)
78{
79 unsigned long flags;
80
81 local_irq_save(flags);
82 puv3_gpio_set(chip, offset, value);
83 writel(readl(GPIO_GPDR) | GPIO_GPIO(offset), GPIO_GPDR);
84 local_irq_restore(flags);
85 return 0;
86}
87
88static struct gpio_chip puv3_gpio_chip = {
89 .label = "gpio",
90 .direction_input = puv3_direction_input,
91 .direction_output = puv3_direction_output,
92 .set = puv3_gpio_set,
93 .get = puv3_gpio_get,
94 .base = 0,
95 .ngpio = GPIO_MAX + 1,
96};
97
98void __init puv3_init_gpio(void)
99{
100 writel(GPIO_DIR, GPIO_GPDR);
101#if defined(CONFIG_PUV3_NB0916) || defined(CONFIG_PUV3_SMW0919) \
102 || defined(CONFIG_PUV3_DB0913)
103 gpio_set_value(GPO_WIFI_EN, 1);
104 gpio_set_value(GPO_HDD_LED, 1);
105 gpio_set_value(GPO_VGA_EN, 1);
106 gpio_set_value(GPO_LCD_EN, 1);
107 gpio_set_value(GPO_CAM_PWR_EN, 0);
108 gpio_set_value(GPO_LCD_VCC_EN, 1);
109 gpio_set_value(GPO_SOFT_OFF, 1);
110 gpio_set_value(GPO_BT_EN, 1);
111 gpio_set_value(GPO_FAN_ON, 0);
112 gpio_set_value(GPO_SPKR, 0);
113 gpio_set_value(GPO_CPU_HEALTH, 1);
114 gpio_set_value(GPO_LAN_SEL, 1);
115/*
116 * DO NOT modify the GPO_SET_V1 and GPO_SET_V2 in kernel
117 * gpio_set_value(GPO_SET_V1, 1);
118 * gpio_set_value(GPO_SET_V2, 1);
119 */
120#endif
121 gpiochip_add(&puv3_gpio_chip);
122}
diff --git a/arch/unicore32/kernel/head.S b/arch/unicore32/kernel/head.S
new file mode 100644
index 00000000000..92255f3ab6a
--- /dev/null
+++ b/arch/unicore32/kernel/head.S
@@ -0,0 +1,252 @@
1/*
2 * linux/arch/unicore32/kernel/head.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14
15#include <asm/assembler.h>
16#include <asm/ptrace.h>
17#include <generated/asm-offsets.h>
18#include <asm/memory.h>
19#include <asm/thread_info.h>
20#include <asm/system.h>
21#include <asm/pgtable-hwdef.h>
22
23#if (PHYS_OFFSET & 0x003fffff)
24#error "PHYS_OFFSET must be at an even 4MiB boundary!"
25#endif
26
27#define KERNEL_RAM_VADDR (PAGE_OFFSET + KERNEL_IMAGE_START)
28#define KERNEL_RAM_PADDR (PHYS_OFFSET + KERNEL_IMAGE_START)
29
30#define KERNEL_PGD_PADDR (KERNEL_RAM_PADDR - 0x1000)
31#define KERNEL_PGD_VADDR (KERNEL_RAM_VADDR - 0x1000)
32
33#define KERNEL_START KERNEL_RAM_VADDR
34#define KERNEL_END _end
35
36/*
37 * swapper_pg_dir is the virtual address of the initial page table.
38 * We place the page tables 4K below KERNEL_RAM_VADDR. Therefore, we must
39 * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect
40 * the least significant 16 bits to be 0x8000, but we could probably
41 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x1000.
42 */
43#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
44#error KERNEL_RAM_VADDR must start at 0xXXXX8000
45#endif
46
47 .globl swapper_pg_dir
48 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x1000
49
50/*
51 * Kernel startup entry point.
52 * ---------------------------
53 *
54 * This is normally called from the decompressor code. The requirements
55 * are: MMU = off, D-cache = off, I-cache = dont care
56 *
57 * This code is mostly position independent, so if you link the kernel at
58 * 0xc0008000, you call this at __pa(0xc0008000).
59 */
60 __HEAD
61ENTRY(stext)
62 @ set asr
63 mov r0, #PRIV_MODE @ ensure priv mode
64 or r0, #PSR_R_BIT | PSR_I_BIT @ disable irqs
65 mov.a asr, r0
66
67 @ process identify
68 movc r0, p0.c0, #0 @ cpuid
69 movl r1, 0xff00ffff @ mask
70 movl r2, 0x4d000863 @ value
71 and r0, r1, r0
72 cxor.a r0, r2
73 bne __error_p @ invalid processor id
74
75 /*
76 * Clear the 4K level 1 swapper page table
77 */
78 movl r0, #KERNEL_PGD_PADDR @ page table address
79 mov r1, #0
80 add r2, r0, #0x1000
81101: stw.w r1, [r0]+, #4
82 stw.w r1, [r0]+, #4
83 stw.w r1, [r0]+, #4
84 stw.w r1, [r0]+, #4
85 cxor.a r0, r2
86 bne 101b
87
88 movl r4, #KERNEL_PGD_PADDR @ page table address
89 mov r7, #PMD_TYPE_SECT | PMD_PRESENT @ page size: section
90 or r7, r7, #PMD_SECT_CACHEABLE @ cacheable
91 or r7, r7, #PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC
92
93 /*
94 * Create identity mapping for first 4MB of kernel to
95 * cater for the MMU enable. This identity mapping
96 * will be removed by paging_init(). We use our current program
97 * counter to determine corresponding section base address.
98 */
99 mov r6, pc
100 mov r6, r6 >> #22 @ start of kernel section
101 or r1, r7, r6 << #22 @ flags + kernel base
102 stw r1, [r4+], r6 << #2 @ identity mapping
103
104 /*
105 * Now setup the pagetables for our kernel direct
106 * mapped region.
107 */
108 add r0, r4, #(KERNEL_START & 0xff000000) >> 20
109 stw.w r1, [r0+], #(KERNEL_START & 0x00c00000) >> 20
110 movl r6, #(KERNEL_END - 1)
111 add r0, r0, #4
112 add r6, r4, r6 >> #20
113102: csub.a r0, r6
114 add r1, r1, #1 << 22
115 bua 103f
116 stw.w r1, [r0]+, #4
117 b 102b
118103:
119 /*
120 * Then map first 4MB of ram in case it contains our boot params.
121 */
122 add r0, r4, #PAGE_OFFSET >> 20
123 or r6, r7, #(PHYS_OFFSET & 0xffc00000)
124 stw r6, [r0]
125
126 ldw r15, __switch_data @ address to jump to after
127
128 /*
129 * Initialise TLB, Caches, and MMU state ready to switch the MMU
130 * on.
131 */
132 mov r0, #0
133 movc p0.c5, r0, #28 @ cache invalidate all
134 nop8
135 movc p0.c6, r0, #6 @ TLB invalidate all
136 nop8
137
138 /*
139 * ..V. .... ..TB IDAM
140 * ..1. .... ..01 1111
141 */
142 movl r0, #0x201f @ control register setting
143
144 /*
145 * Setup common bits before finally enabling the MMU. Essentially
146 * this is just loading the page table pointer and domain access
147 * registers.
148 */
149 #ifndef CONFIG_ALIGNMENT_TRAP
150 andn r0, r0, #CR_A
151 #endif
152 #ifdef CONFIG_CPU_DCACHE_DISABLE
153 andn r0, r0, #CR_D
154 #endif
155 #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
156 andn r0, r0, #CR_B
157 #endif
158 #ifdef CONFIG_CPU_ICACHE_DISABLE
159 andn r0, r0, #CR_I
160 #endif
161
162 movc p0.c2, r4, #0 @ set pgd
163 b __turn_mmu_on
164ENDPROC(stext)
165
166/*
167 * Enable the MMU. This completely changes the stucture of the visible
168 * memory space. You will not be able to trace execution through this.
169 *
170 * r0 = cp#0 control register
171 * r15 = *virtual* address to jump to upon completion
172 */
173 .align 5
174__turn_mmu_on:
175 mov r0, r0
176 movc p0.c1, r0, #0 @ write control reg
177 nop @ fetch inst by phys addr
178 mov pc, r15
179 nop8 @ fetch inst by phys addr
180ENDPROC(__turn_mmu_on)
181
182/*
183 * Setup the initial page tables. We only setup the barest
184 * amount which are required to get the kernel running, which
185 * generally means mapping in the kernel code.
186 *
187 * r9 = cpuid
188 * r10 = procinfo
189 *
190 * Returns:
191 * r0, r3, r6, r7 corrupted
192 * r4 = physical page table address
193 */
194 .ltorg
195
196 .align 2
197 .type __switch_data, %object
198__switch_data:
199 .long __mmap_switched
200 .long __bss_start @ r6
201 .long _end @ r7
202 .long cr_alignment @ r8
203 .long init_thread_union + THREAD_START_SP @ sp
204
205/*
206 * The following fragment of code is executed with the MMU on in MMU mode,
207 * and uses absolute addresses; this is not position independent.
208 *
209 * r0 = cp#0 control register
210 */
211__mmap_switched:
212 adr r3, __switch_data + 4
213
214 ldm.w (r6, r7, r8), [r3]+
215 ldw sp, [r3]
216
217 mov fp, #0 @ Clear BSS (and zero fp)
218203: csub.a r6, r7
219 bea 204f
220 stw.w fp, [r6]+,#4
221 b 203b
222204:
223 andn r1, r0, #CR_A @ Clear 'A' bit
224 stm (r0, r1), [r8]+ @ Save control register values
225 b start_kernel
226ENDPROC(__mmap_switched)
227
228/*
229 * Exception handling. Something went wrong and we can't proceed. We
230 * ought to tell the user, but since we don't have any guarantee that
231 * we're even running on the right architecture, we do virtually nothing.
232 *
233 * If CONFIG_DEBUG_LL is set we try to print out something about the error
234 * and hope for the best (useful if bootloader fails to pass a proper
235 * machine ID for example).
236 */
237__error_p:
238#ifdef CONFIG_DEBUG_LL
239 adr r0, str_p1
240 b.l printascii
241 mov r0, r9
242 b.l printhex8
243 adr r0, str_p2
244 b.l printascii
245901: nop8
246 b 901b
247str_p1: .asciz "\nError: unrecognized processor variant (0x"
248str_p2: .asciz ").\n"
249 .align
250#endif
251ENDPROC(__error_p)
252
diff --git a/arch/unicore32/kernel/hibernate.c b/arch/unicore32/kernel/hibernate.c
new file mode 100644
index 00000000000..7d0f0b7983a
--- /dev/null
+++ b/arch/unicore32/kernel/hibernate.c
@@ -0,0 +1,160 @@
1/*
2 * linux/arch/unicore32/kernel/hibernate.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/gfp.h>
15#include <linux/suspend.h>
16#include <linux/bootmem.h>
17
18#include <asm/system.h>
19#include <asm/page.h>
20#include <asm/pgtable.h>
21#include <asm/pgalloc.h>
22#include <asm/suspend.h>
23
24#include "mach/pm.h"
25
26/* Pointer to the temporary resume page tables */
27pgd_t *resume_pg_dir;
28
29struct swsusp_arch_regs swsusp_arch_regs_cpu0;
30
31/*
32 * Create a middle page table on a resume-safe page and put a pointer to it in
33 * the given global directory entry. This only returns the gd entry
34 * in non-PAE compilation mode, since the middle layer is folded.
35 */
36static pmd_t *resume_one_md_table_init(pgd_t *pgd)
37{
38 pud_t *pud;
39 pmd_t *pmd_table;
40
41 pud = pud_offset(pgd, 0);
42 pmd_table = pmd_offset(pud, 0);
43
44 return pmd_table;
45}
46
47/*
48 * Create a page table on a resume-safe page and place a pointer to it in
49 * a middle page directory entry.
50 */
51static pte_t *resume_one_page_table_init(pmd_t *pmd)
52{
53 if (pmd_none(*pmd)) {
54 pte_t *page_table = (pte_t *)get_safe_page(GFP_ATOMIC);
55 if (!page_table)
56 return NULL;
57
58 set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_KERNEL_TABLE));
59
60 BUG_ON(page_table != pte_offset_kernel(pmd, 0));
61
62 return page_table;
63 }
64
65 return pte_offset_kernel(pmd, 0);
66}
67
68/*
69 * This maps the physical memory to kernel virtual address space, a total
70 * of max_low_pfn pages, by creating page tables starting from address
71 * PAGE_OFFSET. The page tables are allocated out of resume-safe pages.
72 */
73static int resume_physical_mapping_init(pgd_t *pgd_base)
74{
75 unsigned long pfn;
76 pgd_t *pgd;
77 pmd_t *pmd;
78 pte_t *pte;
79 int pgd_idx, pmd_idx;
80
81 pgd_idx = pgd_index(PAGE_OFFSET);
82 pgd = pgd_base + pgd_idx;
83 pfn = 0;
84
85 for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) {
86 pmd = resume_one_md_table_init(pgd);
87 if (!pmd)
88 return -ENOMEM;
89
90 if (pfn >= max_low_pfn)
91 continue;
92
93 for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD; pmd++, pmd_idx++) {
94 pte_t *max_pte;
95
96 if (pfn >= max_low_pfn)
97 break;
98
99 /* Map with normal page tables.
100 * NOTE: We can mark everything as executable here
101 */
102 pte = resume_one_page_table_init(pmd);
103 if (!pte)
104 return -ENOMEM;
105
106 max_pte = pte + PTRS_PER_PTE;
107 for (; pte < max_pte; pte++, pfn++) {
108 if (pfn >= max_low_pfn)
109 break;
110
111 set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
112 }
113 }
114 }
115
116 return 0;
117}
118
119static inline void resume_init_first_level_page_table(pgd_t *pg_dir)
120{
121}
122
123int swsusp_arch_resume(void)
124{
125 int error;
126
127 resume_pg_dir = (pgd_t *)get_safe_page(GFP_ATOMIC);
128 if (!resume_pg_dir)
129 return -ENOMEM;
130
131 resume_init_first_level_page_table(resume_pg_dir);
132 error = resume_physical_mapping_init(resume_pg_dir);
133 if (error)
134 return error;
135
136 /* We have got enough memory and from now on we cannot recover */
137 restore_image(resume_pg_dir, restore_pblist);
138 return 0;
139}
140
141/*
142 * pfn_is_nosave - check if given pfn is in the 'nosave' section
143 */
144
145int pfn_is_nosave(unsigned long pfn)
146{
147 unsigned long begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
148 unsigned long end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
149
150 return (pfn >= begin_pfn) && (pfn < end_pfn);
151}
152
153void save_processor_state(void)
154{
155}
156
157void restore_processor_state(void)
158{
159 local_flush_tlb_all();
160}
diff --git a/arch/unicore32/kernel/hibernate_asm.S b/arch/unicore32/kernel/hibernate_asm.S
new file mode 100644
index 00000000000..cc3c65253c8
--- /dev/null
+++ b/arch/unicore32/kernel/hibernate_asm.S
@@ -0,0 +1,117 @@
1/*
2 * linux/arch/unicore32/kernel/hibernate_asm.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/sys.h>
15#include <linux/errno.h>
16#include <linux/linkage.h>
17#include <generated/asm-offsets.h>
18#include <asm/page.h>
19#include <asm/pgtable.h>
20#include <asm/assembler.h>
21
22@ restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist)
23@ r0: resume_pg_dir
24@ r1: restore_pblist
25@ copy restore_pblist pages
26@ restore registers from swsusp_arch_regs_cpu0
27@
28ENTRY(restore_image)
29 sub r0, r0, #PAGE_OFFSET
30 mov r5, #0
31 movc p0.c6, r5, #6 @invalidate ITLB & DTLB
32 movc p0.c2, r0, #0
33 nop
34 nop
35 nop
36 nop
37 nop
38 nop
39 nop
40
41 .p2align 4,,7
42101:
43 csub.a r1, #0
44 beq 109f
45
46 ldw r6, [r1+], #PBE_ADDRESS
47 ldw r7, [r1+], #PBE_ORIN_ADDRESS
48
49 movl ip, #128
50102: ldm.w (r8 - r15), [r6]+
51 stm.w (r8 - r15), [r7]+
52 sub.a ip, ip, #1
53 bne 102b
54
55 ldw r1, [r1+], #PBE_NEXT
56 b 101b
57
58 .p2align 4,,7
59109:
60 /* go back to the original page tables */
61 ldw r0, =swapper_pg_dir
62 sub r0, r0, #PAGE_OFFSET
63 mov r5, #0
64 movc p0.c6, r5, #6
65 movc p0.c2, r0, #0
66 nop
67 nop
68 nop
69 nop
70 nop
71 nop
72 nop
73
74#ifdef CONFIG_UNICORE_FPU_F64
75 ldw ip, 1f
76 add ip, ip, #SWSUSP_FPSTATE
77 lfm.w (f0 - f7 ), [ip]+
78 lfm.w (f8 - f15), [ip]+
79 lfm.w (f16 - f23), [ip]+
80 lfm.w (f24 - f31), [ip]+
81 ldw r4, [ip]
82 ctf r4, s31
83#endif
84 mov r0, #0x0
85 ldw ip, 1f
86 add ip, ip, #SWSUSP_CPU
87 ldm.w (r4 - r15), [ip]+
88 ldm (r16 - r27, sp, pc), [ip]+ @ Load all regs saved previously
89
90 .align 2
911: .long swsusp_arch_regs_cpu0
92
93
94@ swsusp_arch_suspend()
95@ - prepare pc for resume, return from function without swsusp_save on resume
96@ - save registers in swsusp_arch_regs_cpu0
97@ - call swsusp_save write suspend image
98
99ENTRY(swsusp_arch_suspend)
100 ldw ip, 1f
101 add ip, ip, #SWSUSP_CPU
102 stm.w (r4 - r15), [ip]+
103 stm.w (r16 - r27, sp, lr), [ip]+
104
105#ifdef CONFIG_UNICORE_FPU_F64
106 ldw ip, 1f
107 add ip, ip, #SWSUSP_FPSTATE
108 sfm.w (f0 - f7 ), [ip]+
109 sfm.w (f8 - f15), [ip]+
110 sfm.w (f16 - f23), [ip]+
111 sfm.w (f24 - f31), [ip]+
112 cff r4, s31
113 stw r4, [ip]
114#endif
115 b swsusp_save @ no return
116
1171: .long swsusp_arch_regs_cpu0
diff --git a/arch/unicore32/kernel/init_task.c b/arch/unicore32/kernel/init_task.c
new file mode 100644
index 00000000000..a35a1e50e4f
--- /dev/null
+++ b/arch/unicore32/kernel/init_task.c
@@ -0,0 +1,44 @@
1/*
2 * linux/arch/unicore32/kernel/init_task.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/mm.h>
13#include <linux/module.h>
14#include <linux/fs.h>
15#include <linux/sched.h>
16#include <linux/init.h>
17#include <linux/init_task.h>
18#include <linux/mqueue.h>
19#include <linux/uaccess.h>
20
21#include <asm/pgtable.h>
22
23static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
24static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
25/*
26 * Initial thread structure.
27 *
28 * We need to make sure that this is 8192-byte aligned due to the
29 * way process stacks are handled. This is done by making sure
30 * the linker maps this in the .text segment right after head.S,
31 * and making head.S ensure the proper alignment.
32 *
33 * The things we do for performance..
34 */
35union thread_union init_thread_union __init_task_data = {
36 INIT_THREAD_INFO(init_task) };
37
38/*
39 * Initial task structure.
40 *
41 * All other task structs will be allocated on slabs in fork.c
42 */
43struct task_struct init_task = INIT_TASK(init_task);
44EXPORT_SYMBOL(init_task);
diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c
new file mode 100644
index 00000000000..b23624cf306
--- /dev/null
+++ b/arch/unicore32/kernel/irq.c
@@ -0,0 +1,426 @@
1/*
2 * linux/arch/unicore32/kernel/irq.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/kernel_stat.h>
13#include <linux/module.h>
14#include <linux/signal.h>
15#include <linux/ioport.h>
16#include <linux/interrupt.h>
17#include <linux/irq.h>
18#include <linux/random.h>
19#include <linux/smp.h>
20#include <linux/init.h>
21#include <linux/seq_file.h>
22#include <linux/errno.h>
23#include <linux/list.h>
24#include <linux/kallsyms.h>
25#include <linux/proc_fs.h>
26#include <linux/sysdev.h>
27#include <linux/gpio.h>
28
29#include <asm/system.h>
30#include <mach/hardware.h>
31
32#include "setup.h"
33
34/*
35 * PKUnity GPIO edge detection for IRQs:
36 * IRQs are generated on Falling-Edge, Rising-Edge, or both.
37 * Use this instead of directly setting GRER/GFER.
38 */
39static int GPIO_IRQ_rising_edge;
40static int GPIO_IRQ_falling_edge;
41static int GPIO_IRQ_mask = 0;
42
43#define GPIO_MASK(irq) (1 << (irq - IRQ_GPIO0))
44
45static int puv3_gpio_type(struct irq_data *d, unsigned int type)
46{
47 unsigned int mask;
48
49 if (d->irq < IRQ_GPIOHIGH)
50 mask = 1 << d->irq;
51 else
52 mask = GPIO_MASK(d->irq);
53
54 if (type == IRQ_TYPE_PROBE) {
55 if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
56 return 0;
57 type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
58 }
59
60 if (type & IRQ_TYPE_EDGE_RISING)
61 GPIO_IRQ_rising_edge |= mask;
62 else
63 GPIO_IRQ_rising_edge &= ~mask;
64 if (type & IRQ_TYPE_EDGE_FALLING)
65 GPIO_IRQ_falling_edge |= mask;
66 else
67 GPIO_IRQ_falling_edge &= ~mask;
68
69 writel(GPIO_IRQ_rising_edge & GPIO_IRQ_mask, GPIO_GRER);
70 writel(GPIO_IRQ_falling_edge & GPIO_IRQ_mask, GPIO_GFER);
71
72 return 0;
73}
74
75/*
76 * GPIO IRQs must be acknowledged. This is for IRQs from 0 to 7.
77 */
78static void puv3_low_gpio_ack(struct irq_data *d)
79{
80 writel((1 << d->irq), GPIO_GEDR);
81}
82
83static void puv3_low_gpio_mask(struct irq_data *d)
84{
85 writel(readl(INTC_ICMR) & ~(1 << d->irq), INTC_ICMR);
86}
87
88static void puv3_low_gpio_unmask(struct irq_data *d)
89{
90 writel(readl(INTC_ICMR) | (1 << d->irq), INTC_ICMR);
91}
92
93static int puv3_low_gpio_wake(struct irq_data *d, unsigned int on)
94{
95 if (on)
96 writel(readl(PM_PWER) | (1 << d->irq), PM_PWER);
97 else
98 writel(readl(PM_PWER) & ~(1 << d->irq), PM_PWER);
99 return 0;
100}
101
102static struct irq_chip puv3_low_gpio_chip = {
103 .name = "GPIO-low",
104 .irq_ack = puv3_low_gpio_ack,
105 .irq_mask = puv3_low_gpio_mask,
106 .irq_unmask = puv3_low_gpio_unmask,
107 .irq_set_type = puv3_gpio_type,
108 .irq_set_wake = puv3_low_gpio_wake,
109};
110
111/*
112 * IRQ8 (GPIO0 through 27) handler. We enter here with the
113 * irq_controller_lock held, and IRQs disabled. Decode the IRQ
114 * and call the handler.
115 */
116static void
117puv3_gpio_handler(unsigned int irq, struct irq_desc *desc)
118{
119 unsigned int mask;
120
121 mask = readl(GPIO_GEDR);
122 do {
123 /*
124 * clear down all currently active IRQ sources.
125 * We will be processing them all.
126 */
127 writel(mask, GPIO_GEDR);
128
129 irq = IRQ_GPIO0;
130 do {
131 if (mask & 1)
132 generic_handle_irq(irq);
133 mask >>= 1;
134 irq++;
135 } while (mask);
136 mask = readl(GPIO_GEDR);
137 } while (mask);
138}
139
140/*
141 * GPIO0-27 edge IRQs need to be handled specially.
142 * In addition, the IRQs are all collected up into one bit in the
143 * interrupt controller registers.
144 */
145static void puv3_high_gpio_ack(struct irq_data *d)
146{
147 unsigned int mask = GPIO_MASK(d->irq);
148
149 writel(mask, GPIO_GEDR);
150}
151
152static void puv3_high_gpio_mask(struct irq_data *d)
153{
154 unsigned int mask = GPIO_MASK(d->irq);
155
156 GPIO_IRQ_mask &= ~mask;
157
158 writel(readl(GPIO_GRER) & ~mask, GPIO_GRER);
159 writel(readl(GPIO_GFER) & ~mask, GPIO_GFER);
160}
161
162static void puv3_high_gpio_unmask(struct irq_data *d)
163{
164 unsigned int mask = GPIO_MASK(d->irq);
165
166 GPIO_IRQ_mask |= mask;
167
168 writel(GPIO_IRQ_rising_edge & GPIO_IRQ_mask, GPIO_GRER);
169 writel(GPIO_IRQ_falling_edge & GPIO_IRQ_mask, GPIO_GFER);
170}
171
172static int puv3_high_gpio_wake(struct irq_data *d, unsigned int on)
173{
174 if (on)
175 writel(readl(PM_PWER) | PM_PWER_GPIOHIGH, PM_PWER);
176 else
177 writel(readl(PM_PWER) & ~PM_PWER_GPIOHIGH, PM_PWER);
178 return 0;
179}
180
181static struct irq_chip puv3_high_gpio_chip = {
182 .name = "GPIO-high",
183 .irq_ack = puv3_high_gpio_ack,
184 .irq_mask = puv3_high_gpio_mask,
185 .irq_unmask = puv3_high_gpio_unmask,
186 .irq_set_type = puv3_gpio_type,
187 .irq_set_wake = puv3_high_gpio_wake,
188};
189
190/*
191 * We don't need to ACK IRQs on the PKUnity unless they're GPIOs
192 * this is for internal IRQs i.e. from 8 to 31.
193 */
194static void puv3_mask_irq(struct irq_data *d)
195{
196 writel(readl(INTC_ICMR) & ~(1 << d->irq), INTC_ICMR);
197}
198
199static void puv3_unmask_irq(struct irq_data *d)
200{
201 writel(readl(INTC_ICMR) | (1 << d->irq), INTC_ICMR);
202}
203
204/*
205 * Apart form GPIOs, only the RTC alarm can be a wakeup event.
206 */
207static int puv3_set_wake(struct irq_data *d, unsigned int on)
208{
209 if (d->irq == IRQ_RTCAlarm) {
210 if (on)
211 writel(readl(PM_PWER) | PM_PWER_RTC, PM_PWER);
212 else
213 writel(readl(PM_PWER) & ~PM_PWER_RTC, PM_PWER);
214 return 0;
215 }
216 return -EINVAL;
217}
218
219static struct irq_chip puv3_normal_chip = {
220 .name = "PKUnity-v3",
221 .irq_ack = puv3_mask_irq,
222 .irq_mask = puv3_mask_irq,
223 .irq_unmask = puv3_unmask_irq,
224 .irq_set_wake = puv3_set_wake,
225};
226
227static struct resource irq_resource = {
228 .name = "irqs",
229 .start = io_v2p(PKUNITY_INTC_BASE),
230 .end = io_v2p(PKUNITY_INTC_BASE) + 0xFFFFF,
231};
232
233static struct puv3_irq_state {
234 unsigned int saved;
235 unsigned int icmr;
236 unsigned int iclr;
237 unsigned int iccr;
238} puv3_irq_state;
239
240static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state)
241{
242 struct puv3_irq_state *st = &puv3_irq_state;
243
244 st->saved = 1;
245 st->icmr = readl(INTC_ICMR);
246 st->iclr = readl(INTC_ICLR);
247 st->iccr = readl(INTC_ICCR);
248
249 /*
250 * Disable all GPIO-based interrupts.
251 */
252 writel(readl(INTC_ICMR) & ~(0x1ff), INTC_ICMR);
253
254 /*
255 * Set the appropriate edges for wakeup.
256 */
257 writel(readl(PM_PWER) & GPIO_IRQ_rising_edge, GPIO_GRER);
258 writel(readl(PM_PWER) & GPIO_IRQ_falling_edge, GPIO_GFER);
259
260 /*
261 * Clear any pending GPIO interrupts.
262 */
263 writel(readl(GPIO_GEDR), GPIO_GEDR);
264
265 return 0;
266}
267
268static int puv3_irq_resume(struct sys_device *dev)
269{
270 struct puv3_irq_state *st = &puv3_irq_state;
271
272 if (st->saved) {
273 writel(st->iccr, INTC_ICCR);
274 writel(st->iclr, INTC_ICLR);
275
276 writel(GPIO_IRQ_rising_edge & GPIO_IRQ_mask, GPIO_GRER);
277 writel(GPIO_IRQ_falling_edge & GPIO_IRQ_mask, GPIO_GFER);
278
279 writel(st->icmr, INTC_ICMR);
280 }
281 return 0;
282}
283
284static struct sysdev_class puv3_irq_sysclass = {
285 .name = "pkunity-irq",
286 .suspend = puv3_irq_suspend,
287 .resume = puv3_irq_resume,
288};
289
290static struct sys_device puv3_irq_device = {
291 .id = 0,
292 .cls = &puv3_irq_sysclass,
293};
294
295static int __init puv3_irq_init_devicefs(void)
296{
297 sysdev_class_register(&puv3_irq_sysclass);
298 return sysdev_register(&puv3_irq_device);
299}
300
301device_initcall(puv3_irq_init_devicefs);
302
303void __init init_IRQ(void)
304{
305 unsigned int irq;
306
307 request_resource(&iomem_resource, &irq_resource);
308
309 /* disable all IRQs */
310 writel(0, INTC_ICMR);
311
312 /* all IRQs are IRQ, not REAL */
313 writel(0, INTC_ICLR);
314
315 /* clear all GPIO edge detects */
316 writel(FMASK(8, 0) & ~FIELD(1, 1, GPI_SOFF_REQ), GPIO_GPIR);
317 writel(0, GPIO_GFER);
318 writel(0, GPIO_GRER);
319 writel(0x0FFFFFFF, GPIO_GEDR);
320
321 writel(1, INTC_ICCR);
322
323 for (irq = 0; irq < IRQ_GPIOHIGH; irq++) {
324 set_irq_chip(irq, &puv3_low_gpio_chip);
325 set_irq_handler(irq, handle_edge_irq);
326 irq_modify_status(irq,
327 IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN,
328 0);
329 }
330
331 for (irq = IRQ_GPIOHIGH + 1; irq < IRQ_GPIO0; irq++) {
332 set_irq_chip(irq, &puv3_normal_chip);
333 set_irq_handler(irq, handle_level_irq);
334 irq_modify_status(irq,
335 IRQ_NOREQUEST | IRQ_NOAUTOEN,
336 IRQ_NOPROBE);
337 }
338
339 for (irq = IRQ_GPIO0; irq <= IRQ_GPIO27; irq++) {
340 set_irq_chip(irq, &puv3_high_gpio_chip);
341 set_irq_handler(irq, handle_edge_irq);
342 irq_modify_status(irq,
343 IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN,
344 0);
345 }
346
347 /*
348 * Install handler for GPIO 0-27 edge detect interrupts
349 */
350 set_irq_chip(IRQ_GPIOHIGH, &puv3_normal_chip);
351 set_irq_chained_handler(IRQ_GPIOHIGH, puv3_gpio_handler);
352
353#ifdef CONFIG_PUV3_GPIO
354 puv3_init_gpio();
355#endif
356}
357
358int show_interrupts(struct seq_file *p, void *v)
359{
360 int i = *(loff_t *) v, cpu;
361 struct irq_desc *desc;
362 struct irqaction *action;
363 unsigned long flags;
364
365 if (i == 0) {
366 char cpuname[12];
367
368 seq_printf(p, " ");
369 for_each_present_cpu(cpu) {
370 sprintf(cpuname, "CPU%d", cpu);
371 seq_printf(p, " %10s", cpuname);
372 }
373 seq_putc(p, '\n');
374 }
375
376 if (i < nr_irqs) {
377 desc = irq_to_desc(i);
378 raw_spin_lock_irqsave(&desc->lock, flags);
379 action = desc->action;
380 if (!action)
381 goto unlock;
382
383 seq_printf(p, "%3d: ", i);
384 for_each_present_cpu(cpu)
385 seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu));
386 seq_printf(p, " %10s", desc->irq_data.chip->name ? : "-");
387 seq_printf(p, " %s", action->name);
388 for (action = action->next; action; action = action->next)
389 seq_printf(p, ", %s", action->name);
390
391 seq_putc(p, '\n');
392unlock:
393 raw_spin_unlock_irqrestore(&desc->lock, flags);
394 } else if (i == nr_irqs) {
395 seq_printf(p, "Error in interrupt!\n");
396 }
397 return 0;
398}
399
400/*
401 * do_IRQ handles all hardware IRQ's. Decoded IRQs should not
402 * come via this function. Instead, they should provide their
403 * own 'handler'
404 */
405asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
406{
407 struct pt_regs *old_regs = set_irq_regs(regs);
408
409 irq_enter();
410
411 /*
412 * Some hardware gives randomly wrong interrupts. Rather
413 * than crashing, do something sensible.
414 */
415 if (unlikely(irq >= nr_irqs)) {
416 if (printk_ratelimit())
417 printk(KERN_WARNING "Bad IRQ%u\n", irq);
418 ack_bad_irq(irq);
419 } else {
420 generic_handle_irq(irq);
421 }
422
423 irq_exit();
424 set_irq_regs(old_regs);
425}
426
diff --git a/arch/unicore32/kernel/ksyms.c b/arch/unicore32/kernel/ksyms.c
new file mode 100644
index 00000000000..a8970809428
--- /dev/null
+++ b/arch/unicore32/kernel/ksyms.c
@@ -0,0 +1,99 @@
1/*
2 * linux/arch/unicore32/kernel/ksyms.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/string.h>
15#include <linux/cryptohash.h>
16#include <linux/delay.h>
17#include <linux/in6.h>
18#include <linux/syscalls.h>
19#include <linux/uaccess.h>
20#include <linux/io.h>
21
22#include <asm/checksum.h>
23#include <asm/system.h>
24
25#include "ksyms.h"
26
27EXPORT_SYMBOL(__uc32_find_next_zero_bit);
28EXPORT_SYMBOL(__uc32_find_next_bit);
29
30EXPORT_SYMBOL(__backtrace);
31
32 /* platform dependent support */
33EXPORT_SYMBOL(__udelay);
34EXPORT_SYMBOL(__const_udelay);
35
36 /* networking */
37EXPORT_SYMBOL(csum_partial);
38EXPORT_SYMBOL(csum_partial_copy_from_user);
39EXPORT_SYMBOL(csum_partial_copy_nocheck);
40EXPORT_SYMBOL(__csum_ipv6_magic);
41
42 /* io */
43#ifndef __raw_readsb
44EXPORT_SYMBOL(__raw_readsb);
45#endif
46#ifndef __raw_readsw
47EXPORT_SYMBOL(__raw_readsw);
48#endif
49#ifndef __raw_readsl
50EXPORT_SYMBOL(__raw_readsl);
51#endif
52#ifndef __raw_writesb
53EXPORT_SYMBOL(__raw_writesb);
54#endif
55#ifndef __raw_writesw
56EXPORT_SYMBOL(__raw_writesw);
57#endif
58#ifndef __raw_writesl
59EXPORT_SYMBOL(__raw_writesl);
60#endif
61
62 /* string / mem functions */
63EXPORT_SYMBOL(strchr);
64EXPORT_SYMBOL(strrchr);
65EXPORT_SYMBOL(memset);
66EXPORT_SYMBOL(memcpy);
67EXPORT_SYMBOL(memmove);
68EXPORT_SYMBOL(memchr);
69
70 /* user mem (segment) */
71EXPORT_SYMBOL(__strnlen_user);
72EXPORT_SYMBOL(__strncpy_from_user);
73
74EXPORT_SYMBOL(copy_page);
75
76EXPORT_SYMBOL(__copy_from_user);
77EXPORT_SYMBOL(__copy_to_user);
78EXPORT_SYMBOL(__clear_user);
79
80EXPORT_SYMBOL(__get_user_1);
81EXPORT_SYMBOL(__get_user_2);
82EXPORT_SYMBOL(__get_user_4);
83
84EXPORT_SYMBOL(__put_user_1);
85EXPORT_SYMBOL(__put_user_2);
86EXPORT_SYMBOL(__put_user_4);
87EXPORT_SYMBOL(__put_user_8);
88
89EXPORT_SYMBOL(__ashldi3);
90EXPORT_SYMBOL(__ashrdi3);
91EXPORT_SYMBOL(__divsi3);
92EXPORT_SYMBOL(__lshrdi3);
93EXPORT_SYMBOL(__modsi3);
94EXPORT_SYMBOL(__muldi3);
95EXPORT_SYMBOL(__ucmpdi2);
96EXPORT_SYMBOL(__udivsi3);
97EXPORT_SYMBOL(__umodsi3);
98EXPORT_SYMBOL(__bswapsi2);
99
diff --git a/arch/unicore32/kernel/ksyms.h b/arch/unicore32/kernel/ksyms.h
new file mode 100644
index 00000000000..185cdc712d0
--- /dev/null
+++ b/arch/unicore32/kernel/ksyms.h
@@ -0,0 +1,15 @@
1/*
2 * libgcc functions - functions that are used internally by the
3 * compiler... (prototypes are not correct though, but that
4 * doesn't really matter since they're not versioned).
5 */
6extern void __ashldi3(void);
7extern void __ashrdi3(void);
8extern void __divsi3(void);
9extern void __lshrdi3(void);
10extern void __modsi3(void);
11extern void __muldi3(void);
12extern void __ucmpdi2(void);
13extern void __udivsi3(void);
14extern void __umodsi3(void);
15extern void __bswapsi2(void);
diff --git a/arch/unicore32/kernel/module.c b/arch/unicore32/kernel/module.c
new file mode 100644
index 00000000000..3e5a38d71a1
--- /dev/null
+++ b/arch/unicore32/kernel/module.c
@@ -0,0 +1,152 @@
1/*
2 * linux/arch/unicore32/kernel/module.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/moduleloader.h>
14#include <linux/kernel.h>
15#include <linux/mm.h>
16#include <linux/elf.h>
17#include <linux/vmalloc.h>
18#include <linux/fs.h>
19#include <linux/string.h>
20#include <linux/gfp.h>
21
22#include <asm/pgtable.h>
23#include <asm/sections.h>
24
25void *module_alloc(unsigned long size)
26{
27 struct vm_struct *area;
28
29 size = PAGE_ALIGN(size);
30 if (!size)
31 return NULL;
32
33 area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
34 if (!area)
35 return NULL;
36
37 return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
38}
39
40void module_free(struct module *module, void *region)
41{
42 vfree(region);
43}
44
45int module_frob_arch_sections(Elf_Ehdr *hdr,
46 Elf_Shdr *sechdrs,
47 char *secstrings,
48 struct module *mod)
49{
50 return 0;
51}
52
53int
54apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
55 unsigned int relindex, struct module *module)
56{
57 Elf32_Shdr *symsec = sechdrs + symindex;
58 Elf32_Shdr *relsec = sechdrs + relindex;
59 Elf32_Shdr *dstsec = sechdrs + relsec->sh_info;
60 Elf32_Rel *rel = (void *)relsec->sh_addr;
61 unsigned int i;
62
63 for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) {
64 unsigned long loc;
65 Elf32_Sym *sym;
66 s32 offset;
67
68 offset = ELF32_R_SYM(rel->r_info);
69 if (offset < 0 || offset >
70 (symsec->sh_size / sizeof(Elf32_Sym))) {
71 printk(KERN_ERR "%s: bad relocation, "
72 "section %d reloc %d\n",
73 module->name, relindex, i);
74 return -ENOEXEC;
75 }
76
77 sym = ((Elf32_Sym *)symsec->sh_addr) + offset;
78
79 if (rel->r_offset < 0 || rel->r_offset >
80 dstsec->sh_size - sizeof(u32)) {
81 printk(KERN_ERR "%s: out of bounds relocation, "
82 "section %d reloc %d offset %d size %d\n",
83 module->name, relindex, i, rel->r_offset,
84 dstsec->sh_size);
85 return -ENOEXEC;
86 }
87
88 loc = dstsec->sh_addr + rel->r_offset;
89
90 switch (ELF32_R_TYPE(rel->r_info)) {
91 case R_UNICORE_NONE:
92 /* ignore */
93 break;
94
95 case R_UNICORE_ABS32:
96 *(u32 *)loc += sym->st_value;
97 break;
98
99 case R_UNICORE_PC24:
100 case R_UNICORE_CALL:
101 case R_UNICORE_JUMP24:
102 offset = (*(u32 *)loc & 0x00ffffff) << 2;
103 if (offset & 0x02000000)
104 offset -= 0x04000000;
105
106 offset += sym->st_value - loc;
107 if (offset & 3 ||
108 offset <= (s32)0xfe000000 ||
109 offset >= (s32)0x02000000) {
110 printk(KERN_ERR
111 "%s: relocation out of range, section "
112 "%d reloc %d sym '%s'\n", module->name,
113 relindex, i, strtab + sym->st_name);
114 return -ENOEXEC;
115 }
116
117 offset >>= 2;
118
119 *(u32 *)loc &= 0xff000000;
120 *(u32 *)loc |= offset & 0x00ffffff;
121 break;
122
123 default:
124 printk(KERN_ERR "%s: unknown relocation: %u\n",
125 module->name, ELF32_R_TYPE(rel->r_info));
126 return -ENOEXEC;
127 }
128 }
129 return 0;
130}
131
132int
133apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
134 unsigned int symindex, unsigned int relsec,
135 struct module *module)
136{
137 printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
138 module->name);
139 return -ENOEXEC;
140}
141
142int
143module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
144 struct module *module)
145{
146 return 0;
147}
148
149void
150module_arch_cleanup(struct module *mod)
151{
152}
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
new file mode 100644
index 00000000000..100eab842e6
--- /dev/null
+++ b/arch/unicore32/kernel/pci.c
@@ -0,0 +1,404 @@
1/*
2 * linux/arch/unicore32/kernel/pci.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * PCI bios-type initialisation for PCI machines
13 *
14 */
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <linux/pci.h>
19#include <linux/slab.h>
20#include <linux/init.h>
21#include <linux/io.h>
22
23static int debug_pci;
24static int use_firmware;
25
26#define CONFIG_CMD(bus, devfn, where) \
27 (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
28
29static int
30puv3_read_config(struct pci_bus *bus, unsigned int devfn, int where,
31 int size, u32 *value)
32{
33 writel(CONFIG_CMD(bus, devfn, where), PCICFG_ADDR);
34 switch (size) {
35 case 1:
36 *value = (readl(PCICFG_DATA) >> ((where & 3) * 8)) & 0xFF;
37 break;
38 case 2:
39 *value = (readl(PCICFG_DATA) >> ((where & 2) * 8)) & 0xFFFF;
40 break;
41 case 4:
42 *value = readl(PCICFG_DATA);
43 break;
44 }
45 return PCIBIOS_SUCCESSFUL;
46}
47
48static int
49puv3_write_config(struct pci_bus *bus, unsigned int devfn, int where,
50 int size, u32 value)
51{
52 writel(CONFIG_CMD(bus, devfn, where), PCICFG_ADDR);
53 switch (size) {
54 case 1:
55 writel((readl(PCICFG_DATA) & ~FMASK(8, (where&3)*8))
56 | FIELD(value, 8, (where&3)*8), PCICFG_DATA);
57 break;
58 case 2:
59 writel((readl(PCICFG_DATA) & ~FMASK(16, (where&2)*8))
60 | FIELD(value, 16, (where&2)*8), PCICFG_DATA);
61 break;
62 case 4:
63 writel(value, PCICFG_DATA);
64 break;
65 }
66 return PCIBIOS_SUCCESSFUL;
67}
68
69struct pci_ops pci_puv3_ops = {
70 .read = puv3_read_config,
71 .write = puv3_write_config,
72};
73
74void pci_puv3_preinit(void)
75{
76 printk(KERN_DEBUG "PCI: PKUnity PCI Controller Initializing ...\n");
77 /* config PCI bridge base */
78 writel(io_v2p(PKUNITY_PCIBRI_BASE), PCICFG_BRIBASE);
79
80 writel(0, PCIBRI_AHBCTL0);
81 writel(io_v2p(PKUNITY_PCIBRI_BASE) | PCIBRI_BARx_MEM, PCIBRI_AHBBAR0);
82 writel(0xFFFF0000, PCIBRI_AHBAMR0);
83 writel(0, PCIBRI_AHBTAR0);
84
85 writel(PCIBRI_CTLx_AT, PCIBRI_AHBCTL1);
86 writel(io_v2p(PKUNITY_PCILIO_BASE) | PCIBRI_BARx_IO, PCIBRI_AHBBAR1);
87 writel(0xFFFF0000, PCIBRI_AHBAMR1);
88 writel(0x00000000, PCIBRI_AHBTAR1);
89
90 writel(PCIBRI_CTLx_PREF, PCIBRI_AHBCTL2);
91 writel(io_v2p(PKUNITY_PCIMEM_BASE) | PCIBRI_BARx_MEM, PCIBRI_AHBBAR2);
92 writel(0xF8000000, PCIBRI_AHBAMR2);
93 writel(0, PCIBRI_AHBTAR2);
94
95 writel(io_v2p(PKUNITY_PCIAHB_BASE) | PCIBRI_BARx_MEM, PCIBRI_BAR1);
96
97 writel(PCIBRI_CTLx_AT | PCIBRI_CTLx_PREF, PCIBRI_PCICTL0);
98 writel(io_v2p(PKUNITY_PCIAHB_BASE) | PCIBRI_BARx_MEM, PCIBRI_PCIBAR0);
99 writel(0xF8000000, PCIBRI_PCIAMR0);
100 writel(PKUNITY_SDRAM_BASE, PCIBRI_PCITAR0);
101
102 writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
103}
104
105static int __init pci_puv3_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
106{
107 if (dev->bus->number == 0) {
108#ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
109 if (dev->devfn == 0x00)
110 return IRQ_PCIINTA;
111 else if (dev->devfn == 0x08)
112 return IRQ_PCIINTB;
113 else if (dev->devfn == 0x10)
114 return IRQ_PCIINTC;
115 else if (dev->devfn == 0x18)
116 return IRQ_PCIINTD;
117#endif
118#ifdef CONFIG_PUV3_DB0913 /* 3 pci slots */
119 if (dev->devfn == 0x30)
120 return IRQ_PCIINTB;
121 else if (dev->devfn == 0x60)
122 return IRQ_PCIINTC;
123 else if (dev->devfn == 0x58)
124 return IRQ_PCIINTD;
125#endif
126#if defined(CONFIG_PUV3_NB0916) || defined(CONFIG_PUV3_SMW0919)
127 /* only support 2 pci devices */
128 if (dev->devfn == 0x00)
129 return IRQ_PCIINTC; /* sata */
130#endif
131 }
132 return -1;
133}
134
135/*
136 * Only first 128MB of memory can be accessed via PCI.
137 * We use GFP_DMA to allocate safe buffers to do map/unmap.
138 * This is really ugly and we need a better way of specifying
139 * DMA-capable regions of memory.
140 */
141void __init puv3_pci_adjust_zones(unsigned long *zone_size,
142 unsigned long *zhole_size)
143{
144 unsigned int sz = SZ_128M >> PAGE_SHIFT;
145
146 /*
147 * Only adjust if > 128M on current system
148 */
149 if (zone_size[0] <= sz)
150 return;
151
152 zone_size[1] = zone_size[0] - sz;
153 zone_size[0] = sz;
154 zhole_size[1] = zhole_size[0];
155 zhole_size[0] = 0;
156}
157
158void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
159{
160 if (debug_pci)
161 printk(KERN_DEBUG "PCI: Assigning IRQ %02d to %s\n",
162 irq, pci_name(dev));
163 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
164}
165
166/*
167 * If the bus contains any of these devices, then we must not turn on
168 * parity checking of any kind.
169 */
170static inline int pdev_bad_for_parity(struct pci_dev *dev)
171{
172 return 0;
173}
174
175/*
176 * pcibios_fixup_bus - Called after each bus is probed,
177 * but before its children are examined.
178 */
179void __devinit pcibios_fixup_bus(struct pci_bus *bus)
180{
181 struct pci_dev *dev;
182 u16 features = PCI_COMMAND_SERR
183 | PCI_COMMAND_PARITY
184 | PCI_COMMAND_FAST_BACK;
185
186 bus->resource[0] = &ioport_resource;
187 bus->resource[1] = &iomem_resource;
188
189 /*
190 * Walk the devices on this bus, working out what we can
191 * and can't support.
192 */
193 list_for_each_entry(dev, &bus->devices, bus_list) {
194 u16 status;
195
196 pci_read_config_word(dev, PCI_STATUS, &status);
197
198 /*
199 * If any device on this bus does not support fast back
200 * to back transfers, then the bus as a whole is not able
201 * to support them. Having fast back to back transfers
202 * on saves us one PCI cycle per transaction.
203 */
204 if (!(status & PCI_STATUS_FAST_BACK))
205 features &= ~PCI_COMMAND_FAST_BACK;
206
207 if (pdev_bad_for_parity(dev))
208 features &= ~(PCI_COMMAND_SERR
209 | PCI_COMMAND_PARITY);
210
211 switch (dev->class >> 8) {
212 case PCI_CLASS_BRIDGE_PCI:
213 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status);
214 status |= PCI_BRIDGE_CTL_PARITY
215 | PCI_BRIDGE_CTL_MASTER_ABORT;
216 status &= ~(PCI_BRIDGE_CTL_BUS_RESET
217 | PCI_BRIDGE_CTL_FAST_BACK);
218 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status);
219 break;
220
221 case PCI_CLASS_BRIDGE_CARDBUS:
222 pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL,
223 &status);
224 status |= PCI_CB_BRIDGE_CTL_PARITY
225 | PCI_CB_BRIDGE_CTL_MASTER_ABORT;
226 pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL,
227 status);
228 break;
229 }
230 }
231
232 /*
233 * Now walk the devices again, this time setting them up.
234 */
235 list_for_each_entry(dev, &bus->devices, bus_list) {
236 u16 cmd;
237
238 pci_read_config_word(dev, PCI_COMMAND, &cmd);
239 cmd |= features;
240 pci_write_config_word(dev, PCI_COMMAND, cmd);
241
242 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
243 L1_CACHE_BYTES >> 2);
244 }
245
246 /*
247 * Propagate the flags to the PCI bridge.
248 */
249 if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
250 if (features & PCI_COMMAND_FAST_BACK)
251 bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
252 if (features & PCI_COMMAND_PARITY)
253 bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
254 }
255
256 /*
257 * Report what we did for this bus
258 */
259 printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n",
260 bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
261}
262#ifdef CONFIG_HOTPLUG
263EXPORT_SYMBOL(pcibios_fixup_bus);
264#endif
265
266static int __init pci_common_init(void)
267{
268 struct pci_bus *puv3_bus;
269
270 pci_puv3_preinit();
271
272 puv3_bus = pci_scan_bus(0, &pci_puv3_ops, NULL);
273
274 if (!puv3_bus)
275 panic("PCI: unable to scan bus!");
276
277 pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
278
279 if (!use_firmware) {
280 /*
281 * Size the bridge windows.
282 */
283 pci_bus_size_bridges(puv3_bus);
284
285 /*
286 * Assign resources.
287 */
288 pci_bus_assign_resources(puv3_bus);
289 }
290
291 /*
292 * Tell drivers about devices found.
293 */
294 pci_bus_add_devices(puv3_bus);
295
296 return 0;
297}
298subsys_initcall(pci_common_init);
299
300char * __devinit pcibios_setup(char *str)
301{
302 if (!strcmp(str, "debug")) {
303 debug_pci = 1;
304 return NULL;
305 } else if (!strcmp(str, "firmware")) {
306 use_firmware = 1;
307 return NULL;
308 }
309 return str;
310}
311
312/*
313 * From arch/i386/kernel/pci-i386.c:
314 *
315 * We need to avoid collisions with `mirrored' VGA ports
316 * and other strange ISA hardware, so we always want the
317 * addresses to be allocated in the 0x000-0x0ff region
318 * modulo 0x400.
319 *
320 * Why? Because some silly external IO cards only decode
321 * the low 10 bits of the IO address. The 0x00-0xff region
322 * is reserved for motherboard devices that decode all 16
323 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
324 * but we want to try to avoid allocating at 0x2900-0x2bff
325 * which might be mirrored at 0x0100-0x03ff..
326 */
327resource_size_t pcibios_align_resource(void *data, const struct resource *res,
328 resource_size_t size, resource_size_t align)
329{
330 resource_size_t start = res->start;
331
332 if (res->flags & IORESOURCE_IO && start & 0x300)
333 start = (start + 0x3ff) & ~0x3ff;
334
335 start = (start + align - 1) & ~(align - 1);
336
337 return start;
338}
339
340/**
341 * pcibios_enable_device - Enable I/O and memory.
342 * @dev: PCI device to be enabled
343 */
344int pcibios_enable_device(struct pci_dev *dev, int mask)
345{
346 u16 cmd, old_cmd;
347 int idx;
348 struct resource *r;
349
350 pci_read_config_word(dev, PCI_COMMAND, &cmd);
351 old_cmd = cmd;
352 for (idx = 0; idx < 6; idx++) {
353 /* Only set up the requested stuff */
354 if (!(mask & (1 << idx)))
355 continue;
356
357 r = dev->resource + idx;
358 if (!r->start && r->end) {
359 printk(KERN_ERR "PCI: Device %s not available because"
360 " of resource collisions\n", pci_name(dev));
361 return -EINVAL;
362 }
363 if (r->flags & IORESOURCE_IO)
364 cmd |= PCI_COMMAND_IO;
365 if (r->flags & IORESOURCE_MEM)
366 cmd |= PCI_COMMAND_MEMORY;
367 }
368
369 /*
370 * Bridges (eg, cardbus bridges) need to be fully enabled
371 */
372 if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
373 cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
374
375 if (cmd != old_cmd) {
376 printk("PCI: enabling device %s (%04x -> %04x)\n",
377 pci_name(dev), old_cmd, cmd);
378 pci_write_config_word(dev, PCI_COMMAND, cmd);
379 }
380 return 0;
381}
382
383int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
384 enum pci_mmap_state mmap_state, int write_combine)
385{
386 unsigned long phys;
387
388 if (mmap_state == pci_mmap_io)
389 return -EINVAL;
390
391 phys = vma->vm_pgoff;
392
393 /*
394 * Mark this as IO
395 */
396 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
397
398 if (remap_pfn_range(vma, vma->vm_start, phys,
399 vma->vm_end - vma->vm_start,
400 vma->vm_page_prot))
401 return -EAGAIN;
402
403 return 0;
404}
diff --git a/arch/unicore32/kernel/pm.c b/arch/unicore32/kernel/pm.c
new file mode 100644
index 00000000000..784bc2db3b2
--- /dev/null
+++ b/arch/unicore32/kernel/pm.c
@@ -0,0 +1,123 @@
1/*
2 * linux/arch/unicore32/kernel/pm.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/suspend.h>
16#include <linux/errno.h>
17#include <linux/slab.h>
18#include <linux/io.h>
19
20#include <mach/hardware.h>
21#include <mach/pm.h>
22
23#include "setup.h"
24
25struct puv3_cpu_pm_fns *puv3_cpu_pm_fns;
26static unsigned long *sleep_save;
27
28int puv3_pm_enter(suspend_state_t state)
29{
30 unsigned long sleep_save_checksum = 0, checksum = 0;
31 int i;
32
33 /* skip registers saving for standby */
34 if (state != PM_SUSPEND_STANDBY) {
35 puv3_cpu_pm_fns->save(sleep_save);
36 /* before sleeping, calculate and save a checksum */
37 for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++)
38 sleep_save_checksum += sleep_save[i];
39 }
40
41 /* *** go zzz *** */
42 puv3_cpu_pm_fns->enter(state);
43 cpu_init();
44#ifdef CONFIG_INPUT_KEYBOARD
45 puv3_ps2_init();
46#endif
47#ifdef CONFIG_PCI
48 pci_puv3_preinit();
49#endif
50 if (state != PM_SUSPEND_STANDBY) {
51 /* after sleeping, validate the checksum */
52 for (i = 0; i < puv3_cpu_pm_fns->save_count - 1; i++)
53 checksum += sleep_save[i];
54
55 /* if invalid, display message and wait for a hardware reset */
56 if (checksum != sleep_save_checksum) {
57 while (1)
58 puv3_cpu_pm_fns->enter(state);
59 }
60 puv3_cpu_pm_fns->restore(sleep_save);
61 }
62
63 pr_debug("*** made it back from resume\n");
64
65 return 0;
66}
67EXPORT_SYMBOL_GPL(puv3_pm_enter);
68
69unsigned long sleep_phys_sp(void *sp)
70{
71 return virt_to_phys(sp);
72}
73
74static int puv3_pm_valid(suspend_state_t state)
75{
76 if (puv3_cpu_pm_fns)
77 return puv3_cpu_pm_fns->valid(state);
78
79 return -EINVAL;
80}
81
82static int puv3_pm_prepare(void)
83{
84 int ret = 0;
85
86 if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->prepare)
87 ret = puv3_cpu_pm_fns->prepare();
88
89 return ret;
90}
91
92static void puv3_pm_finish(void)
93{
94 if (puv3_cpu_pm_fns && puv3_cpu_pm_fns->finish)
95 puv3_cpu_pm_fns->finish();
96}
97
98static struct platform_suspend_ops puv3_pm_ops = {
99 .valid = puv3_pm_valid,
100 .enter = puv3_pm_enter,
101 .prepare = puv3_pm_prepare,
102 .finish = puv3_pm_finish,
103};
104
105static int __init puv3_pm_init(void)
106{
107 if (!puv3_cpu_pm_fns) {
108 printk(KERN_ERR "no valid puv3_cpu_pm_fns defined\n");
109 return -EINVAL;
110 }
111
112 sleep_save = kmalloc(puv3_cpu_pm_fns->save_count
113 * sizeof(unsigned long), GFP_KERNEL);
114 if (!sleep_save) {
115 printk(KERN_ERR "failed to alloc memory for pm save\n");
116 return -ENOMEM;
117 }
118
119 suspend_set_ops(&puv3_pm_ops);
120 return 0;
121}
122
123device_initcall(puv3_pm_init);
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
new file mode 100644
index 00000000000..ba401df971e
--- /dev/null
+++ b/arch/unicore32/kernel/process.c
@@ -0,0 +1,389 @@
1/*
2 * linux/arch/unicore32/kernel/process.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <stdarg.h>
13
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/stddef.h>
19#include <linux/unistd.h>
20#include <linux/delay.h>
21#include <linux/reboot.h>
22#include <linux/interrupt.h>
23#include <linux/kallsyms.h>
24#include <linux/init.h>
25#include <linux/cpu.h>
26#include <linux/elfcore.h>
27#include <linux/pm.h>
28#include <linux/tick.h>
29#include <linux/utsname.h>
30#include <linux/uaccess.h>
31#include <linux/random.h>
32#include <linux/gpio.h>
33#include <linux/stacktrace.h>
34
35#include <asm/cacheflush.h>
36#include <asm/processor.h>
37#include <asm/system.h>
38#include <asm/stacktrace.h>
39
40#include "setup.h"
41
42static const char * const processor_modes[] = {
43 "UK00", "UK01", "UK02", "UK03", "UK04", "UK05", "UK06", "UK07",
44 "UK08", "UK09", "UK0A", "UK0B", "UK0C", "UK0D", "UK0E", "UK0F",
45 "USER", "REAL", "INTR", "PRIV", "UK14", "UK15", "UK16", "ABRT",
46 "UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR"
47};
48
49/*
50 * The idle thread, has rather strange semantics for calling pm_idle,
51 * but this is what x86 does and we need to do the same, so that
52 * things like cpuidle get called in the same way.
53 */
54void cpu_idle(void)
55{
56 /* endless idle loop with no priority at all */
57 while (1) {
58 tick_nohz_stop_sched_tick(1);
59 while (!need_resched()) {
60 local_irq_disable();
61 stop_critical_timings();
62 cpu_do_idle();
63 local_irq_enable();
64 start_critical_timings();
65 }
66 tick_nohz_restart_sched_tick();
67 preempt_enable_no_resched();
68 schedule();
69 preempt_disable();
70 }
71}
72
73static char reboot_mode = 'h';
74
75int __init reboot_setup(char *str)
76{
77 reboot_mode = str[0];
78 return 1;
79}
80
81__setup("reboot=", reboot_setup);
82
83void machine_halt(void)
84{
85 gpio_set_value(GPO_SOFT_OFF, 0);
86}
87
88/*
89 * Function pointers to optional machine specific functions
90 */
91void (*pm_power_off)(void) = NULL;
92
93void machine_power_off(void)
94{
95 if (pm_power_off)
96 pm_power_off();
97 machine_halt();
98}
99
100void machine_restart(char *cmd)
101{
102 /* Disable interrupts first */
103 local_irq_disable();
104
105 /*
106 * Tell the mm system that we are going to reboot -
107 * we may need it to insert some 1:1 mappings so that
108 * soft boot works.
109 */
110 setup_mm_for_reboot(reboot_mode);
111
112 /* Clean and invalidate caches */
113 flush_cache_all();
114
115 /* Turn off caching */
116 cpu_proc_fin();
117
118 /* Push out any further dirty data, and ensure cache is empty */
119 flush_cache_all();
120
121 /*
122 * Now handle reboot code.
123 */
124 if (reboot_mode == 's') {
125 /* Jump into ROM at address 0xffff0000 */
126 cpu_reset(VECTORS_BASE);
127 } else {
128 writel(0x00002001, PM_PLLSYSCFG); /* cpu clk = 250M */
129 writel(0x00100800, PM_PLLDDRCFG); /* ddr clk = 44M */
130 writel(0x00002001, PM_PLLVGACFG); /* vga clk = 250M */
131
132 /* Use on-chip reset capability */
133 /* following instructions must be in one icache line */
134 __asm__ __volatile__(
135 " .align 5\n\t"
136 " stw %1, [%0]\n\t"
137 "201: ldw r0, [%0]\n\t"
138 " cmpsub.a r0, #0\n\t"
139 " bne 201b\n\t"
140 " stw %3, [%2]\n\t"
141 " nop; nop; nop\n\t"
142 /* prefetch 3 instructions at most */
143 :
144 : "r" (PM_PMCR),
145 "r" (PM_PMCR_CFBSYS | PM_PMCR_CFBDDR
146 | PM_PMCR_CFBVGA),
147 "r" (RESETC_SWRR),
148 "r" (RESETC_SWRR_SRB)
149 : "r0", "memory");
150 }
151
152 /*
153 * Whoops - the architecture was unable to reboot.
154 * Tell the user!
155 */
156 mdelay(1000);
157 printk(KERN_EMERG "Reboot failed -- System halted\n");
158 do { } while (1);
159}
160
161void __show_regs(struct pt_regs *regs)
162{
163 unsigned long flags;
164 char buf[64];
165
166 printk(KERN_DEFAULT "CPU: %d %s (%s %.*s)\n",
167 raw_smp_processor_id(), print_tainted(),
168 init_utsname()->release,
169 (int)strcspn(init_utsname()->version, " "),
170 init_utsname()->version);
171 print_symbol("PC is at %s\n", instruction_pointer(regs));
172 print_symbol("LR is at %s\n", regs->UCreg_lr);
173 printk(KERN_DEFAULT "pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n"
174 "sp : %08lx ip : %08lx fp : %08lx\n",
175 regs->UCreg_pc, regs->UCreg_lr, regs->UCreg_asr,
176 regs->UCreg_sp, regs->UCreg_ip, regs->UCreg_fp);
177 printk(KERN_DEFAULT "r26: %08lx r25: %08lx r24: %08lx\n",
178 regs->UCreg_26, regs->UCreg_25,
179 regs->UCreg_24);
180 printk(KERN_DEFAULT "r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n",
181 regs->UCreg_23, regs->UCreg_22,
182 regs->UCreg_21, regs->UCreg_20);
183 printk(KERN_DEFAULT "r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n",
184 regs->UCreg_19, regs->UCreg_18,
185 regs->UCreg_17, regs->UCreg_16);
186 printk(KERN_DEFAULT "r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n",
187 regs->UCreg_15, regs->UCreg_14,
188 regs->UCreg_13, regs->UCreg_12);
189 printk(KERN_DEFAULT "r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n",
190 regs->UCreg_11, regs->UCreg_10,
191 regs->UCreg_09, regs->UCreg_08);
192 printk(KERN_DEFAULT "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
193 regs->UCreg_07, regs->UCreg_06,
194 regs->UCreg_05, regs->UCreg_04);
195 printk(KERN_DEFAULT "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
196 regs->UCreg_03, regs->UCreg_02,
197 regs->UCreg_01, regs->UCreg_00);
198
199 flags = regs->UCreg_asr;
200 buf[0] = flags & PSR_S_BIT ? 'S' : 's';
201 buf[1] = flags & PSR_Z_BIT ? 'Z' : 'z';
202 buf[2] = flags & PSR_C_BIT ? 'C' : 'c';
203 buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
204 buf[4] = '\0';
205
206 printk(KERN_DEFAULT "Flags: %s INTR o%s REAL o%s Mode %s Segment %s\n",
207 buf, interrupts_enabled(regs) ? "n" : "ff",
208 fast_interrupts_enabled(regs) ? "n" : "ff",
209 processor_modes[processor_mode(regs)],
210 segment_eq(get_fs(), get_ds()) ? "kernel" : "user");
211 {
212 unsigned int ctrl;
213
214 buf[0] = '\0';
215 {
216 unsigned int transbase;
217 asm("movc %0, p0.c2, #0\n"
218 : "=r" (transbase));
219 snprintf(buf, sizeof(buf), " Table: %08x", transbase);
220 }
221 asm("movc %0, p0.c1, #0\n" : "=r" (ctrl));
222
223 printk(KERN_DEFAULT "Control: %08x%s\n", ctrl, buf);
224 }
225}
226
227void show_regs(struct pt_regs *regs)
228{
229 printk(KERN_DEFAULT "\n");
230 printk(KERN_DEFAULT "Pid: %d, comm: %20s\n",
231 task_pid_nr(current), current->comm);
232 __show_regs(regs);
233 __backtrace();
234}
235
236/*
237 * Free current thread data structures etc..
238 */
239void exit_thread(void)
240{
241}
242
243void flush_thread(void)
244{
245 struct thread_info *thread = current_thread_info();
246 struct task_struct *tsk = current;
247
248 memset(thread->used_cp, 0, sizeof(thread->used_cp));
249 memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
250#ifdef CONFIG_UNICORE_FPU_F64
251 memset(&thread->fpstate, 0, sizeof(struct fp_state));
252#endif
253}
254
255void release_thread(struct task_struct *dead_task)
256{
257}
258
259asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
260
261int
262copy_thread(unsigned long clone_flags, unsigned long stack_start,
263 unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
264{
265 struct thread_info *thread = task_thread_info(p);
266 struct pt_regs *childregs = task_pt_regs(p);
267
268 *childregs = *regs;
269 childregs->UCreg_00 = 0;
270 childregs->UCreg_sp = stack_start;
271
272 memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
273 thread->cpu_context.sp = (unsigned long)childregs;
274 thread->cpu_context.pc = (unsigned long)ret_from_fork;
275
276 if (clone_flags & CLONE_SETTLS)
277 childregs->UCreg_16 = regs->UCreg_03;
278
279 return 0;
280}
281
282/*
283 * Fill in the task's elfregs structure for a core dump.
284 */
285int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs)
286{
287 elf_core_copy_regs(elfregs, task_pt_regs(t));
288 return 1;
289}
290
291/*
292 * fill in the fpe structure for a core dump...
293 */
294int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fp)
295{
296 struct thread_info *thread = current_thread_info();
297 int used_math = thread->used_cp[1] | thread->used_cp[2];
298
299#ifdef CONFIG_UNICORE_FPU_F64
300 if (used_math)
301 memcpy(fp, &thread->fpstate, sizeof(*fp));
302#endif
303 return used_math != 0;
304}
305EXPORT_SYMBOL(dump_fpu);
306
307/*
308 * Shuffle the argument into the correct register before calling the
309 * thread function. r1 is the thread argument, r2 is the pointer to
310 * the thread function, and r3 points to the exit function.
311 */
312asm(".pushsection .text\n"
313" .align\n"
314" .type kernel_thread_helper, #function\n"
315"kernel_thread_helper:\n"
316" mov.a asr, r7\n"
317" mov r0, r4\n"
318" mov lr, r6\n"
319" mov pc, r5\n"
320" .size kernel_thread_helper, . - kernel_thread_helper\n"
321" .popsection");
322
323/*
324 * Create a kernel thread.
325 */
326pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
327{
328 struct pt_regs regs;
329
330 memset(&regs, 0, sizeof(regs));
331
332 regs.UCreg_04 = (unsigned long)arg;
333 regs.UCreg_05 = (unsigned long)fn;
334 regs.UCreg_06 = (unsigned long)do_exit;
335 regs.UCreg_07 = PRIV_MODE;
336 regs.UCreg_pc = (unsigned long)kernel_thread_helper;
337 regs.UCreg_asr = regs.UCreg_07 | PSR_I_BIT;
338
339 return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
340}
341EXPORT_SYMBOL(kernel_thread);
342
343unsigned long get_wchan(struct task_struct *p)
344{
345 struct stackframe frame;
346 int count = 0;
347 if (!p || p == current || p->state == TASK_RUNNING)
348 return 0;
349
350 frame.fp = thread_saved_fp(p);
351 frame.sp = thread_saved_sp(p);
352 frame.lr = 0; /* recovered from the stack */
353 frame.pc = thread_saved_pc(p);
354 do {
355 int ret = unwind_frame(&frame);
356 if (ret < 0)
357 return 0;
358 if (!in_sched_functions(frame.pc))
359 return frame.pc;
360 } while ((count++) < 16);
361 return 0;
362}
363
364unsigned long arch_randomize_brk(struct mm_struct *mm)
365{
366 unsigned long range_end = mm->brk + 0x02000000;
367 return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
368}
369
370/*
371 * The vectors page is always readable from user space for the
372 * atomic helpers and the signal restart code. Let's declare a mapping
373 * for it so it is visible through ptrace and /proc/<pid>/mem.
374 */
375
376int vectors_user_mapping(void)
377{
378 struct mm_struct *mm = current->mm;
379 return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
380 VM_READ | VM_EXEC |
381 VM_MAYREAD | VM_MAYEXEC |
382 VM_ALWAYSDUMP | VM_RESERVED,
383 NULL);
384}
385
386const char *arch_vma_name(struct vm_area_struct *vma)
387{
388 return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
389}
diff --git a/arch/unicore32/kernel/ptrace.c b/arch/unicore32/kernel/ptrace.c
new file mode 100644
index 00000000000..9f07c08da05
--- /dev/null
+++ b/arch/unicore32/kernel/ptrace.c
@@ -0,0 +1,149 @@
1/*
2 * linux/arch/unicore32/kernel/ptrace.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * By Ross Biro 1/23/92
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#include <linux/kernel.h>
15#include <linux/ptrace.h>
16#include <linux/signal.h>
17#include <linux/uaccess.h>
18
19/*
20 * this routine will get a word off of the processes privileged stack.
21 * the offset is how far from the base addr as stored in the THREAD.
22 * this routine assumes that all the privileged stacks are in our
23 * data space.
24 */
25static inline long get_user_reg(struct task_struct *task, int offset)
26{
27 return task_pt_regs(task)->uregs[offset];
28}
29
30/*
31 * this routine will put a word on the processes privileged stack.
32 * the offset is how far from the base addr as stored in the THREAD.
33 * this routine assumes that all the privileged stacks are in our
34 * data space.
35 */
36static inline int
37put_user_reg(struct task_struct *task, int offset, long data)
38{
39 struct pt_regs newregs, *regs = task_pt_regs(task);
40 int ret = -EINVAL;
41
42 newregs = *regs;
43 newregs.uregs[offset] = data;
44
45 if (valid_user_regs(&newregs)) {
46 regs->uregs[offset] = data;
47 ret = 0;
48 }
49
50 return ret;
51}
52
53/*
54 * Called by kernel/ptrace.c when detaching..
55 */
56void ptrace_disable(struct task_struct *child)
57{
58}
59
60/*
61 * We actually access the pt_regs stored on the kernel stack.
62 */
63static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
64 unsigned long __user *ret)
65{
66 unsigned long tmp;
67
68 tmp = 0;
69 if (off < sizeof(struct pt_regs))
70 tmp = get_user_reg(tsk, off >> 2);
71
72 return put_user(tmp, ret);
73}
74
75/*
76 * We actually access the pt_regs stored on the kernel stack.
77 */
78static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
79 unsigned long val)
80{
81 if (off >= sizeof(struct pt_regs))
82 return 0;
83
84 return put_user_reg(tsk, off >> 2, val);
85}
86
87long arch_ptrace(struct task_struct *child, long request,
88 unsigned long addr, unsigned long data)
89{
90 int ret;
91 unsigned long __user *datap = (unsigned long __user *) data;
92
93 switch (request) {
94 case PTRACE_PEEKUSR:
95 ret = ptrace_read_user(child, addr, datap);
96 break;
97
98 case PTRACE_POKEUSR:
99 ret = ptrace_write_user(child, addr, data);
100 break;
101
102 case PTRACE_GET_THREAD_AREA:
103 ret = put_user(task_pt_regs(child)->UCreg_16,
104 datap);
105 break;
106
107 default:
108 ret = ptrace_request(child, request, addr, data);
109 break;
110 }
111
112 return ret;
113}
114
115asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
116{
117 unsigned long ip;
118
119 if (!test_thread_flag(TIF_SYSCALL_TRACE))
120 return scno;
121 if (!(current->ptrace & PT_PTRACED))
122 return scno;
123
124 /*
125 * Save IP. IP is used to denote syscall entry/exit:
126 * IP = 0 -> entry, = 1 -> exit
127 */
128 ip = regs->UCreg_ip;
129 regs->UCreg_ip = why;
130
131 current_thread_info()->syscall = scno;
132
133 /* the 0x80 provides a way for the tracing parent to distinguish
134 between a syscall stop and SIGTRAP delivery */
135 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
136 ? 0x80 : 0));
137 /*
138 * this isn't the same as continuing with a signal, but it will do
139 * for normal use. strace only continues with a signal if the
140 * stopping signal is not SIGTRAP. -brl
141 */
142 if (current->exit_code) {
143 send_sig(current->exit_code, current, 1);
144 current->exit_code = 0;
145 }
146 regs->UCreg_ip = ip;
147
148 return current_thread_info()->syscall;
149}
diff --git a/arch/unicore32/kernel/puv3-core.c b/arch/unicore32/kernel/puv3-core.c
new file mode 100644
index 00000000000..8b1b6beb858
--- /dev/null
+++ b/arch/unicore32/kernel/puv3-core.c
@@ -0,0 +1,285 @@
1/*
2 * linux/arch/unicore32/kernel/puv3-core.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/init.h>
15#include <linux/device.h>
16#include <linux/sysdev.h>
17#include <linux/amba/bus.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20#include <linux/cnt32_to_63.h>
21#include <linux/usb/musb.h>
22
23#include <asm/irq.h>
24#include <mach/hardware.h>
25#include <mach/pm.h>
26
27/*
28 * This is the PKUnity sched_clock implementation. This has
29 * a resolution of 271ns, and a maximum value of 32025597s (370 days).
30 *
31 * The return value is guaranteed to be monotonic in that range as
32 * long as there is always less than 582 seconds between successive
33 * calls to this function.
34 *
35 * ( * 1E9 / CLOCK_TICK_RATE ) -> about 2235/32
36 */
37unsigned long long sched_clock(void)
38{
39 unsigned long long v = cnt32_to_63(readl(OST_OSCR));
40
41 /* original conservative method, but overflow frequently
42 * v *= NSEC_PER_SEC >> 12;
43 * do_div(v, CLOCK_TICK_RATE >> 12);
44 */
45 v = ((v & 0x7fffffffffffffffULL) * 2235) >> 5;
46
47 return v;
48}
49
50static struct resource puv3_usb_resources[] = {
51 /* order is significant! */
52 {
53 .start = io_v2p(PKUNITY_USB_BASE),
54 .end = io_v2p(PKUNITY_USB_BASE) + 0x3ff,
55 .flags = IORESOURCE_MEM,
56 }, {
57 .start = IRQ_USB,
58 .flags = IORESOURCE_IRQ,
59 }, {
60 .start = IRQ_USB,
61 .flags = IORESOURCE_IRQ,
62 },
63};
64
65static struct musb_hdrc_config puv3_usb_config[] = {
66 {
67 .num_eps = 16,
68 .multipoint = 1,
69#ifdef CONFIG_USB_INVENTRA_DMA
70 .dma = 1,
71 .dma_channels = 8,
72#endif
73 },
74};
75
76static struct musb_hdrc_platform_data puv3_usb_plat = {
77 .mode = MUSB_HOST,
78 .min_power = 100,
79 .clock = 0,
80 .config = puv3_usb_config,
81};
82
83static struct resource puv3_mmc_resources[] = {
84 [0] = {
85 .start = io_v2p(PKUNITY_SDC_BASE),
86 .end = io_v2p(PKUNITY_SDC_BASE) + 0xfff,
87 .flags = IORESOURCE_MEM,
88 },
89 [1] = {
90 .start = IRQ_SDC,
91 .end = IRQ_SDC,
92 .flags = IORESOURCE_IRQ,
93 },
94};
95
96static struct resource puv3_unigfx_resources[] = {
97 [0] = {
98 .start = io_v2p(PKUNITY_UNIGFX_BASE),
99 .end = io_v2p(PKUNITY_UNIGFX_BASE) + 0xfff,
100 .flags = IORESOURCE_MEM,
101 },
102 [1] = {
103 .start = PKUNITY_UNIGFX_MMAP_BASE,
104 .end = PKUNITY_UNIGFX_MMAP_BASE + PKUNITY_UNIGFX_MMAP_SIZE,
105 .flags = IORESOURCE_MEM,
106 },
107};
108
109static struct resource puv3_rtc_resources[] = {
110 [0] = {
111 .start = io_v2p(PKUNITY_RTC_BASE),
112 .end = io_v2p(PKUNITY_RTC_BASE) + 0xff,
113 .flags = IORESOURCE_MEM,
114 },
115 [1] = {
116 .start = IRQ_RTCAlarm,
117 .end = IRQ_RTCAlarm,
118 .flags = IORESOURCE_IRQ,
119 },
120 [2] = {
121 .start = IRQ_RTC,
122 .end = IRQ_RTC,
123 .flags = IORESOURCE_IRQ
124 }
125};
126
127static struct resource puv3_pwm_resources[] = {
128 [0] = {
129 .start = io_v2p(PKUNITY_OST_BASE) + 0x80,
130 .end = io_v2p(PKUNITY_OST_BASE) + 0xff,
131 .flags = IORESOURCE_MEM,
132 },
133};
134
135static struct resource puv3_uart0_resources[] = {
136 [0] = {
137 .start = io_v2p(PKUNITY_UART0_BASE),
138 .end = io_v2p(PKUNITY_UART0_BASE) + 0xff,
139 .flags = IORESOURCE_MEM,
140 },
141 [1] = {
142 .start = IRQ_UART0,
143 .end = IRQ_UART0,
144 .flags = IORESOURCE_IRQ
145 }
146};
147
148static struct resource puv3_uart1_resources[] = {
149 [0] = {
150 .start = io_v2p(PKUNITY_UART1_BASE),
151 .end = io_v2p(PKUNITY_UART1_BASE) + 0xff,
152 .flags = IORESOURCE_MEM,
153 },
154 [1] = {
155 .start = IRQ_UART1,
156 .end = IRQ_UART1,
157 .flags = IORESOURCE_IRQ
158 }
159};
160
161static struct resource puv3_umal_resources[] = {
162 [0] = {
163 .start = io_v2p(PKUNITY_UMAL_BASE),
164 .end = io_v2p(PKUNITY_UMAL_BASE) + 0x1fff,
165 .flags = IORESOURCE_MEM,
166 },
167 [1] = {
168 .start = IRQ_UMAL,
169 .end = IRQ_UMAL,
170 .flags = IORESOURCE_IRQ
171 }
172};
173
174#ifdef CONFIG_PUV3_PM
175
176#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
177#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
178
179/*
180 * List of global PXA peripheral registers to preserve.
181 * More ones like CP and general purpose register values are preserved
182 * with the stack pointer in sleep.S.
183 */
184enum {
185 SLEEP_SAVE_PM_PLLDDRCFG,
186 SLEEP_SAVE_COUNT
187};
188
189
190static void puv3_cpu_pm_save(unsigned long *sleep_save)
191{
192/* SAVE(PM_PLLDDRCFG); */
193}
194
195static void puv3_cpu_pm_restore(unsigned long *sleep_save)
196{
197/* RESTORE(PM_PLLDDRCFG); */
198}
199
200static int puv3_cpu_pm_prepare(void)
201{
202 /* set resume return address */
203 writel(virt_to_phys(puv3_cpu_resume), PM_DIVCFG);
204 return 0;
205}
206
207static void puv3_cpu_pm_enter(suspend_state_t state)
208{
209 /* Clear reset status */
210 writel(RESETC_RSSR_HWR | RESETC_RSSR_WDR
211 | RESETC_RSSR_SMR | RESETC_RSSR_SWR, RESETC_RSSR);
212
213 switch (state) {
214/* case PM_SUSPEND_ON:
215 puv3_cpu_idle();
216 break; */
217 case PM_SUSPEND_MEM:
218 puv3_cpu_pm_prepare();
219 puv3_cpu_suspend(PM_PMCR_SFB);
220 break;
221 }
222}
223
224static int puv3_cpu_pm_valid(suspend_state_t state)
225{
226 return state == PM_SUSPEND_MEM;
227}
228
229static void puv3_cpu_pm_finish(void)
230{
231 /* ensure not to come back here if it wasn't intended */
232 /* PSPR = 0; */
233}
234
235static struct puv3_cpu_pm_fns puv3_cpu_pm_fnss = {
236 .save_count = SLEEP_SAVE_COUNT,
237 .valid = puv3_cpu_pm_valid,
238 .save = puv3_cpu_pm_save,
239 .restore = puv3_cpu_pm_restore,
240 .enter = puv3_cpu_pm_enter,
241 .prepare = puv3_cpu_pm_prepare,
242 .finish = puv3_cpu_pm_finish,
243};
244
245static void __init puv3_init_pm(void)
246{
247 puv3_cpu_pm_fns = &puv3_cpu_pm_fnss;
248}
249#else
250static inline void puv3_init_pm(void) {}
251#endif
252
253void puv3_ps2_init(void)
254{
255 struct clk *bclk32;
256
257 bclk32 = clk_get(NULL, "BUS32_CLK");
258 writel(clk_get_rate(bclk32) / 200000, PS2_CNT); /* should > 5us */
259}
260
261void __init puv3_core_init(void)
262{
263 puv3_init_pm();
264 puv3_ps2_init();
265
266 platform_device_register_simple("PKUnity-v3-RTC", -1,
267 puv3_rtc_resources, ARRAY_SIZE(puv3_rtc_resources));
268 platform_device_register_simple("PKUnity-v3-UMAL", -1,
269 puv3_umal_resources, ARRAY_SIZE(puv3_umal_resources));
270 platform_device_register_simple("PKUnity-v3-MMC", -1,
271 puv3_mmc_resources, ARRAY_SIZE(puv3_mmc_resources));
272 platform_device_register_simple("PKUnity-v3-UNIGFX", -1,
273 puv3_unigfx_resources, ARRAY_SIZE(puv3_unigfx_resources));
274 platform_device_register_simple("PKUnity-v3-PWM", -1,
275 puv3_pwm_resources, ARRAY_SIZE(puv3_pwm_resources));
276 platform_device_register_simple("PKUnity-v3-UART", 0,
277 puv3_uart0_resources, ARRAY_SIZE(puv3_uart0_resources));
278 platform_device_register_simple("PKUnity-v3-UART", 1,
279 puv3_uart1_resources, ARRAY_SIZE(puv3_uart1_resources));
280 platform_device_register_simple("PKUnity-v3-AC97", -1, NULL, 0);
281 platform_device_register_resndata(&platform_bus, "musb_hdrc", -1,
282 puv3_usb_resources, ARRAY_SIZE(puv3_usb_resources),
283 &puv3_usb_plat, sizeof(puv3_usb_plat));
284}
285
diff --git a/arch/unicore32/kernel/puv3-nb0916.c b/arch/unicore32/kernel/puv3-nb0916.c
new file mode 100644
index 00000000000..e731c561ed4
--- /dev/null
+++ b/arch/unicore32/kernel/puv3-nb0916.c
@@ -0,0 +1,145 @@
1/*
2 * linux/arch/unicore32/kernel/puv3-nb0916.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/init.h>
15#include <linux/device.h>
16#include <linux/sysdev.h>
17#include <linux/platform_device.h>
18#include <linux/mtd/physmap.h>
19#include <linux/io.h>
20#include <linux/reboot.h>
21#include <linux/interrupt.h>
22#include <linux/i2c.h>
23#include <linux/pwm_backlight.h>
24#include <linux/gpio.h>
25#include <linux/gpio_keys.h>
26#include <linux/input.h>
27
28#include <mach/hardware.h>
29
30static struct physmap_flash_data physmap_flash_data = {
31 .width = 1,
32};
33
34static struct resource physmap_flash_resource = {
35 .start = 0xFFF80000,
36 .end = 0xFFFFFFFF,
37 .flags = IORESOURCE_MEM,
38};
39
40static struct resource puv3_i2c_resources[] = {
41 [0] = {
42 .start = io_v2p(PKUNITY_I2C_BASE),
43 .end = io_v2p(PKUNITY_I2C_BASE) + 0xff,
44 .flags = IORESOURCE_MEM,
45 },
46 [1] = {
47 .start = IRQ_I2C,
48 .end = IRQ_I2C,
49 .flags = IORESOURCE_IRQ,
50 }
51};
52
53static struct platform_pwm_backlight_data nb0916_backlight_data = {
54 .pwm_id = 0,
55 .max_brightness = 100,
56 .dft_brightness = 100,
57 .pwm_period_ns = 70 * 1024,
58};
59
60static struct gpio_keys_button nb0916_gpio_keys[] = {
61 {
62 .type = EV_KEY,
63 .code = KEY_POWER,
64 .gpio = GPI_SOFF_REQ,
65 .desc = "Power Button",
66 .wakeup = 1,
67 .active_low = 1,
68 },
69 {
70 .type = EV_KEY,
71 .code = BTN_TOUCH,
72 .gpio = GPI_BTN_TOUCH,
73 .desc = "Touchpad Button",
74 .wakeup = 1,
75 .active_low = 1,
76 },
77};
78
79static struct gpio_keys_platform_data nb0916_gpio_button_data = {
80 .buttons = nb0916_gpio_keys,
81 .nbuttons = ARRAY_SIZE(nb0916_gpio_keys),
82};
83
84static irqreturn_t nb0916_lcdcaseoff_handler(int irq, void *dev_id)
85{
86 if (gpio_get_value(GPI_LCD_CASE_OFF))
87 gpio_set_value(GPO_LCD_EN, 1);
88 else
89 gpio_set_value(GPO_LCD_EN, 0);
90
91 return IRQ_HANDLED;
92}
93
94static irqreturn_t nb0916_overheat_handler(int irq, void *dev_id)
95{
96 machine_halt();
97 /* SYSTEM HALT, NO RETURN */
98 return IRQ_HANDLED;
99}
100
101static struct i2c_board_info __initdata puv3_i2c_devices[] = {
102 { I2C_BOARD_INFO("lm75", I2C_TAR_THERMAL), },
103 { I2C_BOARD_INFO("bq27200", I2C_TAR_PWIC), },
104 { I2C_BOARD_INFO("24c02", I2C_TAR_EEPROM), },
105};
106
107int __init mach_nb0916_init(void)
108{
109 i2c_register_board_info(0, puv3_i2c_devices,
110 ARRAY_SIZE(puv3_i2c_devices));
111
112 platform_device_register_simple("PKUnity-v3-I2C", -1,
113 puv3_i2c_resources, ARRAY_SIZE(puv3_i2c_resources));
114
115 platform_device_register_data(&platform_bus, "pwm-backlight", -1,
116 &nb0916_backlight_data, sizeof(nb0916_backlight_data));
117
118 platform_device_register_data(&platform_bus, "gpio-keys", -1,
119 &nb0916_gpio_button_data, sizeof(nb0916_gpio_button_data));
120
121 platform_device_register_resndata(&platform_bus, "physmap-flash", -1,
122 &physmap_flash_resource, 1,
123 &physmap_flash_data, sizeof(physmap_flash_data));
124
125 if (request_irq(gpio_to_irq(GPI_LCD_CASE_OFF),
126 &nb0916_lcdcaseoff_handler,
127 IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
128 "NB0916 lcd case off", NULL) < 0) {
129
130 printk(KERN_DEBUG "LCD-Case-OFF IRQ %d not available\n",
131 gpio_to_irq(GPI_LCD_CASE_OFF));
132 }
133
134 if (request_irq(gpio_to_irq(GPI_OTP_INT), &nb0916_overheat_handler,
135 IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
136 "NB0916 overheating protection", NULL) < 0) {
137
138 printk(KERN_DEBUG "Overheating Protection IRQ %d not available\n",
139 gpio_to_irq(GPI_OTP_INT));
140 }
141
142 return 0;
143}
144
145subsys_initcall_sync(mach_nb0916_init);
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c
new file mode 100644
index 00000000000..4615d51e3ba
--- /dev/null
+++ b/arch/unicore32/kernel/pwm.c
@@ -0,0 +1,263 @@
1/*
2 * linux/arch/unicore32/kernel/pwm.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18#include <linux/err.h>
19#include <linux/clk.h>
20#include <linux/io.h>
21#include <linux/pwm.h>
22
23#include <asm/div64.h>
24#include <mach/hardware.h>
25
26struct pwm_device {
27 struct list_head node;
28 struct platform_device *pdev;
29
30 const char *label;
31 struct clk *clk;
32 int clk_enabled;
33
34 unsigned int use_count;
35 unsigned int pwm_id;
36};
37
38/*
39 * period_ns = 10^9 * (PRESCALE + 1) * (PV + 1) / PWM_CLK_RATE
40 * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
41 */
42int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
43{
44 unsigned long long c;
45 unsigned long period_cycles, prescale, pv, dc;
46
47 if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
48 return -EINVAL;
49
50 c = clk_get_rate(pwm->clk);
51 c = c * period_ns;
52 do_div(c, 1000000000);
53 period_cycles = c;
54
55 if (period_cycles < 1)
56 period_cycles = 1;
57 prescale = (period_cycles - 1) / 1024;
58 pv = period_cycles / (prescale + 1) - 1;
59
60 if (prescale > 63)
61 return -EINVAL;
62
63 if (duty_ns == period_ns)
64 dc = OST_PWMDCCR_FDCYCLE;
65 else
66 dc = (pv + 1) * duty_ns / period_ns;
67
68 /* NOTE: the clock to PWM has to be enabled first
69 * before writing to the registers
70 */
71 clk_enable(pwm->clk);
72 OST_PWMPWCR = prescale;
73 OST_PWMDCCR = pv - dc;
74 OST_PWMPCR = pv;
75 clk_disable(pwm->clk);
76
77 return 0;
78}
79EXPORT_SYMBOL(pwm_config);
80
81int pwm_enable(struct pwm_device *pwm)
82{
83 int rc = 0;
84
85 if (!pwm->clk_enabled) {
86 rc = clk_enable(pwm->clk);
87 if (!rc)
88 pwm->clk_enabled = 1;
89 }
90 return rc;
91}
92EXPORT_SYMBOL(pwm_enable);
93
94void pwm_disable(struct pwm_device *pwm)
95{
96 if (pwm->clk_enabled) {
97 clk_disable(pwm->clk);
98 pwm->clk_enabled = 0;
99 }
100}
101EXPORT_SYMBOL(pwm_disable);
102
103static DEFINE_MUTEX(pwm_lock);
104static LIST_HEAD(pwm_list);
105
106struct pwm_device *pwm_request(int pwm_id, const char *label)
107{
108 struct pwm_device *pwm;
109 int found = 0;
110
111 mutex_lock(&pwm_lock);
112
113 list_for_each_entry(pwm, &pwm_list, node) {
114 if (pwm->pwm_id == pwm_id) {
115 found = 1;
116 break;
117 }
118 }
119
120 if (found) {
121 if (pwm->use_count == 0) {
122 pwm->use_count++;
123 pwm->label = label;
124 } else
125 pwm = ERR_PTR(-EBUSY);
126 } else
127 pwm = ERR_PTR(-ENOENT);
128
129 mutex_unlock(&pwm_lock);
130 return pwm;
131}
132EXPORT_SYMBOL(pwm_request);
133
134void pwm_free(struct pwm_device *pwm)
135{
136 mutex_lock(&pwm_lock);
137
138 if (pwm->use_count) {
139 pwm->use_count--;
140 pwm->label = NULL;
141 } else
142 pr_warning("PWM device already freed\n");
143
144 mutex_unlock(&pwm_lock);
145}
146EXPORT_SYMBOL(pwm_free);
147
148static inline void __add_pwm(struct pwm_device *pwm)
149{
150 mutex_lock(&pwm_lock);
151 list_add_tail(&pwm->node, &pwm_list);
152 mutex_unlock(&pwm_lock);
153}
154
155static struct pwm_device *pwm_probe(struct platform_device *pdev,
156 unsigned int pwm_id, struct pwm_device *parent_pwm)
157{
158 struct pwm_device *pwm;
159 struct resource *r;
160 int ret = 0;
161
162 pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
163 if (pwm == NULL) {
164 dev_err(&pdev->dev, "failed to allocate memory\n");
165 return ERR_PTR(-ENOMEM);
166 }
167
168 pwm->clk = clk_get(NULL, "OST_CLK");
169 if (IS_ERR(pwm->clk)) {
170 ret = PTR_ERR(pwm->clk);
171 goto err_free;
172 }
173 pwm->clk_enabled = 0;
174
175 pwm->use_count = 0;
176 pwm->pwm_id = pwm_id;
177 pwm->pdev = pdev;
178
179 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180 if (r == NULL) {
181 dev_err(&pdev->dev, "no memory resource defined\n");
182 ret = -ENODEV;
183 goto err_free_clk;
184 }
185
186 r = request_mem_region(r->start, resource_size(r), pdev->name);
187 if (r == NULL) {
188 dev_err(&pdev->dev, "failed to request memory resource\n");
189 ret = -EBUSY;
190 goto err_free_clk;
191 }
192
193 __add_pwm(pwm);
194 platform_set_drvdata(pdev, pwm);
195 return pwm;
196
197err_free_clk:
198 clk_put(pwm->clk);
199err_free:
200 kfree(pwm);
201 return ERR_PTR(ret);
202}
203
204static int __devinit puv3_pwm_probe(struct platform_device *pdev)
205{
206 struct pwm_device *pwm = pwm_probe(pdev, pdev->id, NULL);
207
208 if (IS_ERR(pwm))
209 return PTR_ERR(pwm);
210
211 return 0;
212}
213
214static int __devexit pwm_remove(struct platform_device *pdev)
215{
216 struct pwm_device *pwm;
217 struct resource *r;
218
219 pwm = platform_get_drvdata(pdev);
220 if (pwm == NULL)
221 return -ENODEV;
222
223 mutex_lock(&pwm_lock);
224 list_del(&pwm->node);
225 mutex_unlock(&pwm_lock);
226
227 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
228 release_mem_region(r->start, resource_size(r));
229
230 clk_put(pwm->clk);
231 kfree(pwm);
232 return 0;
233}
234
235static struct platform_driver puv3_pwm_driver = {
236 .driver = {
237 .name = "PKUnity-v3-PWM",
238 },
239 .probe = puv3_pwm_probe,
240 .remove = __devexit_p(pwm_remove),
241};
242
243static int __init pwm_init(void)
244{
245 int ret = 0;
246
247 ret = platform_driver_register(&puv3_pwm_driver);
248 if (ret) {
249 printk(KERN_ERR "failed to register puv3_pwm_driver\n");
250 return ret;
251 }
252
253 return ret;
254}
255arch_initcall(pwm_init);
256
257static void __exit pwm_exit(void)
258{
259 platform_driver_unregister(&puv3_pwm_driver);
260}
261module_exit(pwm_exit);
262
263MODULE_LICENSE("GPL v2");
diff --git a/arch/unicore32/kernel/rtc.c b/arch/unicore32/kernel/rtc.c
new file mode 100644
index 00000000000..c5f068295b5
--- /dev/null
+++ b/arch/unicore32/kernel/rtc.c
@@ -0,0 +1,380 @@
1/*
2 * linux/arch/unicore32/kernel/rtc.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/string.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/interrupt.h>
20#include <linux/rtc.h>
21#include <linux/bcd.h>
22#include <linux/clk.h>
23#include <linux/log2.h>
24#include <linux/slab.h>
25#include <linux/uaccess.h>
26#include <linux/io.h>
27
28#include <asm/irq.h>
29#include <mach/hardware.h>
30
31static struct resource *puv3_rtc_mem;
32
33static int puv3_rtc_alarmno = IRQ_RTCAlarm;
34static int puv3_rtc_tickno = IRQ_RTC;
35
36static DEFINE_SPINLOCK(puv3_rtc_pie_lock);
37
38/* IRQ Handlers */
39
40static irqreturn_t puv3_rtc_alarmirq(int irq, void *id)
41{
42 struct rtc_device *rdev = id;
43
44 writel(readl(RTC_RTSR) | RTC_RTSR_AL, RTC_RTSR);
45 rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
46 return IRQ_HANDLED;
47}
48
49static irqreturn_t puv3_rtc_tickirq(int irq, void *id)
50{
51 struct rtc_device *rdev = id;
52
53 writel(readl(RTC_RTSR) | RTC_RTSR_HZ, RTC_RTSR);
54 rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
55 return IRQ_HANDLED;
56}
57
58/* Update control registers */
59static void puv3_rtc_setaie(int to)
60{
61 unsigned int tmp;
62
63 pr_debug("%s: aie=%d\n", __func__, to);
64
65 tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE;
66
67 if (to)
68 tmp |= RTC_RTSR_ALE;
69
70 writel(tmp, RTC_RTSR);
71}
72
73static int puv3_rtc_setpie(struct device *dev, int enabled)
74{
75 unsigned int tmp;
76
77 pr_debug("%s: pie=%d\n", __func__, enabled);
78
79 spin_lock_irq(&puv3_rtc_pie_lock);
80 tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE;
81
82 if (enabled)
83 tmp |= RTC_RTSR_HZE;
84
85 writel(tmp, RTC_RTSR);
86 spin_unlock_irq(&puv3_rtc_pie_lock);
87
88 return 0;
89}
90
91static int puv3_rtc_setfreq(struct device *dev, int freq)
92{
93 return 0;
94}
95
96/* Time read/write */
97
98static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
99{
100 rtc_time_to_tm(readl(RTC_RCNR), rtc_tm);
101
102 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
103 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
104 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
105
106 return 0;
107}
108
109static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm)
110{
111 unsigned long rtc_count = 0;
112
113 pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
114 tm->tm_year, tm->tm_mon, tm->tm_mday,
115 tm->tm_hour, tm->tm_min, tm->tm_sec);
116
117 rtc_tm_to_time(tm, &rtc_count);
118 writel(rtc_count, RTC_RCNR);
119
120 return 0;
121}
122
123static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
124{
125 struct rtc_time *alm_tm = &alrm->time;
126
127 rtc_time_to_tm(readl(RTC_RTAR), alm_tm);
128
129 alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE;
130
131 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
132 alrm->enabled,
133 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
134 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
135
136 return 0;
137}
138
139static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
140{
141 struct rtc_time *tm = &alrm->time;
142 unsigned long rtcalarm_count = 0;
143
144 pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
145 alrm->enabled,
146 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
147 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
148
149 rtc_tm_to_time(tm, &rtcalarm_count);
150 writel(rtcalarm_count, RTC_RTAR);
151
152 puv3_rtc_setaie(alrm->enabled);
153
154 if (alrm->enabled)
155 enable_irq_wake(puv3_rtc_alarmno);
156 else
157 disable_irq_wake(puv3_rtc_alarmno);
158
159 return 0;
160}
161
162static int puv3_rtc_proc(struct device *dev, struct seq_file *seq)
163{
164 seq_printf(seq, "periodic_IRQ\t: %s\n",
165 (readl(RTC_RTSR) & RTC_RTSR_HZE) ? "yes" : "no");
166 return 0;
167}
168
169static int puv3_rtc_open(struct device *dev)
170{
171 struct platform_device *pdev = to_platform_device(dev);
172 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
173 int ret;
174
175 ret = request_irq(puv3_rtc_alarmno, puv3_rtc_alarmirq,
176 IRQF_DISABLED, "pkunity-rtc alarm", rtc_dev);
177
178 if (ret) {
179 dev_err(dev, "IRQ%d error %d\n", puv3_rtc_alarmno, ret);
180 return ret;
181 }
182
183 ret = request_irq(puv3_rtc_tickno, puv3_rtc_tickirq,
184 IRQF_DISABLED, "pkunity-rtc tick", rtc_dev);
185
186 if (ret) {
187 dev_err(dev, "IRQ%d error %d\n", puv3_rtc_tickno, ret);
188 goto tick_err;
189 }
190
191 return ret;
192
193 tick_err:
194 free_irq(puv3_rtc_alarmno, rtc_dev);
195 return ret;
196}
197
198static void puv3_rtc_release(struct device *dev)
199{
200 struct platform_device *pdev = to_platform_device(dev);
201 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
202
203 /* do not clear AIE here, it may be needed for wake */
204
205 puv3_rtc_setpie(dev, 0);
206 free_irq(puv3_rtc_alarmno, rtc_dev);
207 free_irq(puv3_rtc_tickno, rtc_dev);
208}
209
210static const struct rtc_class_ops puv3_rtcops = {
211 .open = puv3_rtc_open,
212 .release = puv3_rtc_release,
213 .read_time = puv3_rtc_gettime,
214 .set_time = puv3_rtc_settime,
215 .read_alarm = puv3_rtc_getalarm,
216 .set_alarm = puv3_rtc_setalarm,
217 .irq_set_freq = puv3_rtc_setfreq,
218 .irq_set_state = puv3_rtc_setpie,
219 .proc = puv3_rtc_proc,
220};
221
222static void puv3_rtc_enable(struct platform_device *pdev, int en)
223{
224 if (!en) {
225 writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR);
226 } else {
227 /* re-enable the device, and check it is ok */
228
229 if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) {
230 dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
231 writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR);
232 }
233 }
234}
235
236static int puv3_rtc_remove(struct platform_device *dev)
237{
238 struct rtc_device *rtc = platform_get_drvdata(dev);
239
240 platform_set_drvdata(dev, NULL);
241 rtc_device_unregister(rtc);
242
243 puv3_rtc_setpie(&dev->dev, 0);
244 puv3_rtc_setaie(0);
245
246 release_resource(puv3_rtc_mem);
247 kfree(puv3_rtc_mem);
248
249 return 0;
250}
251
252static int puv3_rtc_probe(struct platform_device *pdev)
253{
254 struct rtc_device *rtc;
255 struct resource *res;
256 int ret;
257
258 pr_debug("%s: probe=%p\n", __func__, pdev);
259
260 /* find the IRQs */
261
262 puv3_rtc_tickno = platform_get_irq(pdev, 1);
263 if (puv3_rtc_tickno < 0) {
264 dev_err(&pdev->dev, "no irq for rtc tick\n");
265 return -ENOENT;
266 }
267
268 puv3_rtc_alarmno = platform_get_irq(pdev, 0);
269 if (puv3_rtc_alarmno < 0) {
270 dev_err(&pdev->dev, "no irq for alarm\n");
271 return -ENOENT;
272 }
273
274 pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n",
275 puv3_rtc_tickno, puv3_rtc_alarmno);
276
277 /* get the memory region */
278
279 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
280 if (res == NULL) {
281 dev_err(&pdev->dev, "failed to get memory region resource\n");
282 return -ENOENT;
283 }
284
285 puv3_rtc_mem = request_mem_region(res->start,
286 res->end-res->start+1,
287 pdev->name);
288
289 if (puv3_rtc_mem == NULL) {
290 dev_err(&pdev->dev, "failed to reserve memory region\n");
291 ret = -ENOENT;
292 goto err_nores;
293 }
294
295 puv3_rtc_enable(pdev, 1);
296
297 puv3_rtc_setfreq(&pdev->dev, 1);
298
299 /* register RTC and exit */
300
301 rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops,
302 THIS_MODULE);
303
304 if (IS_ERR(rtc)) {
305 dev_err(&pdev->dev, "cannot attach rtc\n");
306 ret = PTR_ERR(rtc);
307 goto err_nortc;
308 }
309
310 /* platform setup code should have handled this; sigh */
311 if (!device_can_wakeup(&pdev->dev))
312 device_init_wakeup(&pdev->dev, 1);
313
314 platform_set_drvdata(pdev, rtc);
315 return 0;
316
317 err_nortc:
318 puv3_rtc_enable(pdev, 0);
319 release_resource(puv3_rtc_mem);
320
321 err_nores:
322 return ret;
323}
324
325#ifdef CONFIG_PM
326
327/* RTC Power management control */
328
329static int ticnt_save;
330
331static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state)
332{
333 /* save RTAR for anyone using periodic interrupts */
334 ticnt_save = readl(RTC_RTAR);
335 puv3_rtc_enable(pdev, 0);
336 return 0;
337}
338
339static int puv3_rtc_resume(struct platform_device *pdev)
340{
341 puv3_rtc_enable(pdev, 1);
342 writel(ticnt_save, RTC_RTAR);
343 return 0;
344}
345#else
346#define puv3_rtc_suspend NULL
347#define puv3_rtc_resume NULL
348#endif
349
350static struct platform_driver puv3_rtcdrv = {
351 .probe = puv3_rtc_probe,
352 .remove = __devexit_p(puv3_rtc_remove),
353 .suspend = puv3_rtc_suspend,
354 .resume = puv3_rtc_resume,
355 .driver = {
356 .name = "PKUnity-v3-RTC",
357 .owner = THIS_MODULE,
358 }
359};
360
361static char __initdata banner[] = "PKUnity-v3 RTC, (c) 2009 PKUnity Co.\n";
362
363static int __init puv3_rtc_init(void)
364{
365 printk(banner);
366 return platform_driver_register(&puv3_rtcdrv);
367}
368
369static void __exit puv3_rtc_exit(void)
370{
371 platform_driver_unregister(&puv3_rtcdrv);
372}
373
374module_init(puv3_rtc_init);
375module_exit(puv3_rtc_exit);
376
377MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip");
378MODULE_AUTHOR("Hu Dongliang");
379MODULE_LICENSE("GPL v2");
380
diff --git a/arch/unicore32/kernel/setup.c b/arch/unicore32/kernel/setup.c
new file mode 100644
index 00000000000..1e175a82844
--- /dev/null
+++ b/arch/unicore32/kernel/setup.c
@@ -0,0 +1,360 @@
1/*
2 * linux/arch/unicore32/kernel/setup.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/stddef.h>
15#include <linux/ioport.h>
16#include <linux/delay.h>
17#include <linux/utsname.h>
18#include <linux/initrd.h>
19#include <linux/console.h>
20#include <linux/bootmem.h>
21#include <linux/seq_file.h>
22#include <linux/screen_info.h>
23#include <linux/init.h>
24#include <linux/root_dev.h>
25#include <linux/cpu.h>
26#include <linux/interrupt.h>
27#include <linux/smp.h>
28#include <linux/fs.h>
29#include <linux/proc_fs.h>
30#include <linux/memblock.h>
31#include <linux/elf.h>
32#include <linux/io.h>
33
34#include <asm/cputype.h>
35#include <asm/sections.h>
36#include <asm/setup.h>
37#include <asm/cacheflush.h>
38#include <asm/tlbflush.h>
39#include <asm/traps.h>
40
41#include "setup.h"
42
43#ifndef MEM_SIZE
44#define MEM_SIZE (16*1024*1024)
45#endif
46
47struct stack {
48 u32 irq[3];
49 u32 abt[3];
50 u32 und[3];
51} ____cacheline_aligned;
52
53static struct stack stacks[NR_CPUS];
54
55char elf_platform[ELF_PLATFORM_SIZE];
56EXPORT_SYMBOL(elf_platform);
57
58static char __initdata cmd_line[COMMAND_LINE_SIZE];
59
60static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
61
62/*
63 * Standard memory resources
64 */
65static struct resource mem_res[] = {
66 {
67 .name = "Video RAM",
68 .start = 0,
69 .end = 0,
70 .flags = IORESOURCE_MEM
71 },
72 {
73 .name = "Kernel text",
74 .start = 0,
75 .end = 0,
76 .flags = IORESOURCE_MEM
77 },
78 {
79 .name = "Kernel data",
80 .start = 0,
81 .end = 0,
82 .flags = IORESOURCE_MEM
83 }
84};
85
86#define video_ram mem_res[0]
87#define kernel_code mem_res[1]
88#define kernel_data mem_res[2]
89
90/*
91 * These functions re-use the assembly code in head.S, which
92 * already provide the required functionality.
93 */
94static void __init setup_processor(void)
95{
96 printk(KERN_DEFAULT "CPU: UniCore-II [%08x] revision %d, cr=%08lx\n",
97 uc32_cpuid, (int)(uc32_cpuid >> 16) & 15, cr_alignment);
98
99 sprintf(init_utsname()->machine, "puv3");
100 sprintf(elf_platform, "ucv2");
101}
102
103/*
104 * cpu_init - initialise one CPU.
105 *
106 * cpu_init sets up the per-CPU stacks.
107 */
108void cpu_init(void)
109{
110 unsigned int cpu = smp_processor_id();
111 struct stack *stk = &stacks[cpu];
112
113 /*
114 * setup stacks for re-entrant exception handlers
115 */
116 __asm__ (
117 "mov.a asr, %1\n\t"
118 "add sp, %0, %2\n\t"
119 "mov.a asr, %3\n\t"
120 "add sp, %0, %4\n\t"
121 "mov.a asr, %5\n\t"
122 "add sp, %0, %6\n\t"
123 "mov.a asr, %7"
124 :
125 : "r" (stk),
126 "r" (PSR_R_BIT | PSR_I_BIT | INTR_MODE),
127 "I" (offsetof(struct stack, irq[0])),
128 "r" (PSR_R_BIT | PSR_I_BIT | ABRT_MODE),
129 "I" (offsetof(struct stack, abt[0])),
130 "r" (PSR_R_BIT | PSR_I_BIT | EXTN_MODE),
131 "I" (offsetof(struct stack, und[0])),
132 "r" (PSR_R_BIT | PSR_I_BIT | PRIV_MODE)
133 : "r30", "cc");
134}
135
136static int __init uc32_add_memory(unsigned long start, unsigned long size)
137{
138 struct membank *bank = &meminfo.bank[meminfo.nr_banks];
139
140 if (meminfo.nr_banks >= NR_BANKS) {
141 printk(KERN_CRIT "NR_BANKS too low, "
142 "ignoring memory at %#lx\n", start);
143 return -EINVAL;
144 }
145
146 /*
147 * Ensure that start/size are aligned to a page boundary.
148 * Size is appropriately rounded down, start is rounded up.
149 */
150 size -= start & ~PAGE_MASK;
151
152 bank->start = PAGE_ALIGN(start);
153 bank->size = size & PAGE_MASK;
154
155 /*
156 * Check whether this memory region has non-zero size or
157 * invalid node number.
158 */
159 if (bank->size == 0)
160 return -EINVAL;
161
162 meminfo.nr_banks++;
163 return 0;
164}
165
166/*
167 * Pick out the memory size. We look for mem=size@start,
168 * where start and size are "size[KkMm]"
169 */
170static int __init early_mem(char *p)
171{
172 static int usermem __initdata = 1;
173 unsigned long size, start;
174 char *endp;
175
176 /*
177 * If the user specifies memory size, we
178 * blow away any automatically generated
179 * size.
180 */
181 if (usermem) {
182 usermem = 0;
183 meminfo.nr_banks = 0;
184 }
185
186 start = PHYS_OFFSET;
187 size = memparse(p, &endp);
188 if (*endp == '@')
189 start = memparse(endp + 1, NULL);
190
191 uc32_add_memory(start, size);
192
193 return 0;
194}
195early_param("mem", early_mem);
196
197static void __init
198request_standard_resources(struct meminfo *mi)
199{
200 struct resource *res;
201 int i;
202
203 kernel_code.start = virt_to_phys(_stext);
204 kernel_code.end = virt_to_phys(_etext - 1);
205 kernel_data.start = virt_to_phys(_sdata);
206 kernel_data.end = virt_to_phys(_end - 1);
207
208 for (i = 0; i < mi->nr_banks; i++) {
209 if (mi->bank[i].size == 0)
210 continue;
211
212 res = alloc_bootmem_low(sizeof(*res));
213 res->name = "System RAM";
214 res->start = mi->bank[i].start;
215 res->end = mi->bank[i].start + mi->bank[i].size - 1;
216 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
217
218 request_resource(&iomem_resource, res);
219
220 if (kernel_code.start >= res->start &&
221 kernel_code.end <= res->end)
222 request_resource(res, &kernel_code);
223 if (kernel_data.start >= res->start &&
224 kernel_data.end <= res->end)
225 request_resource(res, &kernel_data);
226 }
227
228 video_ram.start = PKUNITY_UNIGFX_MMAP_BASE;
229 video_ram.end = PKUNITY_UNIGFX_MMAP_BASE + PKUNITY_UNIGFX_MMAP_SIZE;
230 request_resource(&iomem_resource, &video_ram);
231}
232
233static void (*init_machine)(void) __initdata;
234
235static int __init customize_machine(void)
236{
237 /* customizes platform devices, or adds new ones */
238 if (init_machine)
239 init_machine();
240 return 0;
241}
242arch_initcall(customize_machine);
243
244void __init setup_arch(char **cmdline_p)
245{
246 char *from = default_command_line;
247
248 setup_processor();
249
250 init_mm.start_code = (unsigned long) _stext;
251 init_mm.end_code = (unsigned long) _etext;
252 init_mm.end_data = (unsigned long) _edata;
253 init_mm.brk = (unsigned long) _end;
254
255 /* parse_early_param needs a boot_command_line */
256 strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
257
258 /* populate cmd_line too for later use, preserving boot_command_line */
259 strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
260 *cmdline_p = cmd_line;
261
262 parse_early_param();
263
264 uc32_memblock_init(&meminfo);
265
266 paging_init();
267 request_standard_resources(&meminfo);
268
269 cpu_init();
270
271 /*
272 * Set up various architecture-specific pointers
273 */
274 init_machine = puv3_core_init;
275
276#ifdef CONFIG_VT
277#if defined(CONFIG_VGA_CONSOLE)
278 conswitchp = &vga_con;
279#elif defined(CONFIG_DUMMY_CONSOLE)
280 conswitchp = &dummy_con;
281#endif
282#endif
283 early_trap_init();
284}
285
286static struct cpu cpuinfo_unicore;
287
288static int __init topology_init(void)
289{
290 int i;
291
292 for_each_possible_cpu(i)
293 register_cpu(&cpuinfo_unicore, i);
294
295 return 0;
296}
297subsys_initcall(topology_init);
298
299#ifdef CONFIG_HAVE_PROC_CPU
300static int __init proc_cpu_init(void)
301{
302 struct proc_dir_entry *res;
303
304 res = proc_mkdir("cpu", NULL);
305 if (!res)
306 return -ENOMEM;
307 return 0;
308}
309fs_initcall(proc_cpu_init);
310#endif
311
312static int c_show(struct seq_file *m, void *v)
313{
314 seq_printf(m, "Processor\t: UniCore-II rev %d (%s)\n",
315 (int)(uc32_cpuid >> 16) & 15, elf_platform);
316
317 seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
318 loops_per_jiffy / (500000/HZ),
319 (loops_per_jiffy / (5000/HZ)) % 100);
320
321 /* dump out the processor features */
322 seq_puts(m, "Features\t: CMOV UC-F64");
323
324 seq_printf(m, "\nCPU implementer\t: 0x%02x\n", uc32_cpuid >> 24);
325 seq_printf(m, "CPU architecture: 2\n");
326 seq_printf(m, "CPU revision\t: %d\n", (uc32_cpuid >> 16) & 15);
327
328 seq_printf(m, "Cache type\t: write-back\n"
329 "Cache clean\t: cp0 c5 ops\n"
330 "Cache lockdown\t: not support\n"
331 "Cache format\t: Harvard\n");
332
333 seq_puts(m, "\n");
334
335 seq_printf(m, "Hardware\t: PKUnity v3\n");
336
337 return 0;
338}
339
340static void *c_start(struct seq_file *m, loff_t *pos)
341{
342 return *pos < 1 ? (void *)1 : NULL;
343}
344
345static void *c_next(struct seq_file *m, void *v, loff_t *pos)
346{
347 ++*pos;
348 return NULL;
349}
350
351static void c_stop(struct seq_file *m, void *v)
352{
353}
354
355const struct seq_operations cpuinfo_op = {
356 .start = c_start,
357 .next = c_next,
358 .stop = c_stop,
359 .show = c_show
360};
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
new file mode 100644
index 00000000000..dcd1306eb5c
--- /dev/null
+++ b/arch/unicore32/kernel/setup.h
@@ -0,0 +1,30 @@
1/*
2 * linux/arch/unicore32/kernel/setup.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __UNICORE_KERNEL_SETUP_H__
13#define __UNICORE_KERNEL_SETUP_H__
14
15extern void paging_init(void);
16extern void puv3_core_init(void);
17
18extern void puv3_ps2_init(void);
19extern void pci_puv3_preinit(void);
20extern void __init puv3_init_gpio(void);
21
22extern void setup_mm_for_reboot(char mode);
23
24extern char __stubs_start[], __stubs_end[];
25extern char __vectors_start[], __vectors_end[];
26
27extern void kernel_thread_helper(void);
28
29extern void __init early_signal_init(void);
30#endif
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
new file mode 100644
index 00000000000..b163fca5678
--- /dev/null
+++ b/arch/unicore32/kernel/signal.c
@@ -0,0 +1,494 @@
1/*
2 * linux/arch/unicore32/kernel/signal.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/errno.h>
13#include <linux/signal.h>
14#include <linux/personality.h>
15#include <linux/freezer.h>
16#include <linux/uaccess.h>
17#include <linux/tracehook.h>
18#include <linux/elf.h>
19#include <linux/unistd.h>
20
21#include <asm/cacheflush.h>
22#include <asm/ucontext.h>
23
24#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
25
26/*
27 * For UniCore syscalls, we encode the syscall number into the instruction.
28 */
29#define SWI_SYS_SIGRETURN (0xff000000) /* error number for new abi */
30#define SWI_SYS_RT_SIGRETURN (0xff000000 | (__NR_rt_sigreturn))
31#define SWI_SYS_RESTART (0xff000000 | (__NR_restart_syscall))
32
33#define KERN_SIGRETURN_CODE (KUSER_VECPAGE_BASE + 0x00000500)
34#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(sigreturn_codes))
35
36const unsigned long sigreturn_codes[3] = {
37 SWI_SYS_SIGRETURN, SWI_SYS_RT_SIGRETURN,
38};
39
40const unsigned long syscall_restart_code[2] = {
41 SWI_SYS_RESTART, /* swi __NR_restart_syscall */
42 0x69efc004, /* ldr pc, [sp], #4 */
43};
44
45/*
46 * Do a signal return; undo the signal stack. These are aligned to 64-bit.
47 */
48struct sigframe {
49 struct ucontext uc;
50 unsigned long retcode[2];
51};
52
53struct rt_sigframe {
54 struct siginfo info;
55 struct sigframe sig;
56};
57
58static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
59{
60 sigset_t set;
61 int err;
62
63 err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
64 if (err == 0) {
65 sigdelsetmask(&set, ~_BLOCKABLE);
66 spin_lock_irq(&current->sighand->siglock);
67 current->blocked = set;
68 recalc_sigpending();
69 spin_unlock_irq(&current->sighand->siglock);
70 }
71
72 err |= __get_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00);
73 err |= __get_user(regs->UCreg_01, &sf->uc.uc_mcontext.regs.UCreg_01);
74 err |= __get_user(regs->UCreg_02, &sf->uc.uc_mcontext.regs.UCreg_02);
75 err |= __get_user(regs->UCreg_03, &sf->uc.uc_mcontext.regs.UCreg_03);
76 err |= __get_user(regs->UCreg_04, &sf->uc.uc_mcontext.regs.UCreg_04);
77 err |= __get_user(regs->UCreg_05, &sf->uc.uc_mcontext.regs.UCreg_05);
78 err |= __get_user(regs->UCreg_06, &sf->uc.uc_mcontext.regs.UCreg_06);
79 err |= __get_user(regs->UCreg_07, &sf->uc.uc_mcontext.regs.UCreg_07);
80 err |= __get_user(regs->UCreg_08, &sf->uc.uc_mcontext.regs.UCreg_08);
81 err |= __get_user(regs->UCreg_09, &sf->uc.uc_mcontext.regs.UCreg_09);
82 err |= __get_user(regs->UCreg_10, &sf->uc.uc_mcontext.regs.UCreg_10);
83 err |= __get_user(regs->UCreg_11, &sf->uc.uc_mcontext.regs.UCreg_11);
84 err |= __get_user(regs->UCreg_12, &sf->uc.uc_mcontext.regs.UCreg_12);
85 err |= __get_user(regs->UCreg_13, &sf->uc.uc_mcontext.regs.UCreg_13);
86 err |= __get_user(regs->UCreg_14, &sf->uc.uc_mcontext.regs.UCreg_14);
87 err |= __get_user(regs->UCreg_15, &sf->uc.uc_mcontext.regs.UCreg_15);
88 err |= __get_user(regs->UCreg_16, &sf->uc.uc_mcontext.regs.UCreg_16);
89 err |= __get_user(regs->UCreg_17, &sf->uc.uc_mcontext.regs.UCreg_17);
90 err |= __get_user(regs->UCreg_18, &sf->uc.uc_mcontext.regs.UCreg_18);
91 err |= __get_user(regs->UCreg_19, &sf->uc.uc_mcontext.regs.UCreg_19);
92 err |= __get_user(regs->UCreg_20, &sf->uc.uc_mcontext.regs.UCreg_20);
93 err |= __get_user(regs->UCreg_21, &sf->uc.uc_mcontext.regs.UCreg_21);
94 err |= __get_user(regs->UCreg_22, &sf->uc.uc_mcontext.regs.UCreg_22);
95 err |= __get_user(regs->UCreg_23, &sf->uc.uc_mcontext.regs.UCreg_23);
96 err |= __get_user(regs->UCreg_24, &sf->uc.uc_mcontext.regs.UCreg_24);
97 err |= __get_user(regs->UCreg_25, &sf->uc.uc_mcontext.regs.UCreg_25);
98 err |= __get_user(regs->UCreg_26, &sf->uc.uc_mcontext.regs.UCreg_26);
99 err |= __get_user(regs->UCreg_fp, &sf->uc.uc_mcontext.regs.UCreg_fp);
100 err |= __get_user(regs->UCreg_ip, &sf->uc.uc_mcontext.regs.UCreg_ip);
101 err |= __get_user(regs->UCreg_sp, &sf->uc.uc_mcontext.regs.UCreg_sp);
102 err |= __get_user(regs->UCreg_lr, &sf->uc.uc_mcontext.regs.UCreg_lr);
103 err |= __get_user(regs->UCreg_pc, &sf->uc.uc_mcontext.regs.UCreg_pc);
104 err |= __get_user(regs->UCreg_asr, &sf->uc.uc_mcontext.regs.UCreg_asr);
105
106 err |= !valid_user_regs(regs);
107
108 return err;
109}
110
111asmlinkage int __sys_rt_sigreturn(struct pt_regs *regs)
112{
113 struct rt_sigframe __user *frame;
114
115 /* Always make any pending restarted system calls return -EINTR */
116 current_thread_info()->restart_block.fn = do_no_restart_syscall;
117
118 /*
119 * Since we stacked the signal on a 64-bit boundary,
120 * then 'sp' should be word aligned here. If it's
121 * not, then the user is trying to mess with us.
122 */
123 if (regs->UCreg_sp & 7)
124 goto badframe;
125
126 frame = (struct rt_sigframe __user *)regs->UCreg_sp;
127
128 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
129 goto badframe;
130
131 if (restore_sigframe(regs, &frame->sig))
132 goto badframe;
133
134 if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->UCreg_sp)
135 == -EFAULT)
136 goto badframe;
137
138 return regs->UCreg_00;
139
140badframe:
141 force_sig(SIGSEGV, current);
142 return 0;
143}
144
145static int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs,
146 sigset_t *set)
147{
148 int err = 0;
149
150 err |= __put_user(regs->UCreg_00, &sf->uc.uc_mcontext.regs.UCreg_00);
151 err |= __put_user(regs->UCreg_01, &sf->uc.uc_mcontext.regs.UCreg_01);
152 err |= __put_user(regs->UCreg_02, &sf->uc.uc_mcontext.regs.UCreg_02);
153 err |= __put_user(regs->UCreg_03, &sf->uc.uc_mcontext.regs.UCreg_03);
154 err |= __put_user(regs->UCreg_04, &sf->uc.uc_mcontext.regs.UCreg_04);
155 err |= __put_user(regs->UCreg_05, &sf->uc.uc_mcontext.regs.UCreg_05);
156 err |= __put_user(regs->UCreg_06, &sf->uc.uc_mcontext.regs.UCreg_06);
157 err |= __put_user(regs->UCreg_07, &sf->uc.uc_mcontext.regs.UCreg_07);
158 err |= __put_user(regs->UCreg_08, &sf->uc.uc_mcontext.regs.UCreg_08);
159 err |= __put_user(regs->UCreg_09, &sf->uc.uc_mcontext.regs.UCreg_09);
160 err |= __put_user(regs->UCreg_10, &sf->uc.uc_mcontext.regs.UCreg_10);
161 err |= __put_user(regs->UCreg_11, &sf->uc.uc_mcontext.regs.UCreg_11);
162 err |= __put_user(regs->UCreg_12, &sf->uc.uc_mcontext.regs.UCreg_12);
163 err |= __put_user(regs->UCreg_13, &sf->uc.uc_mcontext.regs.UCreg_13);
164 err |= __put_user(regs->UCreg_14, &sf->uc.uc_mcontext.regs.UCreg_14);
165 err |= __put_user(regs->UCreg_15, &sf->uc.uc_mcontext.regs.UCreg_15);
166 err |= __put_user(regs->UCreg_16, &sf->uc.uc_mcontext.regs.UCreg_16);
167 err |= __put_user(regs->UCreg_17, &sf->uc.uc_mcontext.regs.UCreg_17);
168 err |= __put_user(regs->UCreg_18, &sf->uc.uc_mcontext.regs.UCreg_18);
169 err |= __put_user(regs->UCreg_19, &sf->uc.uc_mcontext.regs.UCreg_19);
170 err |= __put_user(regs->UCreg_20, &sf->uc.uc_mcontext.regs.UCreg_20);
171 err |= __put_user(regs->UCreg_21, &sf->uc.uc_mcontext.regs.UCreg_21);
172 err |= __put_user(regs->UCreg_22, &sf->uc.uc_mcontext.regs.UCreg_22);
173 err |= __put_user(regs->UCreg_23, &sf->uc.uc_mcontext.regs.UCreg_23);
174 err |= __put_user(regs->UCreg_24, &sf->uc.uc_mcontext.regs.UCreg_24);
175 err |= __put_user(regs->UCreg_25, &sf->uc.uc_mcontext.regs.UCreg_25);
176 err |= __put_user(regs->UCreg_26, &sf->uc.uc_mcontext.regs.UCreg_26);
177 err |= __put_user(regs->UCreg_fp, &sf->uc.uc_mcontext.regs.UCreg_fp);
178 err |= __put_user(regs->UCreg_ip, &sf->uc.uc_mcontext.regs.UCreg_ip);
179 err |= __put_user(regs->UCreg_sp, &sf->uc.uc_mcontext.regs.UCreg_sp);
180 err |= __put_user(regs->UCreg_lr, &sf->uc.uc_mcontext.regs.UCreg_lr);
181 err |= __put_user(regs->UCreg_pc, &sf->uc.uc_mcontext.regs.UCreg_pc);
182 err |= __put_user(regs->UCreg_asr, &sf->uc.uc_mcontext.regs.UCreg_asr);
183
184 err |= __put_user(current->thread.trap_no,
185 &sf->uc.uc_mcontext.trap_no);
186 err |= __put_user(current->thread.error_code,
187 &sf->uc.uc_mcontext.error_code);
188 err |= __put_user(current->thread.address,
189 &sf->uc.uc_mcontext.fault_address);
190 err |= __put_user(set->sig[0], &sf->uc.uc_mcontext.oldmask);
191
192 err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
193
194 return err;
195}
196
197static inline void __user *get_sigframe(struct k_sigaction *ka,
198 struct pt_regs *regs, int framesize)
199{
200 unsigned long sp = regs->UCreg_sp;
201 void __user *frame;
202
203 /*
204 * This is the X/Open sanctioned signal stack switching.
205 */
206 if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
207 sp = current->sas_ss_sp + current->sas_ss_size;
208
209 /*
210 * ATPCS B01 mandates 8-byte alignment
211 */
212 frame = (void __user *)((sp - framesize) & ~7);
213
214 /*
215 * Check that we can actually write to the signal frame.
216 */
217 if (!access_ok(VERIFY_WRITE, frame, framesize))
218 frame = NULL;
219
220 return frame;
221}
222
223static int setup_return(struct pt_regs *regs, struct k_sigaction *ka,
224 unsigned long __user *rc, void __user *frame, int usig)
225{
226 unsigned long handler = (unsigned long)ka->sa.sa_handler;
227 unsigned long retcode;
228 unsigned long asr = regs->UCreg_asr & ~PSR_f;
229
230 unsigned int idx = 0;
231
232 if (ka->sa.sa_flags & SA_SIGINFO)
233 idx += 1;
234
235 if (__put_user(sigreturn_codes[idx], rc) ||
236 __put_user(sigreturn_codes[idx+1], rc+1))
237 return 1;
238
239 retcode = KERN_SIGRETURN_CODE + (idx << 2);
240
241 regs->UCreg_00 = usig;
242 regs->UCreg_sp = (unsigned long)frame;
243 regs->UCreg_lr = retcode;
244 regs->UCreg_pc = handler;
245 regs->UCreg_asr = asr;
246
247 return 0;
248}
249
250static int setup_frame(int usig, struct k_sigaction *ka,
251 sigset_t *set, struct pt_regs *regs)
252{
253 struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
254 int err = 0;
255
256 if (!frame)
257 return 1;
258
259 /*
260 * Set uc.uc_flags to a value which sc.trap_no would never have.
261 */
262 err |= __put_user(0x5ac3c35a, &frame->uc.uc_flags);
263
264 err |= setup_sigframe(frame, regs, set);
265 if (err == 0)
266 err |= setup_return(regs, ka, frame->retcode, frame, usig);
267
268 return err;
269}
270
271static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
272 sigset_t *set, struct pt_regs *regs)
273{
274 struct rt_sigframe __user *frame =
275 get_sigframe(ka, regs, sizeof(*frame));
276 stack_t stack;
277 int err = 0;
278
279 if (!frame)
280 return 1;
281
282 err |= copy_siginfo_to_user(&frame->info, info);
283
284 err |= __put_user(0, &frame->sig.uc.uc_flags);
285 err |= __put_user(NULL, &frame->sig.uc.uc_link);
286
287 memset(&stack, 0, sizeof(stack));
288 stack.ss_sp = (void __user *)current->sas_ss_sp;
289 stack.ss_flags = sas_ss_flags(regs->UCreg_sp);
290 stack.ss_size = current->sas_ss_size;
291 err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
292
293 err |= setup_sigframe(&frame->sig, regs, set);
294 if (err == 0)
295 err |= setup_return(regs, ka, frame->sig.retcode, frame, usig);
296
297 if (err == 0) {
298 /*
299 * For realtime signals we must also set the second and third
300 * arguments for the signal handler.
301 */
302 regs->UCreg_01 = (unsigned long)&frame->info;
303 regs->UCreg_02 = (unsigned long)&frame->sig.uc;
304 }
305
306 return err;
307}
308
309static inline void setup_syscall_restart(struct pt_regs *regs)
310{
311 regs->UCreg_00 = regs->UCreg_ORIG_00;
312 regs->UCreg_pc -= 4;
313}
314
315/*
316 * OK, we're invoking a handler
317 */
318static int handle_signal(unsigned long sig, struct k_sigaction *ka,
319 siginfo_t *info, sigset_t *oldset,
320 struct pt_regs *regs, int syscall)
321{
322 struct thread_info *thread = current_thread_info();
323 struct task_struct *tsk = current;
324 int usig = sig;
325 int ret;
326
327 /*
328 * If we were from a system call, check for system call restarting...
329 */
330 if (syscall) {
331 switch (regs->UCreg_00) {
332 case -ERESTART_RESTARTBLOCK:
333 case -ERESTARTNOHAND:
334 regs->UCreg_00 = -EINTR;
335 break;
336 case -ERESTARTSYS:
337 if (!(ka->sa.sa_flags & SA_RESTART)) {
338 regs->UCreg_00 = -EINTR;
339 break;
340 }
341 /* fallthrough */
342 case -ERESTARTNOINTR:
343 setup_syscall_restart(regs);
344 }
345 }
346
347 /*
348 * translate the signal
349 */
350 if (usig < 32 && thread->exec_domain
351 && thread->exec_domain->signal_invmap)
352 usig = thread->exec_domain->signal_invmap[usig];
353
354 /*
355 * Set up the stack frame
356 */
357 if (ka->sa.sa_flags & SA_SIGINFO)
358 ret = setup_rt_frame(usig, ka, info, oldset, regs);
359 else
360 ret = setup_frame(usig, ka, oldset, regs);
361
362 /*
363 * Check that the resulting registers are actually sane.
364 */
365 ret |= !valid_user_regs(regs);
366
367 if (ret != 0) {
368 force_sigsegv(sig, tsk);
369 return ret;
370 }
371
372 /*
373 * Block the signal if we were successful.
374 */
375 spin_lock_irq(&tsk->sighand->siglock);
376 sigorsets(&tsk->blocked, &tsk->blocked,
377 &ka->sa.sa_mask);
378 if (!(ka->sa.sa_flags & SA_NODEFER))
379 sigaddset(&tsk->blocked, sig);
380 recalc_sigpending();
381 spin_unlock_irq(&tsk->sighand->siglock);
382
383 return 0;
384}
385
386/*
387 * Note that 'init' is a special process: it doesn't get signals it doesn't
388 * want to handle. Thus you cannot kill init even with a SIGKILL even by
389 * mistake.
390 *
391 * Note that we go through the signals twice: once to check the signals that
392 * the kernel can handle, and then we build all the user-level signal handling
393 * stack-frames in one go after that.
394 */
395static void do_signal(struct pt_regs *regs, int syscall)
396{
397 struct k_sigaction ka;
398 siginfo_t info;
399 int signr;
400
401 /*
402 * We want the common case to go fast, which
403 * is why we may in certain cases get here from
404 * kernel mode. Just return without doing anything
405 * if so.
406 */
407 if (!user_mode(regs))
408 return;
409
410 if (try_to_freeze())
411 goto no_signal;
412
413 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
414 if (signr > 0) {
415 sigset_t *oldset;
416
417 if (test_thread_flag(TIF_RESTORE_SIGMASK))
418 oldset = &current->saved_sigmask;
419 else
420 oldset = &current->blocked;
421 if (handle_signal(signr, &ka, &info, oldset, regs, syscall)
422 == 0) {
423 /*
424 * A signal was successfully delivered; the saved
425 * sigmask will have been stored in the signal frame,
426 * and will be restored by sigreturn, so we can simply
427 * clear the TIF_RESTORE_SIGMASK flag.
428 */
429 if (test_thread_flag(TIF_RESTORE_SIGMASK))
430 clear_thread_flag(TIF_RESTORE_SIGMASK);
431 }
432 return;
433 }
434
435 no_signal:
436 /*
437 * No signal to deliver to the process - restart the syscall.
438 */
439 if (syscall) {
440 if (regs->UCreg_00 == -ERESTART_RESTARTBLOCK) {
441 u32 __user *usp;
442
443 regs->UCreg_sp -= 4;
444 usp = (u32 __user *)regs->UCreg_sp;
445
446 if (put_user(regs->UCreg_pc, usp) == 0) {
447 regs->UCreg_pc = KERN_RESTART_CODE;
448 } else {
449 regs->UCreg_sp += 4;
450 force_sigsegv(0, current);
451 }
452 }
453 if (regs->UCreg_00 == -ERESTARTNOHAND ||
454 regs->UCreg_00 == -ERESTARTSYS ||
455 regs->UCreg_00 == -ERESTARTNOINTR) {
456 setup_syscall_restart(regs);
457 }
458
459 /* If there's no signal to deliver, we just put the saved
460 * sigmask back.
461 */
462 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
463 clear_thread_flag(TIF_RESTORE_SIGMASK);
464 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
465 }
466 }
467}
468
469asmlinkage void do_notify_resume(struct pt_regs *regs,
470 unsigned int thread_flags, int syscall)
471{
472 if (thread_flags & _TIF_SIGPENDING)
473 do_signal(regs, syscall);
474
475 if (thread_flags & _TIF_NOTIFY_RESUME) {
476 clear_thread_flag(TIF_NOTIFY_RESUME);
477 tracehook_notify_resume(regs);
478 if (current->replacement_session_keyring)
479 key_replace_session_keyring();
480 }
481}
482
483/*
484 * Copy signal return handlers into the vector page, and
485 * set sigreturn to be a pointer to these.
486 */
487void __init early_signal_init(void)
488{
489 memcpy((void *)kuser_vecpage_to_vectors(KERN_SIGRETURN_CODE),
490 sigreturn_codes, sizeof(sigreturn_codes));
491 memcpy((void *)kuser_vecpage_to_vectors(KERN_RESTART_CODE),
492 syscall_restart_code, sizeof(syscall_restart_code));
493 /* Need not to flush icache, since early_trap_init will do it last. */
494}
diff --git a/arch/unicore32/kernel/sleep.S b/arch/unicore32/kernel/sleep.S
new file mode 100644
index 00000000000..607a104aec5
--- /dev/null
+++ b/arch/unicore32/kernel/sleep.S
@@ -0,0 +1,202 @@
1/*
2 * linux/arch/unicore32/kernel/sleep.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/linkage.h>
15#include <asm/assembler.h>
16#include <mach/hardware.h>
17
18 .text
19
20pkunity_cpu_save_cp:
21
22 @ get coprocessor registers
23
24 movc r3, p0.c7, #0 @ PID
25 movc r4, p0.c2, #0 @ translation table base addr
26 movc r5, p0.c1, #0 @ control reg
27
28
29 @ store them plus current virtual stack ptr on stack
30 mov r6, sp
31 stm.w (r3 - r6), [sp-]
32
33 mov pc, lr
34
35pkunity_cpu_save_sp:
36 @ preserve phys address of stack
37 mov r0, sp
38 stw.w lr, [sp+], #-4
39 b.l sleep_phys_sp
40 ldw r1, =sleep_save_sp
41 stw r0, [r1]
42 ldw.w pc, [sp]+, #4
43
44/*
45 * puv3_cpu_suspend()
46 *
47 * Forces CPU into sleep state.
48 *
49 * r0 = value for PWRMODE M field for desired sleep state
50 */
51
52ENTRY(puv3_cpu_suspend)
53 stm.w (r16 - r27, lr), [sp-] @ save registers on stack
54 stm.w (r4 - r15), [sp-] @ save registers on stack
55
56#ifdef CONFIG_UNICORE_FPU_F64
57 sfm.w (f0 - f7 ), [sp-]
58 sfm.w (f8 - f15), [sp-]
59 sfm.w (f16 - f23), [sp-]
60 sfm.w (f24 - f31), [sp-]
61 cff r4, s31
62 stm.w (r4), [sp-]
63#endif
64 b.l pkunity_cpu_save_cp
65
66 b.l pkunity_cpu_save_sp
67
68 @ clean data cache
69 mov r1, #0
70 movc p0.c5, r1, #14
71 nop
72 nop
73 nop
74 nop
75
76
77
78 @ DDR2 BaseAddr
79 ldw r0, =(PKUNITY_DDR2CTRL_BASE)
80
81 @ PM BaseAddr
82 ldw r1, =(PKUNITY_PM_BASE)
83
84 @ set PLL_SYS_CFG reg, 275
85 movl r6, #0x00002401
86 stw r6, [r1+], #0x18
87 @ set PLL_DDR_CFG reg, 66MHz
88 movl r6, #0x00100c00
89 stw r6, [r1+], #0x1c
90
91 @ set wake up source
92 movl r8, #0x800001ff @ epip4d
93 stw r8, [r1+], #0xc
94
95 @ set PGSR
96 movl r5, #0x40000
97 stw r5, [r1+], #0x10
98
99 @ prepare DDR2 refresh settings
100 ldw r5, [r0+], #0x24
101 or r5, r5, #0x00000001
102
103 @ prepare PMCR for PLL changing
104 movl r6, #0xc
105
106 @ prepare for closing PLL
107 movl r7, #0x1
108
109 @ prepare sleep mode
110 mov r8, #0x1
111
112@ movl r0, 0x11111111
113@ put_word_ocd r0
114 b pkunity_cpu_do_suspend
115
116 .ltorg
117 .align 5
118pkunity_cpu_do_suspend:
119 b 101f
120 @ put DDR2 into self-refresh
121100: stw r5, [r0+], #0x24
122 @ change PLL
123 stw r6, [r1]
124 b 1f
125
126 .ltorg
127 .align 5
128101: b 102f
129 @ wait for PLL changing complete
1301: ldw r6, [r1+], #0x44
131 csub.a r6, #0x1
132 bne 1b
133 b 2f
134
135 .ltorg
136 .align 5
137102: b 100b
138 @ close PLL
1392: stw r7, [r1+], #0x4
140 @ enter sleep mode
141 stw r8, [r1]
1423: b 3b
143
144
145
146
147/*
148 * puv3_cpu_resume()
149 *
150 * entry point from bootloader into kernel during resume
151 *
152 * Note: Yes, part of the following code is located into the .data section.
153 * This is to allow sleep_save_sp to be accessed with a relative load
154 * while we can't rely on any MMU translation. We could have put
155 * sleep_save_sp in the .text section as well, but some setups might
156 * insist on it to be truly read-only.
157 */
158
159 .data
160 .align 5
161ENTRY(puv3_cpu_resume)
162@ movl r0, 0x20202020
163@ put_word_ocd r0
164
165 ldw r0, sleep_save_sp @ stack phys addr
166 ldw r2, =resume_after_mmu @ its absolute virtual address
167 ldm (r3 - r6), [r0]+ @ CP regs + virt stack ptr
168 mov sp, r6 @ CP regs + virt stack ptr
169
170 mov r1, #0
171 movc p0.c6, r1, #6 @ invalidate I & D TLBs
172 movc p0.c5, r1, #28 @ invalidate I & D caches, BTB
173
174 movc p0.c7, r3, #0 @ PID
175 movc p0.c2, r4, #0 @ translation table base addr
176 movc p0.c1, r5, #0 @ control reg, turn on mmu
177 nop
178 jump r2
179 nop
180 nop
181 nop
182 nop
183 nop
184
185sleep_save_sp:
186 .word 0 @ preserve stack phys ptr here
187
188 .text
189resume_after_mmu:
190@ movl r0, 0x30303030
191@ put_word_ocd r0
192
193#ifdef CONFIG_UNICORE_FPU_F64
194 lfm.w (f0 - f7 ), [sp]+
195 lfm.w (f8 - f15), [sp]+
196 lfm.w (f16 - f23), [sp]+
197 lfm.w (f24 - f31), [sp]+
198 ldm.w (r4), [sp]+
199 ctf r4, s31
200#endif
201 ldm.w (r4 - r15), [sp]+ @ restore registers from stack
202 ldm.w (r16 - r27, pc), [sp]+ @ return to caller
diff --git a/arch/unicore32/kernel/stacktrace.c b/arch/unicore32/kernel/stacktrace.c
new file mode 100644
index 00000000000..b34030bdabe
--- /dev/null
+++ b/arch/unicore32/kernel/stacktrace.c
@@ -0,0 +1,131 @@
1/*
2 * linux/arch/unicore32/kernel/stacktrace.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/stacktrace.h>
15
16#include <asm/stacktrace.h>
17
18#if defined(CONFIG_FRAME_POINTER)
19/*
20 * Unwind the current stack frame and store the new register values in the
21 * structure passed as argument. Unwinding is equivalent to a function return,
22 * hence the new PC value rather than LR should be used for backtrace.
23 *
24 * With framepointer enabled, a simple function prologue looks like this:
25 * mov ip, sp
26 * stmdb sp!, {fp, ip, lr, pc}
27 * sub fp, ip, #4
28 *
29 * A simple function epilogue looks like this:
30 * ldm sp, {fp, sp, pc}
31 *
32 * Note that with framepointer enabled, even the leaf functions have the same
33 * prologue and epilogue, therefore we can ignore the LR value in this case.
34 */
35int notrace unwind_frame(struct stackframe *frame)
36{
37 unsigned long high, low;
38 unsigned long fp = frame->fp;
39
40 /* only go to a higher address on the stack */
41 low = frame->sp;
42 high = ALIGN(low, THREAD_SIZE);
43
44 /* check current frame pointer is within bounds */
45 if (fp < (low + 12) || fp + 4 >= high)
46 return -EINVAL;
47
48 /* restore the registers from the stack frame */
49 frame->fp = *(unsigned long *)(fp - 12);
50 frame->sp = *(unsigned long *)(fp - 8);
51 frame->pc = *(unsigned long *)(fp - 4);
52
53 return 0;
54}
55#endif
56
57void notrace walk_stackframe(struct stackframe *frame,
58 int (*fn)(struct stackframe *, void *), void *data)
59{
60 while (1) {
61 int ret;
62
63 if (fn(frame, data))
64 break;
65 ret = unwind_frame(frame);
66 if (ret < 0)
67 break;
68 }
69}
70EXPORT_SYMBOL(walk_stackframe);
71
72#ifdef CONFIG_STACKTRACE
73struct stack_trace_data {
74 struct stack_trace *trace;
75 unsigned int no_sched_functions;
76 unsigned int skip;
77};
78
79static int save_trace(struct stackframe *frame, void *d)
80{
81 struct stack_trace_data *data = d;
82 struct stack_trace *trace = data->trace;
83 unsigned long addr = frame->pc;
84
85 if (data->no_sched_functions && in_sched_functions(addr))
86 return 0;
87 if (data->skip) {
88 data->skip--;
89 return 0;
90 }
91
92 trace->entries[trace->nr_entries++] = addr;
93
94 return trace->nr_entries >= trace->max_entries;
95}
96
97void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
98{
99 struct stack_trace_data data;
100 struct stackframe frame;
101
102 data.trace = trace;
103 data.skip = trace->skip;
104
105 if (tsk != current) {
106 data.no_sched_functions = 1;
107 frame.fp = thread_saved_fp(tsk);
108 frame.sp = thread_saved_sp(tsk);
109 frame.lr = 0; /* recovered from the stack */
110 frame.pc = thread_saved_pc(tsk);
111 } else {
112 register unsigned long current_sp asm("sp");
113
114 data.no_sched_functions = 0;
115 frame.fp = (unsigned long)__builtin_frame_address(0);
116 frame.sp = current_sp;
117 frame.lr = (unsigned long)__builtin_return_address(0);
118 frame.pc = (unsigned long)save_stack_trace_tsk;
119 }
120
121 walk_stackframe(&frame, save_trace, &data);
122 if (trace->nr_entries < trace->max_entries)
123 trace->entries[trace->nr_entries++] = ULONG_MAX;
124}
125
126void save_stack_trace(struct stack_trace *trace)
127{
128 save_stack_trace_tsk(current, trace);
129}
130EXPORT_SYMBOL_GPL(save_stack_trace);
131#endif
diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c
new file mode 100644
index 00000000000..3afe60a39ac
--- /dev/null
+++ b/arch/unicore32/kernel/sys.c
@@ -0,0 +1,126 @@
1/*
2 * linux/arch/unicore32/kernel/sys.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/slab.h>
16#include <linux/mm.h>
17#include <linux/sem.h>
18#include <linux/msg.h>
19#include <linux/shm.h>
20#include <linux/stat.h>
21#include <linux/syscalls.h>
22#include <linux/mman.h>
23#include <linux/fs.h>
24#include <linux/file.h>
25#include <linux/ipc.h>
26#include <linux/uaccess.h>
27
28#include <asm/syscalls.h>
29#include <asm/cacheflush.h>
30
31/* Clone a task - this clones the calling program thread.
32 * This is called indirectly via a small wrapper
33 */
34asmlinkage long __sys_clone(unsigned long clone_flags, unsigned long newsp,
35 void __user *parent_tid, void __user *child_tid,
36 struct pt_regs *regs)
37{
38 if (!newsp)
39 newsp = regs->UCreg_sp;
40
41 return do_fork(clone_flags, newsp, regs, 0,
42 parent_tid, child_tid);
43}
44
45/* sys_execve() executes a new program.
46 * This is called indirectly via a small wrapper
47 */
48asmlinkage long __sys_execve(const char __user *filename,
49 const char __user *const __user *argv,
50 const char __user *const __user *envp,
51 struct pt_regs *regs)
52{
53 int error;
54 char *fn;
55
56 fn = getname(filename);
57 error = PTR_ERR(fn);
58 if (IS_ERR(fn))
59 goto out;
60 error = do_execve(fn, argv, envp, regs);
61 putname(fn);
62out:
63 return error;
64}
65
66int kernel_execve(const char *filename,
67 const char *const argv[],
68 const char *const envp[])
69{
70 struct pt_regs regs;
71 int ret;
72
73 memset(&regs, 0, sizeof(struct pt_regs));
74 ret = do_execve(filename,
75 (const char __user *const __user *)argv,
76 (const char __user *const __user *)envp, &regs);
77 if (ret < 0)
78 goto out;
79
80 /*
81 * Save argc to the register structure for userspace.
82 */
83 regs.UCreg_00 = ret;
84
85 /*
86 * We were successful. We won't be returning to our caller, but
87 * instead to user space by manipulating the kernel stack.
88 */
89 asm("add r0, %0, %1\n\t"
90 "mov r1, %2\n\t"
91 "mov r2, %3\n\t"
92 "mov r22, #0\n\t" /* not a syscall */
93 "mov r23, %0\n\t" /* thread structure */
94 "b.l memmove\n\t" /* copy regs to top of stack */
95 "mov sp, r0\n\t" /* reposition stack pointer */
96 "b ret_to_user"
97 :
98 : "r" (current_thread_info()),
99 "Ir" (THREAD_START_SP - sizeof(regs)),
100 "r" (&regs),
101 "Ir" (sizeof(regs))
102 : "r0", "r1", "r2", "r3", "ip", "lr", "memory");
103
104 out:
105 return ret;
106}
107EXPORT_SYMBOL(kernel_execve);
108
109/* Note: used by the compat code even in 64-bit Linux. */
110SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
111 unsigned long, prot, unsigned long, flags,
112 unsigned long, fd, unsigned long, off_4k)
113{
114 return sys_mmap_pgoff(addr, len, prot, flags, fd,
115 off_4k);
116}
117
118/* Provide the actual syscall number to call mapping. */
119#undef __SYSCALL
120#define __SYSCALL(nr, call) [nr] = (call),
121
122/* Note that we don't include <linux/unistd.h> but <asm/unistd.h> */
123void *sys_call_table[__NR_syscalls] = {
124 [0 ... __NR_syscalls-1] = sys_ni_syscall,
125#include <asm/unistd.h>
126};
diff --git a/arch/unicore32/kernel/time.c b/arch/unicore32/kernel/time.c
new file mode 100644
index 00000000000..080710c0924
--- /dev/null
+++ b/arch/unicore32/kernel/time.c
@@ -0,0 +1,143 @@
1/*
2 * linux/arch/unicore32/kernel/time.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7 * Copyright (C) 2001-2010 Guan Xuetao
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/init.h>
14#include <linux/errno.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/timex.h>
18#include <linux/clockchips.h>
19
20#include <mach/hardware.h>
21
22#define MIN_OSCR_DELTA 2
23
24static irqreturn_t puv3_ost0_interrupt(int irq, void *dev_id)
25{
26 struct clock_event_device *c = dev_id;
27
28 /* Disarm the compare/match, signal the event. */
29 writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
30 writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
31 c->event_handler(c);
32
33 return IRQ_HANDLED;
34}
35
36static int
37puv3_osmr0_set_next_event(unsigned long delta, struct clock_event_device *c)
38{
39 unsigned long next, oscr;
40
41 writel(readl(OST_OIER) | OST_OIER_E0, OST_OIER);
42 next = readl(OST_OSCR) + delta;
43 writel(next, OST_OSMR0);
44 oscr = readl(OST_OSCR);
45
46 return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
47}
48
49static void
50puv3_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
51{
52 switch (mode) {
53 case CLOCK_EVT_MODE_ONESHOT:
54 case CLOCK_EVT_MODE_UNUSED:
55 case CLOCK_EVT_MODE_SHUTDOWN:
56 writel(readl(OST_OIER) & ~OST_OIER_E0, OST_OIER);
57 writel(readl(OST_OSSR) & ~OST_OSSR_M0, OST_OSSR);
58 break;
59
60 case CLOCK_EVT_MODE_RESUME:
61 case CLOCK_EVT_MODE_PERIODIC:
62 break;
63 }
64}
65
66static struct clock_event_device ckevt_puv3_osmr0 = {
67 .name = "osmr0",
68 .features = CLOCK_EVT_FEAT_ONESHOT,
69 .rating = 200,
70 .set_next_event = puv3_osmr0_set_next_event,
71 .set_mode = puv3_osmr0_set_mode,
72};
73
74static cycle_t puv3_read_oscr(struct clocksource *cs)
75{
76 return readl(OST_OSCR);
77}
78
79static struct clocksource cksrc_puv3_oscr = {
80 .name = "oscr",
81 .rating = 200,
82 .read = puv3_read_oscr,
83 .mask = CLOCKSOURCE_MASK(32),
84 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
85};
86
87static struct irqaction puv3_timer_irq = {
88 .name = "ost0",
89 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
90 .handler = puv3_ost0_interrupt,
91 .dev_id = &ckevt_puv3_osmr0,
92};
93
94void __init time_init(void)
95{
96 writel(0, OST_OIER); /* disable any timer interrupts */
97 writel(0, OST_OSSR); /* clear status on all timers */
98
99 clockevents_calc_mult_shift(&ckevt_puv3_osmr0, CLOCK_TICK_RATE, 5);
100
101 ckevt_puv3_osmr0.max_delta_ns =
102 clockevent_delta2ns(0x7fffffff, &ckevt_puv3_osmr0);
103 ckevt_puv3_osmr0.min_delta_ns =
104 clockevent_delta2ns(MIN_OSCR_DELTA * 2, &ckevt_puv3_osmr0) + 1;
105 ckevt_puv3_osmr0.cpumask = cpumask_of(0);
106
107 setup_irq(IRQ_TIMER0, &puv3_timer_irq);
108
109 clocksource_register_hz(&cksrc_puv3_oscr, CLOCK_TICK_RATE);
110 clockevents_register_device(&ckevt_puv3_osmr0);
111}
112
113#ifdef CONFIG_PM
114unsigned long osmr[4], oier;
115
116void puv3_timer_suspend(void)
117{
118 osmr[0] = readl(OST_OSMR0);
119 osmr[1] = readl(OST_OSMR1);
120 osmr[2] = readl(OST_OSMR2);
121 osmr[3] = readl(OST_OSMR3);
122 oier = readl(OST_OIER);
123}
124
125void puv3_timer_resume(void)
126{
127 writel(0, OST_OSSR);
128 writel(osmr[0], OST_OSMR0);
129 writel(osmr[1], OST_OSMR1);
130 writel(osmr[2], OST_OSMR2);
131 writel(osmr[3], OST_OSMR3);
132 writel(oier, OST_OIER);
133
134 /*
135 * OSMR0 is the system timer: make sure OSCR is sufficiently behind
136 */
137 writel(readl(OST_OSMR0) - LATCH, OST_OSCR);
138}
139#else
140void puv3_timer_suspend(void) { };
141void puv3_timer_resume(void) { };
142#endif
143
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
new file mode 100644
index 00000000000..25abbb10172
--- /dev/null
+++ b/arch/unicore32/kernel/traps.c
@@ -0,0 +1,333 @@
1/*
2 * linux/arch/unicore32/kernel/traps.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * 'traps.c' handles hardware exceptions after we have saved some state.
13 * Mostly a debugging aid, but will probably kill the offending process.
14 */
15#include <linux/module.h>
16#include <linux/signal.h>
17#include <linux/spinlock.h>
18#include <linux/personality.h>
19#include <linux/kallsyms.h>
20#include <linux/kdebug.h>
21#include <linux/uaccess.h>
22#include <linux/delay.h>
23#include <linux/hardirq.h>
24#include <linux/init.h>
25#include <linux/uaccess.h>
26#include <linux/atomic.h>
27#include <linux/unistd.h>
28
29#include <asm/cacheflush.h>
30#include <asm/system.h>
31#include <asm/traps.h>
32
33#include "setup.h"
34
35static void dump_mem(const char *, const char *, unsigned long, unsigned long);
36
37void dump_backtrace_entry(unsigned long where,
38 unsigned long from, unsigned long frame)
39{
40#ifdef CONFIG_KALLSYMS
41 printk(KERN_DEFAULT "[<%08lx>] (%pS) from [<%08lx>] (%pS)\n",
42 where, (void *)where, from, (void *)from);
43#else
44 printk(KERN_DEFAULT "Function entered at [<%08lx>] from [<%08lx>]\n",
45 where, from);
46#endif
47}
48
49/*
50 * Stack pointers should always be within the kernels view of
51 * physical memory. If it is not there, then we can't dump
52 * out any information relating to the stack.
53 */
54static int verify_stack(unsigned long sp)
55{
56 if (sp < PAGE_OFFSET ||
57 (sp > (unsigned long)high_memory && high_memory != NULL))
58 return -EFAULT;
59
60 return 0;
61}
62
63/*
64 * Dump out the contents of some memory nicely...
65 */
66static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
67 unsigned long top)
68{
69 unsigned long first;
70 mm_segment_t fs;
71 int i;
72
73 /*
74 * We need to switch to kernel mode so that we can use __get_user
75 * to safely read from kernel space. Note that we now dump the
76 * code first, just in case the backtrace kills us.
77 */
78 fs = get_fs();
79 set_fs(KERNEL_DS);
80
81 printk(KERN_DEFAULT "%s%s(0x%08lx to 0x%08lx)\n",
82 lvl, str, bottom, top);
83
84 for (first = bottom & ~31; first < top; first += 32) {
85 unsigned long p;
86 char str[sizeof(" 12345678") * 8 + 1];
87
88 memset(str, ' ', sizeof(str));
89 str[sizeof(str) - 1] = '\0';
90
91 for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
92 if (p >= bottom && p < top) {
93 unsigned long val;
94 if (__get_user(val, (unsigned long *)p) == 0)
95 sprintf(str + i * 9, " %08lx", val);
96 else
97 sprintf(str + i * 9, " ????????");
98 }
99 }
100 printk(KERN_DEFAULT "%s%04lx:%s\n", lvl, first & 0xffff, str);
101 }
102
103 set_fs(fs);
104}
105
106static void dump_instr(const char *lvl, struct pt_regs *regs)
107{
108 unsigned long addr = instruction_pointer(regs);
109 const int width = 8;
110 mm_segment_t fs;
111 char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
112 int i;
113
114 /*
115 * We need to switch to kernel mode so that we can use __get_user
116 * to safely read from kernel space. Note that we now dump the
117 * code first, just in case the backtrace kills us.
118 */
119 fs = get_fs();
120 set_fs(KERNEL_DS);
121
122 for (i = -4; i < 1; i++) {
123 unsigned int val, bad;
124
125 bad = __get_user(val, &((u32 *)addr)[i]);
126
127 if (!bad)
128 p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
129 width, val);
130 else {
131 p += sprintf(p, "bad PC value");
132 break;
133 }
134 }
135 printk(KERN_DEFAULT "%sCode: %s\n", lvl, str);
136
137 set_fs(fs);
138}
139
140static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
141{
142 unsigned int fp, mode;
143 int ok = 1;
144
145 printk(KERN_DEFAULT "Backtrace: ");
146
147 if (!tsk)
148 tsk = current;
149
150 if (regs) {
151 fp = regs->UCreg_fp;
152 mode = processor_mode(regs);
153 } else if (tsk != current) {
154 fp = thread_saved_fp(tsk);
155 mode = 0x10;
156 } else {
157 asm("mov %0, fp" : "=r" (fp) : : "cc");
158 mode = 0x10;
159 }
160
161 if (!fp) {
162 printk("no frame pointer");
163 ok = 0;
164 } else if (verify_stack(fp)) {
165 printk("invalid frame pointer 0x%08x", fp);
166 ok = 0;
167 } else if (fp < (unsigned long)end_of_stack(tsk))
168 printk("frame pointer underflow");
169 printk("\n");
170
171 if (ok)
172 c_backtrace(fp, mode);
173}
174
175void dump_stack(void)
176{
177 dump_backtrace(NULL, NULL);
178}
179EXPORT_SYMBOL(dump_stack);
180
181void show_stack(struct task_struct *tsk, unsigned long *sp)
182{
183 dump_backtrace(NULL, tsk);
184 barrier();
185}
186
187static int __die(const char *str, int err, struct thread_info *thread,
188 struct pt_regs *regs)
189{
190 struct task_struct *tsk = thread->task;
191 static int die_counter;
192 int ret;
193
194 printk(KERN_EMERG "Internal error: %s: %x [#%d]\n",
195 str, err, ++die_counter);
196 sysfs_printk_last_file();
197
198 /* trap and error numbers are mostly meaningless on UniCore */
199 ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, \
200 SIGSEGV);
201 if (ret == NOTIFY_STOP)
202 return ret;
203
204 print_modules();
205 __show_regs(regs);
206 printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
207 TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
208
209 if (!user_mode(regs) || in_interrupt()) {
210 dump_mem(KERN_EMERG, "Stack: ", regs->UCreg_sp,
211 THREAD_SIZE + (unsigned long)task_stack_page(tsk));
212 dump_backtrace(regs, tsk);
213 dump_instr(KERN_EMERG, regs);
214 }
215
216 return ret;
217}
218
219DEFINE_SPINLOCK(die_lock);
220
221/*
222 * This function is protected against re-entrancy.
223 */
224void die(const char *str, struct pt_regs *regs, int err)
225{
226 struct thread_info *thread = current_thread_info();
227 int ret;
228
229 oops_enter();
230
231 spin_lock_irq(&die_lock);
232 console_verbose();
233 bust_spinlocks(1);
234 ret = __die(str, err, thread, regs);
235
236 bust_spinlocks(0);
237 add_taint(TAINT_DIE);
238 spin_unlock_irq(&die_lock);
239 oops_exit();
240
241 if (in_interrupt())
242 panic("Fatal exception in interrupt");
243 if (panic_on_oops)
244 panic("Fatal exception");
245 if (ret != NOTIFY_STOP)
246 do_exit(SIGSEGV);
247}
248
249void uc32_notify_die(const char *str, struct pt_regs *regs,
250 struct siginfo *info, unsigned long err, unsigned long trap)
251{
252 if (user_mode(regs)) {
253 current->thread.error_code = err;
254 current->thread.trap_no = trap;
255
256 force_sig_info(info->si_signo, info, current);
257 } else
258 die(str, regs, err);
259}
260
261/*
262 * bad_mode handles the impossible case in the vectors. If you see one of
263 * these, then it's extremely serious, and could mean you have buggy hardware.
264 * It never returns, and never tries to sync. We hope that we can at least
265 * dump out some state information...
266 */
267asmlinkage void bad_mode(struct pt_regs *regs, unsigned int reason)
268{
269 console_verbose();
270
271 printk(KERN_CRIT "Bad mode detected with reason 0x%x\n", reason);
272
273 die("Oops - bad mode", regs, 0);
274 local_irq_disable();
275 panic("bad mode");
276}
277
278void __pte_error(const char *file, int line, unsigned long val)
279{
280 printk(KERN_DEFAULT "%s:%d: bad pte %08lx.\n", file, line, val);
281}
282
283void __pmd_error(const char *file, int line, unsigned long val)
284{
285 printk(KERN_DEFAULT "%s:%d: bad pmd %08lx.\n", file, line, val);
286}
287
288void __pgd_error(const char *file, int line, unsigned long val)
289{
290 printk(KERN_DEFAULT "%s:%d: bad pgd %08lx.\n", file, line, val);
291}
292
293asmlinkage void __div0(void)
294{
295 printk(KERN_DEFAULT "Division by zero in kernel.\n");
296 dump_stack();
297}
298EXPORT_SYMBOL(__div0);
299
300void abort(void)
301{
302 BUG();
303
304 /* if that doesn't kill us, halt */
305 panic("Oops failed to kill thread");
306}
307EXPORT_SYMBOL(abort);
308
309void __init trap_init(void)
310{
311 return;
312}
313
314void __init early_trap_init(void)
315{
316 unsigned long vectors = VECTORS_BASE;
317
318 /*
319 * Copy the vectors, stubs (in entry-unicore.S)
320 * into the vector page, mapped at 0xffff0000, and ensure these
321 * are visible to the instruction stream.
322 */
323 memcpy((void *)vectors,
324 __vectors_start,
325 __vectors_end - __vectors_start);
326 memcpy((void *)vectors + 0x200,
327 __stubs_start,
328 __stubs_end - __stubs_start);
329
330 early_signal_init();
331
332 flush_icache_range(vectors, vectors + PAGE_SIZE);
333}
diff --git a/arch/unicore32/kernel/vmlinux.lds.S b/arch/unicore32/kernel/vmlinux.lds.S
new file mode 100644
index 00000000000..0b4eb89729e
--- /dev/null
+++ b/arch/unicore32/kernel/vmlinux.lds.S
@@ -0,0 +1,61 @@
1/*
2 * linux/arch/unicore32/kernel/vmlinux.lds.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <asm-generic/vmlinux.lds.h>
14#include <asm/thread_info.h>
15#include <asm/memory.h>
16#include <asm/page.h>
17
18OUTPUT_ARCH(unicore32)
19ENTRY(stext)
20
21jiffies = jiffies_64;
22
23SECTIONS
24{
25 . = PAGE_OFFSET + KERNEL_IMAGE_START;
26
27 _text = .;
28 __init_begin = .;
29 HEAD_TEXT_SECTION
30 INIT_TEXT_SECTION(PAGE_SIZE)
31 INIT_DATA_SECTION(16)
32 PERCPU(PAGE_SIZE)
33 __init_end = .;
34
35 _stext = .;
36 .text : { /* Real text segment */
37 TEXT_TEXT
38 SCHED_TEXT
39 LOCK_TEXT
40
41 *(.fixup)
42 *(.gnu.warning)
43 }
44 _etext = .;
45
46 _sdata = .;
47 RO_DATA_SECTION(PAGE_SIZE)
48 RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
49 _edata = .;
50
51 EXCEPTION_TABLE(32)
52 NOTES
53
54 BSS_SECTION(0, 0, 0)
55 _end = .;
56
57 STABS_DEBUG
58 DWARF_DEBUG
59
60 DISCARDS /* Exit code and data */
61}
diff --git a/arch/unicore32/lib/Makefile b/arch/unicore32/lib/Makefile
new file mode 100644
index 00000000000..87229a558b3
--- /dev/null
+++ b/arch/unicore32/lib/Makefile
@@ -0,0 +1,27 @@
1#
2# linux/arch/unicore32/lib/Makefile
3#
4# Copyright (C) 2001-2010 GUAN Xue-tao
5#
6
7lib-y := backtrace.o delay.o findbit.o
8lib-y += strncpy_from_user.o strnlen_user.o
9lib-y += clear_user.o copy_page.o
10lib-y += copy_from_user.o copy_to_user.o
11
12GNU_LIBC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libc.a)
13GNU_LIBC_A_OBJS := memchr.o memcpy.o memmove.o memset.o
14GNU_LIBC_A_OBJS += strchr.o strrchr.o
15GNU_LIBC_A_OBJS += rawmemchr.o # needed by strrchr.o
16
17GNU_LIBGCC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a)
18GNU_LIBGCC_A_OBJS := _ashldi3.o _ashrdi3.o _lshrdi3.o
19GNU_LIBGCC_A_OBJS += _divsi3.o _modsi3.o _ucmpdi2.o _umodsi3.o _udivsi3.o
20
21lib-y += $(GNU_LIBC_A_OBJS) $(GNU_LIBGCC_A_OBJS)
22
23$(addprefix $(obj)/, $(GNU_LIBC_A_OBJS)):
24 $(Q)$(AR) p $(GNU_LIBC_A) $(notdir $@) > $@
25
26$(addprefix $(obj)/, $(GNU_LIBGCC_A_OBJS)):
27 $(Q)$(AR) p $(GNU_LIBGCC_A) $(notdir $@) > $@
diff --git a/arch/unicore32/lib/backtrace.S b/arch/unicore32/lib/backtrace.S
new file mode 100644
index 00000000000..ef01d77f2f6
--- /dev/null
+++ b/arch/unicore32/lib/backtrace.S
@@ -0,0 +1,163 @@
1/*
2 * linux/arch/unicore32/lib/backtrace.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14 .text
15
16@ fp is 0 or stack frame
17
18#define frame v4
19#define sv_fp v5
20#define sv_pc v6
21#define offset v8
22
23ENTRY(__backtrace)
24 mov r0, fp
25
26ENTRY(c_backtrace)
27
28#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
29 mov pc, lr
30ENDPROC(__backtrace)
31ENDPROC(c_backtrace)
32#else
33 stm.w (v4 - v8, lr), [sp-] @ Save an extra register
34 @ so we have a location...
35 mov.a frame, r0 @ if frame pointer is zero
36 beq no_frame @ we have no stack frames
37
381: stm.w (pc), [sp-] @ calculate offset of PC stored
39 ldw.w r0, [sp]+, #4 @ by stmfd for this CPU
40 adr r1, 1b
41 sub offset, r0, r1
42
43/*
44 * Stack frame layout:
45 * optionally saved caller registers (r4 - r10)
46 * saved fp
47 * saved sp
48 * saved lr
49 * frame => saved pc
50 * optionally saved arguments (r0 - r3)
51 * saved sp => <next word>
52 *
53 * Functions start with the following code sequence:
54 * mov ip, sp
55 * stm.w (r0 - r3), [sp-] (optional)
56 * corrected pc => stm.w sp, (..., fp, ip, lr, pc)
57 */
58for_each_frame:
59
601001: ldw sv_pc, [frame+], #0 @ get saved pc
611002: ldw sv_fp, [frame+], #-12 @ get saved fp
62
63 sub sv_pc, sv_pc, offset @ Correct PC for prefetching
64
651003: ldw r2, [sv_pc+], #-4 @ if stmfd sp, {args} exists,
66 ldw r3, .Ldsi+4 @ adjust saved 'pc' back one
67 cxor.a r3, r2 >> #14 @ instruction
68 beq 201f
69 sub r0, sv_pc, #4 @ allow for mov
70 b 202f
71201:
72 sub r0, sv_pc, #8 @ allow for mov + stmia
73202:
74 ldw r1, [frame+], #-4 @ get saved lr
75 mov r2, frame
76 b.l dump_backtrace_entry
77
78 ldw r1, [sv_pc+], #-4 @ if stmfd sp, {args} exists,
79 ldw r3, .Ldsi+4
80 cxor.a r3, r1 >> #14
81 bne 1004f
82 ldw r0, [frame+], #-8 @ get sp
83 sub r0, r0, #4 @ point at the last arg
84 b.l .Ldumpstm @ dump saved registers
85
861004: ldw r1, [sv_pc+], #0 @ if stmfd {, fp, ip, lr, pc}
87 ldw r3, .Ldsi @ instruction exists,
88 cxor.a r3, r1 >> #14
89 bne 201f
90 sub r0, frame, #16
91 b.l .Ldumpstm @ dump saved registers
92201:
93 cxor.a sv_fp, #0 @ zero saved fp means
94 beq no_frame @ no further frames
95
96 csub.a sv_fp, frame @ next frame must be
97 mov frame, sv_fp @ above the current frame
98 bua for_each_frame
99
1001006: adr r0, .Lbad
101 mov r1, frame
102 b.l printk
103no_frame: ldm.w (v4 - v8, pc), [sp]+
104ENDPROC(__backtrace)
105ENDPROC(c_backtrace)
106
107 .pushsection __ex_table,"a"
108 .align 3
109 .long 1001b, 1006b
110 .long 1002b, 1006b
111 .long 1003b, 1006b
112 .long 1004b, 1006b
113 .popsection
114
115#define instr v4
116#define reg v5
117#define stack v6
118
119.Ldumpstm: stm.w (instr, reg, stack, v7, lr), [sp-]
120 mov stack, r0
121 mov instr, r1
122 mov reg, #14
123 mov v7, #0
1241: mov r3, #1
125 csub.a reg, #8
126 bne 201f
127 sub reg, reg, #3
128201:
129 cand.a instr, r3 << reg
130 beq 2f
131 add v7, v7, #1
132 cxor.a v7, #6
133 cmoveq v7, #1
134 cmoveq r1, #'\n'
135 cmovne r1, #' '
136 ldw.w r3, [stack]+, #-4
137 mov r2, reg
138 csub.a r2, #8
139 bsl 201f
140 sub r2, r2, #3
141201:
142 cand.a instr, #0x40 @ if H is 1, high 16 regs
143 beq 201f
144 add r2, r2, #0x10 @ so r2 need add 16
145201:
146 adr r0, .Lfp
147 b.l printk
1482: sub.a reg, reg, #1
149 bns 1b
150 cxor.a v7, #0
151 beq 201f
152 adr r0, .Lcr
153 b.l printk
154201: ldm.w (instr, reg, stack, v7, pc), [sp]+
155
156.Lfp: .asciz "%cr%d:%08x"
157.Lcr: .asciz "\n"
158.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
159 .align
160.Ldsi: .word 0x92eec000 >> 14 @ stm.w sp, (... fp, ip, lr, pc)
161 .word 0x92e10000 >> 14 @ stm.w sp, ()
162
163#endif
diff --git a/arch/unicore32/lib/clear_user.S b/arch/unicore32/lib/clear_user.S
new file mode 100644
index 00000000000..20047f7224f
--- /dev/null
+++ b/arch/unicore32/lib/clear_user.S
@@ -0,0 +1,57 @@
1/*
2 * linux/arch/unicore32/lib/clear_user.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14
15 .text
16
17/* Prototype: int __clear_user(void *addr, size_t sz)
18 * Purpose : clear some user memory
19 * Params : addr - user memory address to clear
20 * : sz - number of bytes to clear
21 * Returns : number of bytes NOT cleared
22 */
23WEAK(__clear_user)
24 stm.w (lr), [sp-]
25 stm.w (r1), [sp-]
26 mov r2, #0
27 csub.a r1, #4
28 bsl 2f
29 and.a ip, r0, #3
30 beq 1f
31 csub.a ip, #2
32 strusr r2, r0, 1
33 strusr r2, r0, 1, el
34 strusr r2, r0, 1, sl
35 rsub ip, ip, #4
36 sub r1, r1, ip @ 7 6 5 4 3 2 1
371: sub.a r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
38 strusr r2, r0, 4, ns, rept=2
39 bns 1b
40 add.a r1, r1, #4 @ 3 2 1 0 -1 -2 -3
41 strusr r2, r0, 4, ns
422: cand.a r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
43 strusr r2, r0, 1, ne, rept=2
44 cand.a r1, #1 @ x1 x0 x1 x0 x1 x0 x1
45 beq 3f
46USER( stb.u r2, [r0])
473: mov r0, #0
48 ldm.w (r1), [sp]+
49 ldm.w (pc), [sp]+
50ENDPROC(__clear_user)
51
52 .pushsection .fixup,"ax"
53 .align 0
549001: ldm.w (r0), [sp]+
55 ldm.w (pc), [sp]+
56 .popsection
57
diff --git a/arch/unicore32/lib/copy_from_user.S b/arch/unicore32/lib/copy_from_user.S
new file mode 100644
index 00000000000..ab0767ea5db
--- /dev/null
+++ b/arch/unicore32/lib/copy_from_user.S
@@ -0,0 +1,108 @@
1/*
2 * linux/arch/unicore32/lib/copy_from_user.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/linkage.h>
14#include <asm/assembler.h>
15
16/*
17 * Prototype:
18 *
19 * size_t __copy_from_user(void *to, const void *from, size_t n)
20 *
21 * Purpose:
22 *
23 * copy a block to kernel memory from user memory
24 *
25 * Params:
26 *
27 * to = kernel memory
28 * from = user memory
29 * n = number of bytes to copy
30 *
31 * Return value:
32 *
33 * Number of bytes NOT copied.
34 */
35
36 .macro ldr1w ptr reg abort
37 ldrusr \reg, \ptr, 4, abort=\abort
38 .endm
39
40 .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
41100: ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
42 .pushsection __ex_table, "a"
43 .align 3
44 .long 100b, \abort
45 .popsection
46 .endm
47
48 .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
49100: ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
50 .pushsection __ex_table, "a"
51 .align 3
52 .long 100b, \abort
53 .popsection
54 .endm
55
56 .macro ldr1b ptr reg cond=al abort
57 ldrusr \reg, \ptr, 1, \cond, abort=\abort
58 .endm
59
60 .macro str1w ptr reg abort
61 stw.w \reg, [\ptr]+, #4
62 .endm
63
64 .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
65 stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
66 .endm
67
68 .macro str1b ptr reg cond=al abort
69 .ifnc \cond, al
70 b\cond 201f
71 b 202f
72 .endif
73201: stb.w \reg, [\ptr]+, #1
74202:
75 .endm
76
77 .macro enter
78 mov r3, #0
79 stm.w (r0, r2, r3), [sp-]
80 .endm
81
82 .macro exit
83 add sp, sp, #8
84 ldm.w (r0), [sp]+
85 mov pc, lr
86 .endm
87
88 .text
89
90ENTRY(__copy_from_user)
91
92#include "copy_template.S"
93
94ENDPROC(__copy_from_user)
95
96 .pushsection .fixup,"ax"
97 .align 0
98 copy_abort_preamble
99 ldm.w (r1, r2), [sp]+
100 sub r3, r0, r1
101 rsub r2, r3, r2
102 stw r2, [sp]
103 mov r1, #0
104 b.l memset
105 ldw.w r0, [sp]+, #4
106 copy_abort_end
107 .popsection
108
diff --git a/arch/unicore32/lib/copy_page.S b/arch/unicore32/lib/copy_page.S
new file mode 100644
index 00000000000..3a448d755ad
--- /dev/null
+++ b/arch/unicore32/lib/copy_page.S
@@ -0,0 +1,39 @@
1/*
2 * linux/arch/unicore32/lib/copy_page.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * ASM optimised string functions
13 */
14#include <linux/linkage.h>
15#include <asm/assembler.h>
16#include <generated/asm-offsets.h>
17#include <asm/cache.h>
18
19#define COPY_COUNT (PAGE_SZ/256)
20
21 .text
22 .align 5
23/*
24 * UniCore optimised copy_page routine
25 */
26ENTRY(copy_page)
27 stm.w (r17 - r19, lr), [sp-]
28 mov r17, r0
29 mov r18, r1
30 mov r19, #COPY_COUNT
311:
32 .rept 4
33 ldm.w (r0 - r15), [r18]+
34 stm.w (r0 - r15), [r17]+
35 .endr
36 sub.a r19, r19, #1
37 bne 1b
38 ldm.w (r17 - r19, pc), [sp]+
39ENDPROC(copy_page)
diff --git a/arch/unicore32/lib/copy_template.S b/arch/unicore32/lib/copy_template.S
new file mode 100644
index 00000000000..524287fc012
--- /dev/null
+++ b/arch/unicore32/lib/copy_template.S
@@ -0,0 +1,214 @@
1/*
2 * linux/arch/unicore32/lib/copy_template.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13/*
14 * Theory of operation
15 * -------------------
16 *
17 * This file provides the core code for a forward memory copy used in
18 * the implementation of memcopy(), copy_to_user() and copy_from_user().
19 *
20 * The including file must define the following accessor macros
21 * according to the need of the given function:
22 *
23 * ldr1w ptr reg abort
24 *
25 * This loads one word from 'ptr', stores it in 'reg' and increments
26 * 'ptr' to the next word. The 'abort' argument is used for fixup tables.
27 *
28 * ldr4w ptr reg1 reg2 reg3 reg4 abort
29 * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
30 *
31 * This loads four or eight words starting from 'ptr', stores them
32 * in provided registers and increments 'ptr' past those words.
33 * The'abort' argument is used for fixup tables.
34 *
35 * ldr1b ptr reg cond abort
36 *
37 * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
38 * It also must apply the condition code if provided, otherwise the
39 * "al" condition is assumed by default.
40 *
41 * str1w ptr reg abort
42 * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
43 * str1b ptr reg cond abort
44 *
45 * Same as their ldr* counterparts, but data is stored to 'ptr' location
46 * rather than being loaded.
47 *
48 * enter
49 *
50 * Preserve the provided registers on the stack plus any additional
51 * data as needed by the implementation including this code. Called
52 * upon code entry.
53 *
54 * exit
55 *
56 * Restore registers with the values previously saved with the
57 * 'preserv' macro. Called upon code termination.
58 */
59
60
61 enter
62
63 sub.a r2, r2, #4
64 bsl 8f
65 and.a ip, r0, #3
66 bne 9f
67 and.a ip, r1, #3
68 bne 10f
69
701: sub.a r2, r2, #(28)
71 stm.w (r5 - r8), [sp-]
72 bsl 5f
73
743:
754: ldr8w r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
76 sub.a r2, r2, #32
77 str8w r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
78 beg 3b
79
805: and.a ip, r2, #28
81 rsub ip, ip, #32
82 beq 7f
83 add pc, pc, ip @ C is always clear here
84 nop
85
86 ldr1w r1, r3, abort=20f
87 ldr1w r1, r4, abort=20f
88 ldr1w r1, r5, abort=20f
89 ldr1w r1, r6, abort=20f
90 ldr1w r1, r7, abort=20f
91 ldr1w r1, r8, abort=20f
92 ldr1w r1, r11, abort=20f
93
94 add pc, pc, ip
95 nop
96
97 str1w r0, r3, abort=20f
98 str1w r0, r4, abort=20f
99 str1w r0, r5, abort=20f
100 str1w r0, r6, abort=20f
101 str1w r0, r7, abort=20f
102 str1w r0, r8, abort=20f
103 str1w r0, r11, abort=20f
104
1057: ldm.w (r5 - r8), [sp]+
106
1078: mov.a r2, r2 << #31
108 ldr1b r1, r3, ne, abort=21f
109 ldr1b r1, r4, ea, abort=21f
110 ldr1b r1, r10, ea, abort=21f
111 str1b r0, r3, ne, abort=21f
112 str1b r0, r4, ea, abort=21f
113 str1b r0, r10, ea, abort=21f
114
115 exit
116
1179: rsub ip, ip, #4
118 csub.a ip, #2
119 ldr1b r1, r3, sg, abort=21f
120 ldr1b r1, r4, eg, abort=21f
121 ldr1b r1, r11, abort=21f
122 str1b r0, r3, sg, abort=21f
123 str1b r0, r4, eg, abort=21f
124 sub.a r2, r2, ip
125 str1b r0, r11, abort=21f
126 bsl 8b
127 and.a ip, r1, #3
128 beq 1b
129
13010: andn r1, r1, #3
131 csub.a ip, #2
132 ldr1w r1, r11, abort=21f
133 beq 17f
134 bsg 18f
135
136
137 .macro forward_copy_shift a b
138
139 sub.a r2, r2, #28
140 bsl 14f
141
14211: stm.w (r5 - r9), [sp-]
143
14412:
145 ldr4w r1, r4, r5, r6, r7, abort=19f
146 mov r3, r11 pull #\a
147 sub.a r2, r2, #32
148 ldr4w r1, r8, r9, r10, r11, abort=19f
149 or r3, r3, r4 push #\b
150 mov r4, r4 pull #\a
151 or r4, r4, r5 push #\b
152 mov r5, r5 pull #\a
153 or r5, r5, r6 push #\b
154 mov r6, r6 pull #\a
155 or r6, r6, r7 push #\b
156 mov r7, r7 pull #\a
157 or r7, r7, r8 push #\b
158 mov r8, r8 pull #\a
159 or r8, r8, r9 push #\b
160 mov r9, r9 pull #\a
161 or r9, r9, r10 push #\b
162 mov r10, r10 pull #\a
163 or r10, r10, r11 push #\b
164 str8w r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f
165 beg 12b
166
167 ldm.w (r5 - r9), [sp]+
168
16914: and.a ip, r2, #28
170 beq 16f
171
17215: mov r3, r11 pull #\a
173 ldr1w r1, r11, abort=21f
174 sub.a ip, ip, #4
175 or r3, r3, r11 push #\b
176 str1w r0, r3, abort=21f
177 bsg 15b
178
17916: sub r1, r1, #(\b / 8)
180 b 8b
181
182 .endm
183
184
185 forward_copy_shift a=8 b=24
186
18717: forward_copy_shift a=16 b=16
188
18918: forward_copy_shift a=24 b=8
190
191
192/*
193 * Abort preamble and completion macros.
194 * If a fixup handler is required then those macros must surround it.
195 * It is assumed that the fixup code will handle the private part of
196 * the exit macro.
197 */
198
199 .macro copy_abort_preamble
20019: ldm.w (r5 - r9), [sp]+
201 b 21f
202299: .word 0 @ store lr
203 @ to avoid function call in fixup
20420: ldm.w (r5 - r8), [sp]+
20521:
206 adr r1, 299b
207 stw lr, [r1]
208 .endm
209
210 .macro copy_abort_end
211 adr lr, 299b
212 ldw pc, [lr]
213 .endm
214
diff --git a/arch/unicore32/lib/copy_to_user.S b/arch/unicore32/lib/copy_to_user.S
new file mode 100644
index 00000000000..6e22151c840
--- /dev/null
+++ b/arch/unicore32/lib/copy_to_user.S
@@ -0,0 +1,96 @@
1/*
2 * linux/arch/unicore32/lib/copy_to_user.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/linkage.h>
14#include <asm/assembler.h>
15
16/*
17 * Prototype:
18 *
19 * size_t __copy_to_user(void *to, const void *from, size_t n)
20 *
21 * Purpose:
22 *
23 * copy a block to user memory from kernel memory
24 *
25 * Params:
26 *
27 * to = user memory
28 * from = kernel memory
29 * n = number of bytes to copy
30 *
31 * Return value:
32 *
33 * Number of bytes NOT copied.
34 */
35
36 .macro ldr1w ptr reg abort
37 ldw.w \reg, [\ptr]+, #4
38 .endm
39
40 .macro ldr4w ptr reg1 reg2 reg3 reg4 abort
41 ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
42 .endm
43
44 .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
45 ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
46 .endm
47
48 .macro ldr1b ptr reg cond=al abort
49 notcond \cond, .+8
50 ldb.w \reg, [\ptr]+, #1
51 .endm
52
53 .macro str1w ptr reg abort
54 strusr \reg, \ptr, 4, abort=\abort
55 .endm
56
57 .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
58100: stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
59
60 .pushsection __ex_table, "a"
61 .long 100b, \abort
62 .popsection
63 .endm
64
65 .macro str1b ptr reg cond=al abort
66 strusr \reg, \ptr, 1, \cond, abort=\abort
67 .endm
68
69 .macro enter
70 mov r3, #0
71 stm.w (r0, r2, r3), [sp-]
72 .endm
73
74 .macro exit
75 add sp, sp, #8
76 ldm.w (r0), [sp]+
77 mov pc, lr
78 .endm
79
80 .text
81
82WEAK(__copy_to_user)
83
84#include "copy_template.S"
85
86ENDPROC(__copy_to_user)
87
88 .pushsection .fixup,"ax"
89 .align 0
90 copy_abort_preamble
91 ldm.w (r1, r2, r3), [sp]+
92 sub r0, r0, r1
93 rsub r0, r0, r2
94 copy_abort_end
95 .popsection
96
diff --git a/arch/unicore32/lib/delay.S b/arch/unicore32/lib/delay.S
new file mode 100644
index 00000000000..24664c009e7
--- /dev/null
+++ b/arch/unicore32/lib/delay.S
@@ -0,0 +1,51 @@
1/*
2 * linux/arch/unicore32/lib/delay.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14#include <asm/param.h>
15 .text
16
17.LC0: .word loops_per_jiffy
18.LC1: .word (2199023*HZ)>>11
19
20/*
21 * r0 <= 2000
22 * lpj <= 0x01ffffff (max. 3355 bogomips)
23 * HZ <= 1000
24 */
25
26ENTRY(__udelay)
27 ldw r2, .LC1
28 mul r0, r2, r0
29ENTRY(__const_udelay) @ 0 <= r0 <= 0x7fffff06
30 ldw r2, .LC0
31 ldw r2, [r2] @ max = 0x01ffffff
32 mov r0, r0 >> #14 @ max = 0x0001ffff
33 mov r2, r2 >> #10 @ max = 0x00007fff
34 mul r0, r2, r0 @ max = 2^32-1
35 mov.a r0, r0 >> #6
36 cmoveq pc, lr
37
38/*
39 * loops = r0 * HZ * loops_per_jiffy / 1000000
40 *
41 * Oh, if only we had a cycle counter...
42 */
43
44@ Delay routine
45ENTRY(__delay)
46 sub.a r0, r0, #2
47 bua __delay
48 mov pc, lr
49ENDPROC(__udelay)
50ENDPROC(__const_udelay)
51ENDPROC(__delay)
diff --git a/arch/unicore32/lib/findbit.S b/arch/unicore32/lib/findbit.S
new file mode 100644
index 00000000000..c360ce905d8
--- /dev/null
+++ b/arch/unicore32/lib/findbit.S
@@ -0,0 +1,98 @@
1/*
2 * linux/arch/unicore32/lib/findbit.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14 .text
15
16/*
17 * Purpose : Find a 'zero' bit
18 * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit);
19 */
20__uc32_find_first_zero_bit:
21 cxor.a r1, #0
22 beq 3f
23 mov r2, #0
241: ldb r3, [r0+], r2 >> #3
25 xor.a r3, r3, #0xff @ invert bits
26 bne .L_found @ any now set - found zero bit
27 add r2, r2, #8 @ next bit pointer
282: csub.a r2, r1 @ any more?
29 bub 1b
303: mov r0, r1 @ no free bits
31 mov pc, lr
32
33/*
34 * Purpose : Find next 'zero' bit
35 * Prototype: int find_next_zero_bit
36 * (void *addr, unsigned int maxbit, int offset)
37 */
38ENTRY(__uc32_find_next_zero_bit)
39 cxor.a r1, #0
40 beq 3b
41 and.a ip, r2, #7
42 beq 1b @ If new byte, goto old routine
43 ldb r3, [r0+], r2 >> #3
44 xor r3, r3, #0xff @ now looking for a 1 bit
45 mov.a r3, r3 >> ip @ shift off unused bits
46 bne .L_found
47 or r2, r2, #7 @ if zero, then no bits here
48 add r2, r2, #1 @ align bit pointer
49 b 2b @ loop for next bit
50ENDPROC(__uc32_find_next_zero_bit)
51
52/*
53 * Purpose : Find a 'one' bit
54 * Prototype: int find_first_bit
55 * (const unsigned long *addr, unsigned int maxbit);
56 */
57__uc32_find_first_bit:
58 cxor.a r1, #0
59 beq 3f
60 mov r2, #0
611: ldb r3, [r0+], r2 >> #3
62 mov.a r3, r3
63 bne .L_found @ any now set - found zero bit
64 add r2, r2, #8 @ next bit pointer
652: csub.a r2, r1 @ any more?
66 bub 1b
673: mov r0, r1 @ no free bits
68 mov pc, lr
69
70/*
71 * Purpose : Find next 'one' bit
72 * Prototype: int find_next_zero_bit
73 * (void *addr, unsigned int maxbit, int offset)
74 */
75ENTRY(__uc32_find_next_bit)
76 cxor.a r1, #0
77 beq 3b
78 and.a ip, r2, #7
79 beq 1b @ If new byte, goto old routine
80 ldb r3, [r0+], r2 >> #3
81 mov.a r3, r3 >> ip @ shift off unused bits
82 bne .L_found
83 or r2, r2, #7 @ if zero, then no bits here
84 add r2, r2, #1 @ align bit pointer
85 b 2b @ loop for next bit
86ENDPROC(__uc32_find_next_bit)
87
88/*
89 * One or more bits in the LSB of r3 are assumed to be set.
90 */
91.L_found:
92 rsub r1, r3, #0
93 and r3, r3, r1
94 cntlz r3, r3
95 rsub r3, r3, #31
96 add r0, r2, r3
97 mov pc, lr
98
diff --git a/arch/unicore32/lib/strncpy_from_user.S b/arch/unicore32/lib/strncpy_from_user.S
new file mode 100644
index 00000000000..ff6c304d5c7
--- /dev/null
+++ b/arch/unicore32/lib/strncpy_from_user.S
@@ -0,0 +1,45 @@
1/*
2 * linux/arch/unicore32/lib/strncpy_from_user.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14#include <asm/errno.h>
15
16 .text
17 .align 5
18
19/*
20 * Copy a string from user space to kernel space.
21 * r0 = dst, r1 = src, r2 = byte length
22 * returns the number of characters copied (strlen of copied string),
23 * -EFAULT on exception, or "len" if we fill the whole buffer
24 */
25ENTRY(__strncpy_from_user)
26 mov ip, r1
271: sub.a r2, r2, #1
28 ldrusr r3, r1, 1, ns
29 bfs 2f
30 stb.w r3, [r0]+, #1
31 cxor.a r3, #0
32 bne 1b
33 sub r1, r1, #1 @ take NUL character out of count
342: sub r0, r1, ip
35 mov pc, lr
36ENDPROC(__strncpy_from_user)
37
38 .pushsection .fixup,"ax"
39 .align 0
409001: mov r3, #0
41 stb r3, [r0+], #0 @ null terminate
42 mov r0, #-EFAULT
43 mov pc, lr
44 .popsection
45
diff --git a/arch/unicore32/lib/strnlen_user.S b/arch/unicore32/lib/strnlen_user.S
new file mode 100644
index 00000000000..75863030f21
--- /dev/null
+++ b/arch/unicore32/lib/strnlen_user.S
@@ -0,0 +1,42 @@
1/*
2 * linux/arch/unicore32/lib/strnlen_user.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14#include <asm/errno.h>
15
16 .text
17 .align 5
18
19/* Prototype: unsigned long __strnlen_user(const char *str, long n)
20 * Purpose : get length of a string in user memory
21 * Params : str - address of string in user memory
22 * Returns : length of string *including terminator*
23 * or zero on exception, or n + 1 if too long
24 */
25ENTRY(__strnlen_user)
26 mov r2, r0
271:
28 ldrusr r3, r0, 1
29 cxor.a r3, #0
30 beq 2f
31 sub.a r1, r1, #1
32 bne 1b
33 add r0, r0, #1
342: sub r0, r0, r2
35 mov pc, lr
36ENDPROC(__strnlen_user)
37
38 .pushsection .fixup,"ax"
39 .align 0
409001: mov r0, #0
41 mov pc, lr
42 .popsection
diff --git a/arch/unicore32/mm/Kconfig b/arch/unicore32/mm/Kconfig
new file mode 100644
index 00000000000..5f77fb3c63b
--- /dev/null
+++ b/arch/unicore32/mm/Kconfig
@@ -0,0 +1,50 @@
1comment "Processor Type"
2
3# Select CPU types depending on the architecture selected. This selects
4# which CPUs we support in the kernel image, and the compiler instruction
5# optimiser behaviour.
6
7config CPU_UCV2
8 def_bool y
9
10comment "Processor Features"
11
12config CPU_ICACHE_DISABLE
13 bool "Disable I-Cache (I-bit)"
14 help
15 Say Y here to disable the processor instruction cache. Unless
16 you have a reason not to or are unsure, say N.
17
18config CPU_DCACHE_DISABLE
19 bool "Disable D-Cache (D-bit)"
20 help
21 Say Y here to disable the processor data cache. Unless
22 you have a reason not to or are unsure, say N.
23
24config CPU_DCACHE_WRITETHROUGH
25 bool "Force write through D-cache"
26 help
27 Say Y here to use the data cache in writethrough mode. Unless you
28 specifically require this or are unsure, say N.
29
30config CPU_DCACHE_LINE_DISABLE
31 bool "Disable D-cache line ops"
32 default y
33 help
34 Say Y here to disable the data cache line operations.
35
36config CPU_TLB_SINGLE_ENTRY_DISABLE
37 bool "Disable TLB single entry ops"
38 default y
39 help
40 Say Y here to disable the TLB single entry operations.
41
42config SWIOTLB
43 def_bool y
44
45config IOMMU_HELPER
46 def_bool SWIOTLB
47
48config NEED_SG_DMA_LENGTH
49 def_bool SWIOTLB
50
diff --git a/arch/unicore32/mm/Makefile b/arch/unicore32/mm/Makefile
new file mode 100644
index 00000000000..46c16669931
--- /dev/null
+++ b/arch/unicore32/mm/Makefile
@@ -0,0 +1,15 @@
1#
2# Makefile for the linux unicore-specific parts of the memory manager.
3#
4
5obj-y := extable.o fault.o init.o pgd.o mmu.o
6obj-y += flush.o ioremap.o
7
8obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
9
10obj-$(CONFIG_MODULES) += proc-syms.o
11
12obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
13
14obj-$(CONFIG_CPU_UCV2) += cache-ucv2.o tlb-ucv2.o proc-ucv2.o
15
diff --git a/arch/unicore32/mm/alignment.c b/arch/unicore32/mm/alignment.c
new file mode 100644
index 00000000000..28f576d733e
--- /dev/null
+++ b/arch/unicore32/mm/alignment.c
@@ -0,0 +1,523 @@
1/*
2 * linux/arch/unicore32/mm/alignment.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12/*
13 * TODO:
14 * FPU ldm/stm not handling
15 */
16#include <linux/compiler.h>
17#include <linux/kernel.h>
18#include <linux/errno.h>
19#include <linux/string.h>
20#include <linux/init.h>
21#include <linux/sched.h>
22#include <linux/uaccess.h>
23
24#include <asm/tlbflush.h>
25#include <asm/unaligned.h>
26
27#define CODING_BITS(i) (i & 0xe0000120)
28
29#define LDST_P_BIT(i) (i & (1 << 28)) /* Preindex */
30#define LDST_U_BIT(i) (i & (1 << 27)) /* Add offset */
31#define LDST_W_BIT(i) (i & (1 << 25)) /* Writeback */
32#define LDST_L_BIT(i) (i & (1 << 24)) /* Load */
33
34#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 27)) == 0)
35
36#define LDSTH_I_BIT(i) (i & (1 << 26)) /* half-word immed */
37#define LDM_S_BIT(i) (i & (1 << 26)) /* write ASR from BSR */
38#define LDM_H_BIT(i) (i & (1 << 6)) /* select r0-r15 or r16-r31 */
39
40#define RN_BITS(i) ((i >> 19) & 31) /* Rn */
41#define RD_BITS(i) ((i >> 14) & 31) /* Rd */
42#define RM_BITS(i) (i & 31) /* Rm */
43
44#define REGMASK_BITS(i) (((i & 0x7fe00) >> 3) | (i & 0x3f))
45#define OFFSET_BITS(i) (i & 0x03fff)
46
47#define SHIFT_BITS(i) ((i >> 9) & 0x1f)
48#define SHIFT_TYPE(i) (i & 0xc0)
49#define SHIFT_LSL 0x00
50#define SHIFT_LSR 0x40
51#define SHIFT_ASR 0x80
52#define SHIFT_RORRRX 0xc0
53
54union offset_union {
55 unsigned long un;
56 signed long sn;
57};
58
59#define TYPE_ERROR 0
60#define TYPE_FAULT 1
61#define TYPE_LDST 2
62#define TYPE_DONE 3
63#define TYPE_SWAP 4
64#define TYPE_COLS 5 /* Coprocessor load/store */
65
66#define get8_unaligned_check(val, addr, err) \
67 __asm__( \
68 "1: ldb.u %1, [%2], #1\n" \
69 "2:\n" \
70 " .pushsection .fixup,\"ax\"\n" \
71 " .align 2\n" \
72 "3: mov %0, #1\n" \
73 " b 2b\n" \
74 " .popsection\n" \
75 " .pushsection __ex_table,\"a\"\n" \
76 " .align 3\n" \
77 " .long 1b, 3b\n" \
78 " .popsection\n" \
79 : "=r" (err), "=&r" (val), "=r" (addr) \
80 : "0" (err), "2" (addr))
81
82#define get8t_unaligned_check(val, addr, err) \
83 __asm__( \
84 "1: ldb.u %1, [%2], #1\n" \
85 "2:\n" \
86 " .pushsection .fixup,\"ax\"\n" \
87 " .align 2\n" \
88 "3: mov %0, #1\n" \
89 " b 2b\n" \
90 " .popsection\n" \
91 " .pushsection __ex_table,\"a\"\n" \
92 " .align 3\n" \
93 " .long 1b, 3b\n" \
94 " .popsection\n" \
95 : "=r" (err), "=&r" (val), "=r" (addr) \
96 : "0" (err), "2" (addr))
97
98#define get16_unaligned_check(val, addr) \
99 do { \
100 unsigned int err = 0, v, a = addr; \
101 get8_unaligned_check(val, a, err); \
102 get8_unaligned_check(v, a, err); \
103 val |= v << 8; \
104 if (err) \
105 goto fault; \
106 } while (0)
107
108#define put16_unaligned_check(val, addr) \
109 do { \
110 unsigned int err = 0, v = val, a = addr; \
111 __asm__( \
112 "1: stb.u %1, [%2], #1\n" \
113 " mov %1, %1 >> #8\n" \
114 "2: stb.u %1, [%2]\n" \
115 "3:\n" \
116 " .pushsection .fixup,\"ax\"\n" \
117 " .align 2\n" \
118 "4: mov %0, #1\n" \
119 " b 3b\n" \
120 " .popsection\n" \
121 " .pushsection __ex_table,\"a\"\n" \
122 " .align 3\n" \
123 " .long 1b, 4b\n" \
124 " .long 2b, 4b\n" \
125 " .popsection\n" \
126 : "=r" (err), "=&r" (v), "=&r" (a) \
127 : "0" (err), "1" (v), "2" (a)); \
128 if (err) \
129 goto fault; \
130 } while (0)
131
132#define __put32_unaligned_check(ins, val, addr) \
133 do { \
134 unsigned int err = 0, v = val, a = addr; \
135 __asm__( \
136 "1: "ins" %1, [%2], #1\n" \
137 " mov %1, %1 >> #8\n" \
138 "2: "ins" %1, [%2], #1\n" \
139 " mov %1, %1 >> #8\n" \
140 "3: "ins" %1, [%2], #1\n" \
141 " mov %1, %1 >> #8\n" \
142 "4: "ins" %1, [%2]\n" \
143 "5:\n" \
144 " .pushsection .fixup,\"ax\"\n" \
145 " .align 2\n" \
146 "6: mov %0, #1\n" \
147 " b 5b\n" \
148 " .popsection\n" \
149 " .pushsection __ex_table,\"a\"\n" \
150 " .align 3\n" \
151 " .long 1b, 6b\n" \
152 " .long 2b, 6b\n" \
153 " .long 3b, 6b\n" \
154 " .long 4b, 6b\n" \
155 " .popsection\n" \
156 : "=r" (err), "=&r" (v), "=&r" (a) \
157 : "0" (err), "1" (v), "2" (a)); \
158 if (err) \
159 goto fault; \
160 } while (0)
161
162#define get32_unaligned_check(val, addr) \
163 do { \
164 unsigned int err = 0, v, a = addr; \
165 get8_unaligned_check(val, a, err); \
166 get8_unaligned_check(v, a, err); \
167 val |= v << 8; \
168 get8_unaligned_check(v, a, err); \
169 val |= v << 16; \
170 get8_unaligned_check(v, a, err); \
171 val |= v << 24; \
172 if (err) \
173 goto fault; \
174 } while (0)
175
176#define put32_unaligned_check(val, addr) \
177 __put32_unaligned_check("stb.u", val, addr)
178
179#define get32t_unaligned_check(val, addr) \
180 do { \
181 unsigned int err = 0, v, a = addr; \
182 get8t_unaligned_check(val, a, err); \
183 get8t_unaligned_check(v, a, err); \
184 val |= v << 8; \
185 get8t_unaligned_check(v, a, err); \
186 val |= v << 16; \
187 get8t_unaligned_check(v, a, err); \
188 val |= v << 24; \
189 if (err) \
190 goto fault; \
191 } while (0)
192
193#define put32t_unaligned_check(val, addr) \
194 __put32_unaligned_check("stb.u", val, addr)
195
196static void
197do_alignment_finish_ldst(unsigned long addr, unsigned long instr,
198 struct pt_regs *regs, union offset_union offset)
199{
200 if (!LDST_U_BIT(instr))
201 offset.un = -offset.un;
202
203 if (!LDST_P_BIT(instr))
204 addr += offset.un;
205
206 if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
207 regs->uregs[RN_BITS(instr)] = addr;
208}
209
210static int
211do_alignment_ldrhstrh(unsigned long addr, unsigned long instr,
212 struct pt_regs *regs)
213{
214 unsigned int rd = RD_BITS(instr);
215
216 /* old value 0x40002120, can't judge swap instr correctly */
217 if ((instr & 0x4b003fe0) == 0x40000120)
218 goto swp;
219
220 if (LDST_L_BIT(instr)) {
221 unsigned long val;
222 get16_unaligned_check(val, addr);
223
224 /* signed half-word? */
225 if (instr & 0x80)
226 val = (signed long)((signed short)val);
227
228 regs->uregs[rd] = val;
229 } else
230 put16_unaligned_check(regs->uregs[rd], addr);
231
232 return TYPE_LDST;
233
234swp:
235 /* only handle swap word
236 * for swap byte should not active this alignment exception */
237 get32_unaligned_check(regs->uregs[RD_BITS(instr)], addr);
238 put32_unaligned_check(regs->uregs[RM_BITS(instr)], addr);
239 return TYPE_SWAP;
240
241fault:
242 return TYPE_FAULT;
243}
244
245static int
246do_alignment_ldrstr(unsigned long addr, unsigned long instr,
247 struct pt_regs *regs)
248{
249 unsigned int rd = RD_BITS(instr);
250
251 if (!LDST_P_BIT(instr) && LDST_W_BIT(instr))
252 goto trans;
253
254 if (LDST_L_BIT(instr))
255 get32_unaligned_check(regs->uregs[rd], addr);
256 else
257 put32_unaligned_check(regs->uregs[rd], addr);
258 return TYPE_LDST;
259
260trans:
261 if (LDST_L_BIT(instr))
262 get32t_unaligned_check(regs->uregs[rd], addr);
263 else
264 put32t_unaligned_check(regs->uregs[rd], addr);
265 return TYPE_LDST;
266
267fault:
268 return TYPE_FAULT;
269}
270
271/*
272 * LDM/STM alignment handler.
273 *
274 * There are 4 variants of this instruction:
275 *
276 * B = rn pointer before instruction, A = rn pointer after instruction
277 * ------ increasing address ----->
278 * | | r0 | r1 | ... | rx | |
279 * PU = 01 B A
280 * PU = 11 B A
281 * PU = 00 A B
282 * PU = 10 A B
283 */
284static int
285do_alignment_ldmstm(unsigned long addr, unsigned long instr,
286 struct pt_regs *regs)
287{
288 unsigned int rd, rn, pc_correction, reg_correction, nr_regs, regbits;
289 unsigned long eaddr, newaddr;
290
291 if (LDM_S_BIT(instr))
292 goto bad;
293
294 pc_correction = 4; /* processor implementation defined */
295
296 /* count the number of registers in the mask to be transferred */
297 nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
298
299 rn = RN_BITS(instr);
300 newaddr = eaddr = regs->uregs[rn];
301
302 if (!LDST_U_BIT(instr))
303 nr_regs = -nr_regs;
304 newaddr += nr_regs;
305 if (!LDST_U_BIT(instr))
306 eaddr = newaddr;
307
308 if (LDST_P_EQ_U(instr)) /* U = P */
309 eaddr += 4;
310
311 /*
312 * This is a "hint" - we already have eaddr worked out by the
313 * processor for us.
314 */
315 if (addr != eaddr) {
316 printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
317 "addr = %08lx, eaddr = %08lx\n",
318 instruction_pointer(regs), instr, addr, eaddr);
319 show_regs(regs);
320 }
321
322 if (LDM_H_BIT(instr))
323 reg_correction = 0x10;
324 else
325 reg_correction = 0x00;
326
327 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
328 regbits >>= 1, rd += 1)
329 if (regbits & 1) {
330 if (LDST_L_BIT(instr))
331 get32_unaligned_check(regs->
332 uregs[rd + reg_correction], eaddr);
333 else
334 put32_unaligned_check(regs->
335 uregs[rd + reg_correction], eaddr);
336 eaddr += 4;
337 }
338
339 if (LDST_W_BIT(instr))
340 regs->uregs[rn] = newaddr;
341 return TYPE_DONE;
342
343fault:
344 regs->UCreg_pc -= pc_correction;
345 return TYPE_FAULT;
346
347bad:
348 printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
349 return TYPE_ERROR;
350}
351
352static int
353do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs)
354{
355 union offset_union offset;
356 unsigned long instr, instrptr;
357 int (*handler) (unsigned long addr, unsigned long instr,
358 struct pt_regs *regs);
359 unsigned int type;
360
361 instrptr = instruction_pointer(regs);
362 if (instrptr >= PAGE_OFFSET)
363 instr = *(unsigned long *)instrptr;
364 else {
365 __asm__ __volatile__(
366 "ldw.u %0, [%1]\n"
367 : "=&r"(instr)
368 : "r"(instrptr));
369 }
370
371 regs->UCreg_pc += 4;
372
373 switch (CODING_BITS(instr)) {
374 case 0x40000120: /* ldrh or strh */
375 if (LDSTH_I_BIT(instr))
376 offset.un = (instr & 0x3e00) >> 4 | (instr & 31);
377 else
378 offset.un = regs->uregs[RM_BITS(instr)];
379 handler = do_alignment_ldrhstrh;
380 break;
381
382 case 0x60000000: /* ldr or str immediate */
383 case 0x60000100: /* ldr or str immediate */
384 case 0x60000020: /* ldr or str immediate */
385 case 0x60000120: /* ldr or str immediate */
386 offset.un = OFFSET_BITS(instr);
387 handler = do_alignment_ldrstr;
388 break;
389
390 case 0x40000000: /* ldr or str register */
391 offset.un = regs->uregs[RM_BITS(instr)];
392 {
393 unsigned int shiftval = SHIFT_BITS(instr);
394
395 switch (SHIFT_TYPE(instr)) {
396 case SHIFT_LSL:
397 offset.un <<= shiftval;
398 break;
399
400 case SHIFT_LSR:
401 offset.un >>= shiftval;
402 break;
403
404 case SHIFT_ASR:
405 offset.sn >>= shiftval;
406 break;
407
408 case SHIFT_RORRRX:
409 if (shiftval == 0) {
410 offset.un >>= 1;
411 if (regs->UCreg_asr & PSR_C_BIT)
412 offset.un |= 1 << 31;
413 } else
414 offset.un = offset.un >> shiftval |
415 offset.un << (32 - shiftval);
416 break;
417 }
418 }
419 handler = do_alignment_ldrstr;
420 break;
421
422 case 0x80000000: /* ldm or stm */
423 case 0x80000020: /* ldm or stm */
424 handler = do_alignment_ldmstm;
425 break;
426
427 default:
428 goto bad;
429 }
430
431 type = handler(addr, instr, regs);
432
433 if (type == TYPE_ERROR || type == TYPE_FAULT)
434 goto bad_or_fault;
435
436 if (type == TYPE_LDST)
437 do_alignment_finish_ldst(addr, instr, regs, offset);
438
439 return 0;
440
441bad_or_fault:
442 if (type == TYPE_ERROR)
443 goto bad;
444 regs->UCreg_pc -= 4;
445 /*
446 * We got a fault - fix it up, or die.
447 */
448 do_bad_area(addr, error_code, regs);
449 return 0;
450
451bad:
452 /*
453 * Oops, we didn't handle the instruction.
454 * However, we must handle fpu instr firstly.
455 */
456#ifdef CONFIG_UNICORE_FPU_F64
457 /* handle co.load/store */
458#define CODING_COLS 0xc0000000
459#define COLS_OFFSET_BITS(i) (i & 0x1FF)
460#define COLS_L_BITS(i) (i & (1<<24))
461#define COLS_FN_BITS(i) ((i>>14) & 31)
462 if ((instr & 0xe0000000) == CODING_COLS) {
463 unsigned int fn = COLS_FN_BITS(instr);
464 unsigned long val = 0;
465 if (COLS_L_BITS(instr)) {
466 get32t_unaligned_check(val, addr);
467 switch (fn) {
468#define ASM_MTF(n) case n: \
469 __asm__ __volatile__("MTF %0, F" __stringify(n) \
470 : : "r"(val)); \
471 break;
472 ASM_MTF(0); ASM_MTF(1); ASM_MTF(2); ASM_MTF(3);
473 ASM_MTF(4); ASM_MTF(5); ASM_MTF(6); ASM_MTF(7);
474 ASM_MTF(8); ASM_MTF(9); ASM_MTF(10); ASM_MTF(11);
475 ASM_MTF(12); ASM_MTF(13); ASM_MTF(14); ASM_MTF(15);
476 ASM_MTF(16); ASM_MTF(17); ASM_MTF(18); ASM_MTF(19);
477 ASM_MTF(20); ASM_MTF(21); ASM_MTF(22); ASM_MTF(23);
478 ASM_MTF(24); ASM_MTF(25); ASM_MTF(26); ASM_MTF(27);
479 ASM_MTF(28); ASM_MTF(29); ASM_MTF(30); ASM_MTF(31);
480#undef ASM_MTF
481 }
482 } else {
483 switch (fn) {
484#define ASM_MFF(n) case n: \
485 __asm__ __volatile__("MFF %0, F" __stringify(n) \
486 : : "r"(val)); \
487 break;
488 ASM_MFF(0); ASM_MFF(1); ASM_MFF(2); ASM_MFF(3);
489 ASM_MFF(4); ASM_MFF(5); ASM_MFF(6); ASM_MFF(7);
490 ASM_MFF(8); ASM_MFF(9); ASM_MFF(10); ASM_MFF(11);
491 ASM_MFF(12); ASM_MFF(13); ASM_MFF(14); ASM_MFF(15);
492 ASM_MFF(16); ASM_MFF(17); ASM_MFF(18); ASM_MFF(19);
493 ASM_MFF(20); ASM_MFF(21); ASM_MFF(22); ASM_MFF(23);
494 ASM_MFF(24); ASM_MFF(25); ASM_MFF(26); ASM_MFF(27);
495 ASM_MFF(28); ASM_MFF(29); ASM_MFF(30); ASM_MFF(31);
496#undef ASM_MFF
497 }
498 put32t_unaligned_check(val, addr);
499 }
500 return TYPE_COLS;
501 }
502fault:
503 return TYPE_FAULT;
504#endif
505 printk(KERN_ERR "Alignment trap: not handling instruction "
506 "%08lx at [<%08lx>]\n", instr, instrptr);
507 return 1;
508}
509
510/*
511 * This needs to be done after sysctl_init, otherwise sys/ will be
512 * overwritten. Actually, this shouldn't be in sys/ at all since
513 * it isn't a sysctl, and it doesn't contain sysctl information.
514 */
515static int __init alignment_init(void)
516{
517 hook_fault_code(1, do_alignment, SIGBUS, BUS_ADRALN,
518 "alignment exception");
519
520 return 0;
521}
522
523fs_initcall(alignment_init);
diff --git a/arch/unicore32/mm/cache-ucv2.S b/arch/unicore32/mm/cache-ucv2.S
new file mode 100644
index 00000000000..ecaa1727f90
--- /dev/null
+++ b/arch/unicore32/mm/cache-ucv2.S
@@ -0,0 +1,212 @@
1/*
2 * linux/arch/unicore32/mm/cache-ucv2.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * This is the "shell" of the UniCore-v2 processor support.
13 */
14#include <linux/linkage.h>
15#include <linux/init.h>
16#include <asm/assembler.h>
17#include <asm/page.h>
18
19#include "proc-macros.S"
20
21/*
22 * __cpuc_flush_icache_all()
23 * __cpuc_flush_kern_all()
24 * __cpuc_flush_user_all()
25 *
26 * Flush the entire cache.
27 */
28ENTRY(__cpuc_flush_icache_all)
29 /*FALLTHROUGH*/
30ENTRY(__cpuc_flush_kern_all)
31 /*FALLTHROUGH*/
32ENTRY(__cpuc_flush_user_all)
33 mov r0, #0
34 movc p0.c5, r0, #14 @ Dcache flush all
35 nop8
36
37 mov r0, #0
38 movc p0.c5, r0, #20 @ Icache invalidate all
39 nop8
40
41 mov pc, lr
42
43/*
44 * __cpuc_flush_user_range(start, end, flags)
45 *
46 * Flush a range of TLB entries in the specified address space.
47 *
48 * - start - start address (may not be aligned)
49 * - end - end address (exclusive, may not be aligned)
50 * - flags - vm_area_struct flags describing address space
51 */
52ENTRY(__cpuc_flush_user_range)
53 cxor.a r2, #0
54 beq __cpuc_dma_flush_range
55
56#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
57 andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check
58 sub r1, r1, r0
59 csub.a r1, #MAX_AREA_SIZE
60 bsg 2f
61
62 andn r1, r1, #CACHE_LINESIZE - 1
63 add r1, r1, #CACHE_LINESIZE
64
65101: dcacheline_flush r0, r11, r12
66
67 add r0, r0, #CACHE_LINESIZE
68 sub.a r1, r1, #CACHE_LINESIZE
69 bns 101b
70 b 3f
71#endif
722: mov ip, #0
73 movc p0.c5, ip, #14 @ Dcache flush all
74 nop8
75
763: mov ip, #0
77 movc p0.c5, ip, #20 @ Icache invalidate all
78 nop8
79
80 mov pc, lr
81
82/*
83 * __cpuc_coherent_kern_range(start,end)
84 * __cpuc_coherent_user_range(start,end)
85 *
86 * Ensure that the I and D caches are coherent within specified
87 * region. This is typically used when code has been written to
88 * a memory region, and will be executed.
89 *
90 * - start - virtual start address of region
91 * - end - virtual end address of region
92 */
93ENTRY(__cpuc_coherent_kern_range)
94 /* FALLTHROUGH */
95ENTRY(__cpuc_coherent_user_range)
96#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
97 andn r0, r0, #CACHE_LINESIZE - 1 @ Safety check
98 sub r1, r1, r0
99 csub.a r1, #MAX_AREA_SIZE
100 bsg 2f
101
102 andn r1, r1, #CACHE_LINESIZE - 1
103 add r1, r1, #CACHE_LINESIZE
104
105 @ r0 va2pa r10
106 mov r9, #PAGE_SZ
107 sub r9, r9, #1 @ PAGE_MASK
108101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA
109 b 103f
110102: cand.a r0, r9
111 beq 101b
112
113103: movc p0.c5, r10, #11 @ Dcache clean line of R10
114 nop8
115
116 add r0, r0, #CACHE_LINESIZE
117 add r10, r10, #CACHE_LINESIZE
118 sub.a r1, r1, #CACHE_LINESIZE
119 bns 102b
120 b 3f
121#endif
1222: mov ip, #0
123 movc p0.c5, ip, #10 @ Dcache clean all
124 nop8
125
1263: mov ip, #0
127 movc p0.c5, ip, #20 @ Icache invalidate all
128 nop8
129
130 mov pc, lr
131
132/*
133 * __cpuc_flush_kern_dcache_area(void *addr, size_t size)
134 *
135 * - addr - kernel address
136 * - size - region size
137 */
138ENTRY(__cpuc_flush_kern_dcache_area)
139 mov ip, #0
140 movc p0.c5, ip, #14 @ Dcache flush all
141 nop8
142 mov pc, lr
143
144/*
145 * __cpuc_dma_clean_range(start,end)
146 * - start - virtual start address of region
147 * - end - virtual end address of region
148 */
149ENTRY(__cpuc_dma_clean_range)
150#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
151 andn r0, r0, #CACHE_LINESIZE - 1
152 sub r1, r1, r0
153 andn r1, r1, #CACHE_LINESIZE - 1
154 add r1, r1, #CACHE_LINESIZE
155
156 csub.a r1, #MAX_AREA_SIZE
157 bsg 2f
158
159 @ r0 va2pa r10
160 mov r9, #PAGE_SZ
161 sub r9, r9, #1 @ PAGE_MASK
162101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA
163 b 1f
164102: cand.a r0, r9
165 beq 101b
166
1671: movc p0.c5, r10, #11 @ Dcache clean line of R10
168 nop8
169 add r0, r0, #CACHE_LINESIZE
170 add r10, r10, #CACHE_LINESIZE
171 sub.a r1, r1, #CACHE_LINESIZE
172 bns 102b
173 mov pc, lr
174#endif
1752: mov ip, #0
176 movc p0.c5, ip, #10 @ Dcache clean all
177 nop8
178
179 mov pc, lr
180
181/*
182 * __cpuc_dma_inv_range(start,end)
183 * __cpuc_dma_flush_range(start,end)
184 * - start - virtual start address of region
185 * - end - virtual end address of region
186 */
187__cpuc_dma_inv_range:
188 /* FALLTHROUGH */
189ENTRY(__cpuc_dma_flush_range)
190#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
191 andn r0, r0, #CACHE_LINESIZE - 1
192 sub r1, r1, r0
193 andn r1, r1, #CACHE_LINESIZE - 1
194 add r1, r1, #CACHE_LINESIZE
195
196 csub.a r1, #MAX_AREA_SIZE
197 bsg 2f
198
199 @ r0 va2pa r10
200101: dcacheline_flush r0, r11, r12
201
202 add r0, r0, #CACHE_LINESIZE
203 sub.a r1, r1, #CACHE_LINESIZE
204 bns 101b
205 mov pc, lr
206#endif
2072: mov ip, #0
208 movc p0.c5, ip, #14 @ Dcache flush all
209 nop8
210
211 mov pc, lr
212
diff --git a/arch/unicore32/mm/dma-swiotlb.c b/arch/unicore32/mm/dma-swiotlb.c
new file mode 100644
index 00000000000..bfa9fbb2bbb
--- /dev/null
+++ b/arch/unicore32/mm/dma-swiotlb.c
@@ -0,0 +1,34 @@
1/*
2 * Contains routines needed to support swiotlb for UniCore32.
3 *
4 * Copyright (C) 2010 Guan Xuetao
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11#include <linux/pci.h>
12#include <linux/cache.h>
13#include <linux/module.h>
14#include <linux/dma-mapping.h>
15#include <linux/swiotlb.h>
16#include <linux/bootmem.h>
17
18#include <asm/dma.h>
19
20struct dma_map_ops swiotlb_dma_map_ops = {
21 .alloc_coherent = swiotlb_alloc_coherent,
22 .free_coherent = swiotlb_free_coherent,
23 .map_sg = swiotlb_map_sg_attrs,
24 .unmap_sg = swiotlb_unmap_sg_attrs,
25 .dma_supported = swiotlb_dma_supported,
26 .map_page = swiotlb_map_page,
27 .unmap_page = swiotlb_unmap_page,
28 .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
29 .sync_single_for_device = swiotlb_sync_single_for_device,
30 .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
31 .sync_sg_for_device = swiotlb_sync_sg_for_device,
32 .mapping_error = swiotlb_dma_mapping_error,
33};
34EXPORT_SYMBOL(swiotlb_dma_map_ops);
diff --git a/arch/unicore32/mm/extable.c b/arch/unicore32/mm/extable.c
new file mode 100644
index 00000000000..6564180eb28
--- /dev/null
+++ b/arch/unicore32/mm/extable.c
@@ -0,0 +1,24 @@
1/*
2 * linux/arch/unicore32/mm/extable.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/uaccess.h>
14
15int fixup_exception(struct pt_regs *regs)
16{
17 const struct exception_table_entry *fixup;
18
19 fixup = search_exception_tables(instruction_pointer(regs));
20 if (fixup)
21 regs->UCreg_pc = fixup->fixup;
22
23 return fixup != NULL;
24}
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
new file mode 100644
index 00000000000..283aa4b50b7
--- /dev/null
+++ b/arch/unicore32/mm/fault.c
@@ -0,0 +1,479 @@
1/*
2 * linux/arch/unicore32/mm/fault.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/signal.h>
14#include <linux/mm.h>
15#include <linux/hardirq.h>
16#include <linux/init.h>
17#include <linux/kprobes.h>
18#include <linux/uaccess.h>
19#include <linux/page-flags.h>
20#include <linux/sched.h>
21#include <linux/io.h>
22
23#include <asm/system.h>
24#include <asm/pgtable.h>
25#include <asm/tlbflush.h>
26
27/*
28 * Fault status register encodings. We steal bit 31 for our own purposes.
29 */
30#define FSR_LNX_PF (1 << 31)
31
32static inline int fsr_fs(unsigned int fsr)
33{
34 /* xyabcde will be abcde+xy */
35 return (fsr & 31) + ((fsr & (3 << 5)) >> 5);
36}
37
38/*
39 * This is useful to dump out the page tables associated with
40 * 'addr' in mm 'mm'.
41 */
42void show_pte(struct mm_struct *mm, unsigned long addr)
43{
44 pgd_t *pgd;
45
46 if (!mm)
47 mm = &init_mm;
48
49 printk(KERN_ALERT "pgd = %p\n", mm->pgd);
50 pgd = pgd_offset(mm, addr);
51 printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
52
53 do {
54 pmd_t *pmd;
55 pte_t *pte;
56
57 if (pgd_none(*pgd))
58 break;
59
60 if (pgd_bad(*pgd)) {
61 printk("(bad)");
62 break;
63 }
64
65 pmd = pmd_offset((pud_t *) pgd, addr);
66 if (PTRS_PER_PMD != 1)
67 printk(", *pmd=%08lx", pmd_val(*pmd));
68
69 if (pmd_none(*pmd))
70 break;
71
72 if (pmd_bad(*pmd)) {
73 printk("(bad)");
74 break;
75 }
76
77 /* We must not map this if we have highmem enabled */
78 if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
79 break;
80
81 pte = pte_offset_map(pmd, addr);
82 printk(", *pte=%08lx", pte_val(*pte));
83 pte_unmap(pte);
84 } while (0);
85
86 printk("\n");
87}
88
89/*
90 * Oops. The kernel tried to access some page that wasn't present.
91 */
92static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr,
93 unsigned int fsr, struct pt_regs *regs)
94{
95 /*
96 * Are we prepared to handle this kernel fault?
97 */
98 if (fixup_exception(regs))
99 return;
100
101 /*
102 * No handler, we'll have to terminate things with extreme prejudice.
103 */
104 bust_spinlocks(1);
105 printk(KERN_ALERT
106 "Unable to handle kernel %s at virtual address %08lx\n",
107 (addr < PAGE_SIZE) ? "NULL pointer dereference" :
108 "paging request", addr);
109
110 show_pte(mm, addr);
111 die("Oops", regs, fsr);
112 bust_spinlocks(0);
113 do_exit(SIGKILL);
114}
115
116/*
117 * Something tried to access memory that isn't in our memory map..
118 * User mode accesses just cause a SIGSEGV
119 */
120static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
121 unsigned int fsr, unsigned int sig, int code,
122 struct pt_regs *regs)
123{
124 struct siginfo si;
125
126 tsk->thread.address = addr;
127 tsk->thread.error_code = fsr;
128 tsk->thread.trap_no = 14;
129 si.si_signo = sig;
130 si.si_errno = 0;
131 si.si_code = code;
132 si.si_addr = (void __user *)addr;
133 force_sig_info(sig, &si, tsk);
134}
135
136void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
137{
138 struct task_struct *tsk = current;
139 struct mm_struct *mm = tsk->active_mm;
140
141 /*
142 * If we are in kernel mode at this point, we
143 * have no context to handle this fault with.
144 */
145 if (user_mode(regs))
146 __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
147 else
148 __do_kernel_fault(mm, addr, fsr, regs);
149}
150
151#define VM_FAULT_BADMAP 0x010000
152#define VM_FAULT_BADACCESS 0x020000
153
154/*
155 * Check that the permissions on the VMA allow for the fault which occurred.
156 * If we encountered a write fault, we must have write permission, otherwise
157 * we allow any permission.
158 */
159static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
160{
161 unsigned int mask = VM_READ | VM_WRITE | VM_EXEC;
162
163 if (!(fsr ^ 0x12)) /* write? */
164 mask = VM_WRITE;
165 if (fsr & FSR_LNX_PF)
166 mask = VM_EXEC;
167
168 return vma->vm_flags & mask ? false : true;
169}
170
171static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
172 struct task_struct *tsk)
173{
174 struct vm_area_struct *vma;
175 int fault;
176
177 vma = find_vma(mm, addr);
178 fault = VM_FAULT_BADMAP;
179 if (unlikely(!vma))
180 goto out;
181 if (unlikely(vma->vm_start > addr))
182 goto check_stack;
183
184 /*
185 * Ok, we have a good vm_area for this
186 * memory access, so we can handle it.
187 */
188good_area:
189 if (access_error(fsr, vma)) {
190 fault = VM_FAULT_BADACCESS;
191 goto out;
192 }
193
194 /*
195 * If for any reason at all we couldn't handle the fault, make
196 * sure we exit gracefully rather than endlessly redo the fault.
197 */
198 fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,
199 (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
200 if (unlikely(fault & VM_FAULT_ERROR))
201 return fault;
202 if (fault & VM_FAULT_MAJOR)
203 tsk->maj_flt++;
204 else
205 tsk->min_flt++;
206 return fault;
207
208check_stack:
209 if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
210 goto good_area;
211out:
212 return fault;
213}
214
215static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
216{
217 struct task_struct *tsk;
218 struct mm_struct *mm;
219 int fault, sig, code;
220
221 tsk = current;
222 mm = tsk->mm;
223
224 /*
225 * If we're in an interrupt or have no user
226 * context, we must not take the fault..
227 */
228 if (in_atomic() || !mm)
229 goto no_context;
230
231 /*
232 * As per x86, we may deadlock here. However, since the kernel only
233 * validly references user space from well defined areas of the code,
234 * we can bug out early if this is from code which shouldn't.
235 */
236 if (!down_read_trylock(&mm->mmap_sem)) {
237 if (!user_mode(regs)
238 && !search_exception_tables(regs->UCreg_pc))
239 goto no_context;
240 down_read(&mm->mmap_sem);
241 } else {
242 /*
243 * The above down_read_trylock() might have succeeded in
244 * which case, we'll have missed the might_sleep() from
245 * down_read()
246 */
247 might_sleep();
248#ifdef CONFIG_DEBUG_VM
249 if (!user_mode(regs) &&
250 !search_exception_tables(regs->UCreg_pc))
251 goto no_context;
252#endif
253 }
254
255 fault = __do_pf(mm, addr, fsr, tsk);
256 up_read(&mm->mmap_sem);
257
258 /*
259 * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
260 */
261 if (likely(!(fault &
262 (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
263 return 0;
264
265 if (fault & VM_FAULT_OOM) {
266 /*
267 * We ran out of memory, call the OOM killer, and return to
268 * userspace (which will retry the fault, or kill us if we
269 * got oom-killed)
270 */
271 pagefault_out_of_memory();
272 return 0;
273 }
274
275 /*
276 * If we are in kernel mode at this point, we
277 * have no context to handle this fault with.
278 */
279 if (!user_mode(regs))
280 goto no_context;
281
282 if (fault & VM_FAULT_SIGBUS) {
283 /*
284 * We had some memory, but were unable to
285 * successfully fix up this page fault.
286 */
287 sig = SIGBUS;
288 code = BUS_ADRERR;
289 } else {
290 /*
291 * Something tried to access memory that
292 * isn't in our memory map..
293 */
294 sig = SIGSEGV;
295 code = fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR;
296 }
297
298 __do_user_fault(tsk, addr, fsr, sig, code, regs);
299 return 0;
300
301no_context:
302 __do_kernel_fault(mm, addr, fsr, regs);
303 return 0;
304}
305
306/*
307 * First Level Translation Fault Handler
308 *
309 * We enter here because the first level page table doesn't contain
310 * a valid entry for the address.
311 *
312 * If the address is in kernel space (>= TASK_SIZE), then we are
313 * probably faulting in the vmalloc() area.
314 *
315 * If the init_task's first level page tables contains the relevant
316 * entry, we copy the it to this task. If not, we send the process
317 * a signal, fixup the exception, or oops the kernel.
318 *
319 * NOTE! We MUST NOT take any locks for this case. We may be in an
320 * interrupt or a critical region, and should only copy the information
321 * from the master page table, nothing more.
322 */
323static int do_ifault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
324{
325 unsigned int index;
326 pgd_t *pgd, *pgd_k;
327 pmd_t *pmd, *pmd_k;
328
329 if (addr < TASK_SIZE)
330 return do_pf(addr, fsr, regs);
331
332 if (user_mode(regs))
333 goto bad_area;
334
335 index = pgd_index(addr);
336
337 pgd = cpu_get_pgd() + index;
338 pgd_k = init_mm.pgd + index;
339
340 if (pgd_none(*pgd_k))
341 goto bad_area;
342
343 pmd_k = pmd_offset((pud_t *) pgd_k, addr);
344 pmd = pmd_offset((pud_t *) pgd, addr);
345
346 if (pmd_none(*pmd_k))
347 goto bad_area;
348
349 set_pmd(pmd, *pmd_k);
350 flush_pmd_entry(pmd);
351 return 0;
352
353bad_area:
354 do_bad_area(addr, fsr, regs);
355 return 0;
356}
357
358/*
359 * This abort handler always returns "fault".
360 */
361static int do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
362{
363 return 1;
364}
365
366static int do_good(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
367{
368 unsigned int res1, res2;
369
370 printk("dabt exception but no error!\n");
371
372 __asm__ __volatile__(
373 "mff %0,f0\n"
374 "mff %1,f1\n"
375 : "=r"(res1), "=r"(res2)
376 :
377 : "memory");
378
379 printk(KERN_EMERG "r0 :%08x r1 :%08x\n", res1, res2);
380 panic("shut up\n");
381 return 0;
382}
383
384static struct fsr_info {
385 int (*fn) (unsigned long addr, unsigned int fsr, struct pt_regs *regs);
386 int sig;
387 int code;
388 const char *name;
389} fsr_info[] = {
390 /*
391 * The following are the standard Unicore-I and UniCore-II aborts.
392 */
393 { do_good, SIGBUS, 0, "no error" },
394 { do_bad, SIGBUS, BUS_ADRALN, "alignment exception" },
395 { do_bad, SIGBUS, BUS_OBJERR, "external exception" },
396 { do_bad, SIGBUS, 0, "burst operation" },
397 { do_bad, SIGBUS, 0, "unknown 00100" },
398 { do_ifault, SIGSEGV, SEGV_MAPERR, "2nd level pt non-exist"},
399 { do_bad, SIGBUS, 0, "2nd lvl large pt non-exist" },
400 { do_bad, SIGBUS, 0, "invalid pte" },
401 { do_pf, SIGSEGV, SEGV_MAPERR, "page miss" },
402 { do_bad, SIGBUS, 0, "middle page miss" },
403 { do_bad, SIGBUS, 0, "large page miss" },
404 { do_pf, SIGSEGV, SEGV_MAPERR, "super page (section) miss" },
405 { do_bad, SIGBUS, 0, "unknown 01100" },
406 { do_bad, SIGBUS, 0, "unknown 01101" },
407 { do_bad, SIGBUS, 0, "unknown 01110" },
408 { do_bad, SIGBUS, 0, "unknown 01111" },
409 { do_bad, SIGBUS, 0, "addr: up 3G or IO" },
410 { do_pf, SIGSEGV, SEGV_ACCERR, "read unreadable addr" },
411 { do_pf, SIGSEGV, SEGV_ACCERR, "write unwriteable addr"},
412 { do_pf, SIGSEGV, SEGV_ACCERR, "exec unexecutable addr"},
413 { do_bad, SIGBUS, 0, "unknown 10100" },
414 { do_bad, SIGBUS, 0, "unknown 10101" },
415 { do_bad, SIGBUS, 0, "unknown 10110" },
416 { do_bad, SIGBUS, 0, "unknown 10111" },
417 { do_bad, SIGBUS, 0, "unknown 11000" },
418 { do_bad, SIGBUS, 0, "unknown 11001" },
419 { do_bad, SIGBUS, 0, "unknown 11010" },
420 { do_bad, SIGBUS, 0, "unknown 11011" },
421 { do_bad, SIGBUS, 0, "unknown 11100" },
422 { do_bad, SIGBUS, 0, "unknown 11101" },
423 { do_bad, SIGBUS, 0, "unknown 11110" },
424 { do_bad, SIGBUS, 0, "unknown 11111" }
425};
426
427void __init hook_fault_code(int nr,
428 int (*fn) (unsigned long, unsigned int, struct pt_regs *),
429 int sig, int code, const char *name)
430{
431 if (nr < 0 || nr >= ARRAY_SIZE(fsr_info))
432 BUG();
433
434 fsr_info[nr].fn = fn;
435 fsr_info[nr].sig = sig;
436 fsr_info[nr].code = code;
437 fsr_info[nr].name = name;
438}
439
440/*
441 * Dispatch a data abort to the relevant handler.
442 */
443asmlinkage void do_DataAbort(unsigned long addr, unsigned int fsr,
444 struct pt_regs *regs)
445{
446 const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
447 struct siginfo info;
448
449 if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
450 return;
451
452 printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
453 inf->name, fsr, addr);
454
455 info.si_signo = inf->sig;
456 info.si_errno = 0;
457 info.si_code = inf->code;
458 info.si_addr = (void __user *)addr;
459 uc32_notify_die("", regs, &info, fsr, 0);
460}
461
462asmlinkage void do_PrefetchAbort(unsigned long addr,
463 unsigned int ifsr, struct pt_regs *regs)
464{
465 const struct fsr_info *inf = fsr_info + fsr_fs(ifsr);
466 struct siginfo info;
467
468 if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
469 return;
470
471 printk(KERN_ALERT "Unhandled prefetch abort: %s (0x%03x) at 0x%08lx\n",
472 inf->name, ifsr, addr);
473
474 info.si_signo = inf->sig;
475 info.si_errno = 0;
476 info.si_code = inf->code;
477 info.si_addr = (void __user *)addr;
478 uc32_notify_die("", regs, &info, ifsr, 0);
479}
diff --git a/arch/unicore32/mm/flush.c b/arch/unicore32/mm/flush.c
new file mode 100644
index 00000000000..93478cc8b26
--- /dev/null
+++ b/arch/unicore32/mm/flush.c
@@ -0,0 +1,98 @@
1/*
2 * linux/arch/unicore32/mm/flush.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/mm.h>
14#include <linux/pagemap.h>
15
16#include <asm/cacheflush.h>
17#include <asm/system.h>
18#include <asm/tlbflush.h>
19
20void flush_cache_mm(struct mm_struct *mm)
21{
22}
23
24void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
25 unsigned long end)
26{
27 if (vma->vm_flags & VM_EXEC)
28 __flush_icache_all();
29}
30
31void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr,
32 unsigned long pfn)
33{
34}
35
36static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
37 unsigned long uaddr, void *kaddr, unsigned long len)
38{
39 /* VIPT non-aliasing D-cache */
40 if (vma->vm_flags & VM_EXEC) {
41 unsigned long addr = (unsigned long)kaddr;
42
43 __cpuc_coherent_kern_range(addr, addr + len);
44 }
45}
46
47/*
48 * Copy user data from/to a page which is mapped into a different
49 * processes address space. Really, we want to allow our "user
50 * space" model to handle this.
51 *
52 * Note that this code needs to run on the current CPU.
53 */
54void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
55 unsigned long uaddr, void *dst, const void *src,
56 unsigned long len)
57{
58 memcpy(dst, src, len);
59 flush_ptrace_access(vma, page, uaddr, dst, len);
60}
61
62void __flush_dcache_page(struct address_space *mapping, struct page *page)
63{
64 /*
65 * Writeback any data associated with the kernel mapping of this
66 * page. This ensures that data in the physical page is mutually
67 * coherent with the kernels mapping.
68 */
69 __cpuc_flush_kern_dcache_area(page_address(page), PAGE_SIZE);
70}
71
72/*
73 * Ensure cache coherency between kernel mapping and userspace mapping
74 * of this page.
75 */
76void flush_dcache_page(struct page *page)
77{
78 struct address_space *mapping;
79
80 /*
81 * The zero page is never written to, so never has any dirty
82 * cache lines, and therefore never needs to be flushed.
83 */
84 if (page == ZERO_PAGE(0))
85 return;
86
87 mapping = page_mapping(page);
88
89 if (mapping && !mapping_mapped(mapping))
90 clear_bit(PG_dcache_clean, &page->flags);
91 else {
92 __flush_dcache_page(mapping, page);
93 if (mapping)
94 __flush_icache_all();
95 set_bit(PG_dcache_clean, &page->flags);
96 }
97}
98EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c
new file mode 100644
index 00000000000..3dbe3709b69
--- /dev/null
+++ b/arch/unicore32/mm/init.c
@@ -0,0 +1,517 @@
1/*
2 * linux/arch/unicore32/mm/init.c
3 *
4 * Copyright (C) 2010 GUAN Xue-tao
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/kernel.h>
11#include <linux/errno.h>
12#include <linux/swap.h>
13#include <linux/init.h>
14#include <linux/bootmem.h>
15#include <linux/mman.h>
16#include <linux/nodemask.h>
17#include <linux/initrd.h>
18#include <linux/highmem.h>
19#include <linux/gfp.h>
20#include <linux/memblock.h>
21#include <linux/sort.h>
22#include <linux/dma-mapping.h>
23
24#include <asm/sections.h>
25#include <asm/setup.h>
26#include <asm/sizes.h>
27#include <asm/tlb.h>
28#include <mach/map.h>
29
30#include "mm.h"
31
32static unsigned long phys_initrd_start __initdata = 0x01000000;
33static unsigned long phys_initrd_size __initdata = SZ_8M;
34
35static int __init early_initrd(char *p)
36{
37 unsigned long start, size;
38 char *endp;
39
40 start = memparse(p, &endp);
41 if (*endp == ',') {
42 size = memparse(endp + 1, NULL);
43
44 phys_initrd_start = start;
45 phys_initrd_size = size;
46 }
47 return 0;
48}
49early_param("initrd", early_initrd);
50
51/*
52 * This keeps memory configuration data used by a couple memory
53 * initialization functions, as well as show_mem() for the skipping
54 * of holes in the memory map. It is populated by uc32_add_memory().
55 */
56struct meminfo meminfo;
57
58void show_mem(void)
59{
60 int free = 0, total = 0, reserved = 0;
61 int shared = 0, cached = 0, slab = 0, i;
62 struct meminfo *mi = &meminfo;
63
64 printk(KERN_DEFAULT "Mem-info:\n");
65 show_free_areas();
66
67 for_each_bank(i, mi) {
68 struct membank *bank = &mi->bank[i];
69 unsigned int pfn1, pfn2;
70 struct page *page, *end;
71
72 pfn1 = bank_pfn_start(bank);
73 pfn2 = bank_pfn_end(bank);
74
75 page = pfn_to_page(pfn1);
76 end = pfn_to_page(pfn2 - 1) + 1;
77
78 do {
79 total++;
80 if (PageReserved(page))
81 reserved++;
82 else if (PageSwapCache(page))
83 cached++;
84 else if (PageSlab(page))
85 slab++;
86 else if (!page_count(page))
87 free++;
88 else
89 shared += page_count(page) - 1;
90 page++;
91 } while (page < end);
92 }
93
94 printk(KERN_DEFAULT "%d pages of RAM\n", total);
95 printk(KERN_DEFAULT "%d free pages\n", free);
96 printk(KERN_DEFAULT "%d reserved pages\n", reserved);
97 printk(KERN_DEFAULT "%d slab pages\n", slab);
98 printk(KERN_DEFAULT "%d pages shared\n", shared);
99 printk(KERN_DEFAULT "%d pages swap cached\n", cached);
100}
101
102static void __init find_limits(unsigned long *min, unsigned long *max_low,
103 unsigned long *max_high)
104{
105 struct meminfo *mi = &meminfo;
106 int i;
107
108 *min = -1UL;
109 *max_low = *max_high = 0;
110
111 for_each_bank(i, mi) {
112 struct membank *bank = &mi->bank[i];
113 unsigned long start, end;
114
115 start = bank_pfn_start(bank);
116 end = bank_pfn_end(bank);
117
118 if (*min > start)
119 *min = start;
120 if (*max_high < end)
121 *max_high = end;
122 if (bank->highmem)
123 continue;
124 if (*max_low < end)
125 *max_low = end;
126 }
127}
128
129static void __init uc32_bootmem_init(unsigned long start_pfn,
130 unsigned long end_pfn)
131{
132 struct memblock_region *reg;
133 unsigned int boot_pages;
134 phys_addr_t bitmap;
135 pg_data_t *pgdat;
136
137 /*
138 * Allocate the bootmem bitmap page. This must be in a region
139 * of memory which has already been mapped.
140 */
141 boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
142 bitmap = memblock_alloc_base(boot_pages << PAGE_SHIFT, L1_CACHE_BYTES,
143 __pfn_to_phys(end_pfn));
144
145 /*
146 * Initialise the bootmem allocator, handing the
147 * memory banks over to bootmem.
148 */
149 node_set_online(0);
150 pgdat = NODE_DATA(0);
151 init_bootmem_node(pgdat, __phys_to_pfn(bitmap), start_pfn, end_pfn);
152
153 /* Free the lowmem regions from memblock into bootmem. */
154 for_each_memblock(memory, reg) {
155 unsigned long start = memblock_region_memory_base_pfn(reg);
156 unsigned long end = memblock_region_memory_end_pfn(reg);
157
158 if (end >= end_pfn)
159 end = end_pfn;
160 if (start >= end)
161 break;
162
163 free_bootmem(__pfn_to_phys(start), (end - start) << PAGE_SHIFT);
164 }
165
166 /* Reserve the lowmem memblock reserved regions in bootmem. */
167 for_each_memblock(reserved, reg) {
168 unsigned long start = memblock_region_reserved_base_pfn(reg);
169 unsigned long end = memblock_region_reserved_end_pfn(reg);
170
171 if (end >= end_pfn)
172 end = end_pfn;
173 if (start >= end)
174 break;
175
176 reserve_bootmem(__pfn_to_phys(start),
177 (end - start) << PAGE_SHIFT, BOOTMEM_DEFAULT);
178 }
179}
180
181static void __init uc32_bootmem_free(unsigned long min, unsigned long max_low,
182 unsigned long max_high)
183{
184 unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
185 struct memblock_region *reg;
186
187 /*
188 * initialise the zones.
189 */
190 memset(zone_size, 0, sizeof(zone_size));
191
192 /*
193 * The memory size has already been determined. If we need
194 * to do anything fancy with the allocation of this memory
195 * to the zones, now is the time to do it.
196 */
197 zone_size[0] = max_low - min;
198
199 /*
200 * Calculate the size of the holes.
201 * holes = node_size - sum(bank_sizes)
202 */
203 memcpy(zhole_size, zone_size, sizeof(zhole_size));
204 for_each_memblock(memory, reg) {
205 unsigned long start = memblock_region_memory_base_pfn(reg);
206 unsigned long end = memblock_region_memory_end_pfn(reg);
207
208 if (start < max_low) {
209 unsigned long low_end = min(end, max_low);
210 zhole_size[0] -= low_end - start;
211 }
212 }
213
214 /*
215 * Adjust the sizes according to any special requirements for
216 * this machine type.
217 */
218 arch_adjust_zones(zone_size, zhole_size);
219
220 free_area_init_node(0, zone_size, min, zhole_size);
221}
222
223int pfn_valid(unsigned long pfn)
224{
225 return memblock_is_memory(pfn << PAGE_SHIFT);
226}
227EXPORT_SYMBOL(pfn_valid);
228
229static void uc32_memory_present(void)
230{
231}
232
233static int __init meminfo_cmp(const void *_a, const void *_b)
234{
235 const struct membank *a = _a, *b = _b;
236 long cmp = bank_pfn_start(a) - bank_pfn_start(b);
237 return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
238}
239
240void __init uc32_memblock_init(struct meminfo *mi)
241{
242 int i;
243
244 sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]),
245 meminfo_cmp, NULL);
246
247 memblock_init();
248 for (i = 0; i < mi->nr_banks; i++)
249 memblock_add(mi->bank[i].start, mi->bank[i].size);
250
251 /* Register the kernel text, kernel data and initrd with memblock. */
252 memblock_reserve(__pa(_text), _end - _text);
253
254#ifdef CONFIG_BLK_DEV_INITRD
255 if (phys_initrd_size) {
256 memblock_reserve(phys_initrd_start, phys_initrd_size);
257
258 /* Now convert initrd to virtual addresses */
259 initrd_start = __phys_to_virt(phys_initrd_start);
260 initrd_end = initrd_start + phys_initrd_size;
261 }
262#endif
263
264 uc32_mm_memblock_reserve();
265
266 memblock_analyze();
267 memblock_dump_all();
268}
269
270void __init bootmem_init(void)
271{
272 unsigned long min, max_low, max_high;
273
274 max_low = max_high = 0;
275
276 find_limits(&min, &max_low, &max_high);
277
278 uc32_bootmem_init(min, max_low);
279
280#ifdef CONFIG_SWIOTLB
281 swiotlb_init(1);
282#endif
283 /*
284 * Sparsemem tries to allocate bootmem in memory_present(),
285 * so must be done after the fixed reservations
286 */
287 uc32_memory_present();
288
289 /*
290 * sparse_init() needs the bootmem allocator up and running.
291 */
292 sparse_init();
293
294 /*
295 * Now free the memory - free_area_init_node needs
296 * the sparse mem_map arrays initialized by sparse_init()
297 * for memmap_init_zone(), otherwise all PFNs are invalid.
298 */
299 uc32_bootmem_free(min, max_low, max_high);
300
301 high_memory = __va((max_low << PAGE_SHIFT) - 1) + 1;
302
303 /*
304 * This doesn't seem to be used by the Linux memory manager any
305 * more, but is used by ll_rw_block. If we can get rid of it, we
306 * also get rid of some of the stuff above as well.
307 *
308 * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
309 * the system, not the maximum PFN.
310 */
311 max_low_pfn = max_low - PHYS_PFN_OFFSET;
312 max_pfn = max_high - PHYS_PFN_OFFSET;
313}
314
315static inline int free_area(unsigned long pfn, unsigned long end, char *s)
316{
317 unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
318
319 for (; pfn < end; pfn++) {
320 struct page *page = pfn_to_page(pfn);
321 ClearPageReserved(page);
322 init_page_count(page);
323 __free_page(page);
324 pages++;
325 }
326
327 if (size && s)
328 printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
329
330 return pages;
331}
332
333static inline void
334free_memmap(unsigned long start_pfn, unsigned long end_pfn)
335{
336 struct page *start_pg, *end_pg;
337 unsigned long pg, pgend;
338
339 /*
340 * Convert start_pfn/end_pfn to a struct page pointer.
341 */
342 start_pg = pfn_to_page(start_pfn - 1) + 1;
343 end_pg = pfn_to_page(end_pfn);
344
345 /*
346 * Convert to physical addresses, and
347 * round start upwards and end downwards.
348 */
349 pg = PAGE_ALIGN(__pa(start_pg));
350 pgend = __pa(end_pg) & PAGE_MASK;
351
352 /*
353 * If there are free pages between these,
354 * free the section of the memmap array.
355 */
356 if (pg < pgend)
357 free_bootmem(pg, pgend - pg);
358}
359
360/*
361 * The mem_map array can get very big. Free the unused area of the memory map.
362 */
363static void __init free_unused_memmap(struct meminfo *mi)
364{
365 unsigned long bank_start, prev_bank_end = 0;
366 unsigned int i;
367
368 /*
369 * This relies on each bank being in address order.
370 * The banks are sorted previously in bootmem_init().
371 */
372 for_each_bank(i, mi) {
373 struct membank *bank = &mi->bank[i];
374
375 bank_start = bank_pfn_start(bank);
376
377 /*
378 * If we had a previous bank, and there is a space
379 * between the current bank and the previous, free it.
380 */
381 if (prev_bank_end && prev_bank_end < bank_start)
382 free_memmap(prev_bank_end, bank_start);
383
384 /*
385 * Align up here since the VM subsystem insists that the
386 * memmap entries are valid from the bank end aligned to
387 * MAX_ORDER_NR_PAGES.
388 */
389 prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
390 }
391}
392
393/*
394 * mem_init() marks the free areas in the mem_map and tells us how much
395 * memory is free. This is done after various parts of the system have
396 * claimed their memory after the kernel image.
397 */
398void __init mem_init(void)
399{
400 unsigned long reserved_pages, free_pages;
401 struct memblock_region *reg;
402 int i;
403
404 max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
405
406 /* this will put all unused low memory onto the freelists */
407 free_unused_memmap(&meminfo);
408
409 totalram_pages += free_all_bootmem();
410
411 reserved_pages = free_pages = 0;
412
413 for_each_bank(i, &meminfo) {
414 struct membank *bank = &meminfo.bank[i];
415 unsigned int pfn1, pfn2;
416 struct page *page, *end;
417
418 pfn1 = bank_pfn_start(bank);
419 pfn2 = bank_pfn_end(bank);
420
421 page = pfn_to_page(pfn1);
422 end = pfn_to_page(pfn2 - 1) + 1;
423
424 do {
425 if (PageReserved(page))
426 reserved_pages++;
427 else if (!page_count(page))
428 free_pages++;
429 page++;
430 } while (page < end);
431 }
432
433 /*
434 * Since our memory may not be contiguous, calculate the
435 * real number of pages we have in this system
436 */
437 printk(KERN_INFO "Memory:");
438 num_physpages = 0;
439 for_each_memblock(memory, reg) {
440 unsigned long pages = memblock_region_memory_end_pfn(reg) -
441 memblock_region_memory_base_pfn(reg);
442 num_physpages += pages;
443 printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
444 }
445 printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
446
447 printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
448 nr_free_pages() << (PAGE_SHIFT-10),
449 free_pages << (PAGE_SHIFT-10),
450 reserved_pages << (PAGE_SHIFT-10),
451 totalhigh_pages << (PAGE_SHIFT-10));
452
453 printk(KERN_NOTICE "Virtual kernel memory layout:\n"
454 " vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
455 " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
456 " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
457 " modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
458 " .init : 0x%p" " - 0x%p" " (%4d kB)\n"
459 " .text : 0x%p" " - 0x%p" " (%4d kB)\n"
460 " .data : 0x%p" " - 0x%p" " (%4d kB)\n",
461
462 VECTORS_BASE, VECTORS_BASE + PAGE_SIZE,
463 DIV_ROUND_UP(PAGE_SIZE, SZ_1K),
464 VMALLOC_START, VMALLOC_END,
465 DIV_ROUND_UP((VMALLOC_END - VMALLOC_START), SZ_1M),
466 PAGE_OFFSET, (unsigned long)high_memory,
467 DIV_ROUND_UP(((unsigned long)high_memory - PAGE_OFFSET), SZ_1M),
468 MODULES_VADDR, MODULES_END,
469 DIV_ROUND_UP((MODULES_END - MODULES_VADDR), SZ_1M),
470
471 __init_begin, __init_end,
472 DIV_ROUND_UP((__init_end - __init_begin), SZ_1K),
473 _stext, _etext,
474 DIV_ROUND_UP((_etext - _stext), SZ_1K),
475 _sdata, _edata,
476 DIV_ROUND_UP((_edata - _sdata), SZ_1K));
477
478 BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
479 BUG_ON(TASK_SIZE > MODULES_VADDR);
480
481 if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
482 /*
483 * On a machine this small we won't get
484 * anywhere without overcommit, so turn
485 * it on by default.
486 */
487 sysctl_overcommit_memory = OVERCOMMIT_ALWAYS;
488 }
489}
490
491void free_initmem(void)
492{
493 totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
494 __phys_to_pfn(__pa(__init_end)),
495 "init");
496}
497
498#ifdef CONFIG_BLK_DEV_INITRD
499
500static int keep_initrd;
501
502void free_initrd_mem(unsigned long start, unsigned long end)
503{
504 if (!keep_initrd)
505 totalram_pages += free_area(__phys_to_pfn(__pa(start)),
506 __phys_to_pfn(__pa(end)),
507 "initrd");
508}
509
510static int __init keepinitrd_setup(char *__unused)
511{
512 keep_initrd = 1;
513 return 1;
514}
515
516__setup("keepinitrd", keepinitrd_setup);
517#endif
diff --git a/arch/unicore32/mm/ioremap.c b/arch/unicore32/mm/ioremap.c
new file mode 100644
index 00000000000..b7a605597b0
--- /dev/null
+++ b/arch/unicore32/mm/ioremap.c
@@ -0,0 +1,261 @@
1/*
2 * linux/arch/unicore32/mm/ioremap.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 *
13 * Re-map IO memory to kernel address space so that we can access it.
14 *
15 * This allows a driver to remap an arbitrary region of bus memory into
16 * virtual space. One should *only* use readl, writel, memcpy_toio and
17 * so on with such remapped areas.
18 *
19 * Because UniCore only has a 32-bit address space we can't address the
20 * whole of the (physical) PCI space at once. PCI huge-mode addressing
21 * allows us to circumvent this restriction by splitting PCI space into
22 * two 2GB chunks and mapping only one at a time into processor memory.
23 * We use MMU protection domains to trap any attempt to access the bank
24 * that is not currently mapped. (This isn't fully implemented yet.)
25 */
26#include <linux/module.h>
27#include <linux/errno.h>
28#include <linux/mm.h>
29#include <linux/vmalloc.h>
30#include <linux/io.h>
31
32#include <asm/cputype.h>
33#include <asm/cacheflush.h>
34#include <asm/mmu_context.h>
35#include <asm/pgalloc.h>
36#include <asm/tlbflush.h>
37#include <asm/sizes.h>
38
39#include <mach/map.h>
40#include "mm.h"
41
42/*
43 * Used by ioremap() and iounmap() code to mark (super)section-mapped
44 * I/O regions in vm_struct->flags field.
45 */
46#define VM_UNICORE_SECTION_MAPPING 0x80000000
47
48int ioremap_page(unsigned long virt, unsigned long phys,
49 const struct mem_type *mtype)
50{
51 return ioremap_page_range(virt, virt + PAGE_SIZE, phys,
52 __pgprot(mtype->prot_pte));
53}
54EXPORT_SYMBOL(ioremap_page);
55
56/*
57 * Section support is unsafe on SMP - If you iounmap and ioremap a region,
58 * the other CPUs will not see this change until their next context switch.
59 * Meanwhile, (eg) if an interrupt comes in on one of those other CPUs
60 * which requires the new ioremap'd region to be referenced, the CPU will
61 * reference the _old_ region.
62 *
63 * Note that get_vm_area_caller() allocates a guard 4K page, so we need to
64 * mask the size back to 4MB aligned or we will overflow in the loop below.
65 */
66static void unmap_area_sections(unsigned long virt, unsigned long size)
67{
68 unsigned long addr = virt, end = virt + (size & ~(SZ_4M - 1));
69 pgd_t *pgd;
70
71 flush_cache_vunmap(addr, end);
72 pgd = pgd_offset_k(addr);
73 do {
74 pmd_t pmd, *pmdp = pmd_offset((pud_t *)pgd, addr);
75
76 pmd = *pmdp;
77 if (!pmd_none(pmd)) {
78 /*
79 * Clear the PMD from the page table, and
80 * increment the kvm sequence so others
81 * notice this change.
82 *
83 * Note: this is still racy on SMP machines.
84 */
85 pmd_clear(pmdp);
86
87 /*
88 * Free the page table, if there was one.
89 */
90 if ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
91 pte_free_kernel(&init_mm, pmd_page_vaddr(pmd));
92 }
93
94 addr += PGDIR_SIZE;
95 pgd++;
96 } while (addr < end);
97
98 flush_tlb_kernel_range(virt, end);
99}
100
101static int
102remap_area_sections(unsigned long virt, unsigned long pfn,
103 size_t size, const struct mem_type *type)
104{
105 unsigned long addr = virt, end = virt + size;
106 pgd_t *pgd;
107
108 /*
109 * Remove and free any PTE-based mapping, and
110 * sync the current kernel mapping.
111 */
112 unmap_area_sections(virt, size);
113
114 pgd = pgd_offset_k(addr);
115 do {
116 pmd_t *pmd = pmd_offset((pud_t *)pgd, addr);
117
118 set_pmd(pmd, __pmd(__pfn_to_phys(pfn) | type->prot_sect));
119 pfn += SZ_4M >> PAGE_SHIFT;
120 flush_pmd_entry(pmd);
121
122 addr += PGDIR_SIZE;
123 pgd++;
124 } while (addr < end);
125
126 return 0;
127}
128
129void __iomem *__uc32_ioremap_pfn_caller(unsigned long pfn,
130 unsigned long offset, size_t size, unsigned int mtype, void *caller)
131{
132 const struct mem_type *type;
133 int err;
134 unsigned long addr;
135 struct vm_struct *area;
136
137 /*
138 * High mappings must be section aligned
139 */
140 if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SECTION_MASK))
141 return NULL;
142
143 /*
144 * Don't allow RAM to be mapped
145 */
146 if (pfn_valid(pfn)) {
147 printk(KERN_WARNING "BUG: Your driver calls ioremap() on\n"
148 "system memory. This leads to architecturally\n"
149 "unpredictable behaviour, and ioremap() will fail in\n"
150 "the next kernel release. Please fix your driver.\n");
151 WARN_ON(1);
152 }
153
154 type = get_mem_type(mtype);
155 if (!type)
156 return NULL;
157
158 /*
159 * Page align the mapping size, taking account of any offset.
160 */
161 size = PAGE_ALIGN(offset + size);
162
163 area = get_vm_area_caller(size, VM_IOREMAP, caller);
164 if (!area)
165 return NULL;
166 addr = (unsigned long)area->addr;
167
168 if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
169 area->flags |= VM_UNICORE_SECTION_MAPPING;
170 err = remap_area_sections(addr, pfn, size, type);
171 } else
172 err = ioremap_page_range(addr, addr + size, __pfn_to_phys(pfn),
173 __pgprot(type->prot_pte));
174
175 if (err) {
176 vunmap((void *)addr);
177 return NULL;
178 }
179
180 flush_cache_vmap(addr, addr + size);
181 return (void __iomem *) (offset + addr);
182}
183
184void __iomem *__uc32_ioremap_caller(unsigned long phys_addr, size_t size,
185 unsigned int mtype, void *caller)
186{
187 unsigned long last_addr;
188 unsigned long offset = phys_addr & ~PAGE_MASK;
189 unsigned long pfn = __phys_to_pfn(phys_addr);
190
191 /*
192 * Don't allow wraparound or zero size
193 */
194 last_addr = phys_addr + size - 1;
195 if (!size || last_addr < phys_addr)
196 return NULL;
197
198 return __uc32_ioremap_pfn_caller(pfn, offset, size, mtype, caller);
199}
200
201/*
202 * Remap an arbitrary physical address space into the kernel virtual
203 * address space. Needed when the kernel wants to access high addresses
204 * directly.
205 *
206 * NOTE! We need to allow non-page-aligned mappings too: we will obviously
207 * have to convert them into an offset in a page-aligned mapping, but the
208 * caller shouldn't need to know that small detail.
209 */
210void __iomem *
211__uc32_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
212 unsigned int mtype)
213{
214 return __uc32_ioremap_pfn_caller(pfn, offset, size, mtype,
215 __builtin_return_address(0));
216}
217EXPORT_SYMBOL(__uc32_ioremap_pfn);
218
219void __iomem *
220__uc32_ioremap(unsigned long phys_addr, size_t size)
221{
222 return __uc32_ioremap_caller(phys_addr, size, MT_DEVICE,
223 __builtin_return_address(0));
224}
225EXPORT_SYMBOL(__uc32_ioremap);
226
227void __iomem *
228__uc32_ioremap_cached(unsigned long phys_addr, size_t size)
229{
230 return __uc32_ioremap_caller(phys_addr, size, MT_DEVICE_CACHED,
231 __builtin_return_address(0));
232}
233EXPORT_SYMBOL(__uc32_ioremap_cached);
234
235void __uc32_iounmap(volatile void __iomem *io_addr)
236{
237 void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
238 struct vm_struct **p, *tmp;
239
240 /*
241 * If this is a section based mapping we need to handle it
242 * specially as the VM subsystem does not know how to handle
243 * such a beast. We need the lock here b/c we need to clear
244 * all the mappings before the area can be reclaimed
245 * by someone else.
246 */
247 write_lock(&vmlist_lock);
248 for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
249 if ((tmp->flags & VM_IOREMAP) && (tmp->addr == addr)) {
250 if (tmp->flags & VM_UNICORE_SECTION_MAPPING) {
251 unmap_area_sections((unsigned long)tmp->addr,
252 tmp->size);
253 }
254 break;
255 }
256 }
257 write_unlock(&vmlist_lock);
258
259 vunmap(addr);
260}
261EXPORT_SYMBOL(__uc32_iounmap);
diff --git a/arch/unicore32/mm/mm.h b/arch/unicore32/mm/mm.h
new file mode 100644
index 00000000000..3296bca0f1f
--- /dev/null
+++ b/arch/unicore32/mm/mm.h
@@ -0,0 +1,39 @@
1/*
2 * linux/arch/unicore32/mm/mm.h
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12/* the upper-most page table pointer */
13extern pmd_t *top_pmd;
14extern int sysctl_overcommit_memory;
15
16#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
17
18static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
19{
20 return pmd_offset((pud_t *)pgd, virt);
21}
22
23static inline pmd_t *pmd_off_k(unsigned long virt)
24{
25 return pmd_off(pgd_offset_k(virt), virt);
26}
27
28struct mem_type {
29 unsigned int prot_pte;
30 unsigned int prot_l1;
31 unsigned int prot_sect;
32};
33
34const struct mem_type *get_mem_type(unsigned int type);
35
36extern void __flush_dcache_page(struct address_space *, struct page *);
37
38void __init bootmem_init(void);
39void uc32_mm_memblock_reserve(void);
diff --git a/arch/unicore32/mm/mmu.c b/arch/unicore32/mm/mmu.c
new file mode 100644
index 00000000000..7bf3d588631
--- /dev/null
+++ b/arch/unicore32/mm/mmu.c
@@ -0,0 +1,533 @@
1/*
2 * linux/arch/unicore32/mm/mmu.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/init.h>
16#include <linux/mman.h>
17#include <linux/nodemask.h>
18#include <linux/memblock.h>
19#include <linux/fs.h>
20#include <linux/bootmem.h>
21#include <linux/io.h>
22
23#include <asm/cputype.h>
24#include <asm/sections.h>
25#include <asm/setup.h>
26#include <asm/sizes.h>
27#include <asm/tlb.h>
28
29#include <mach/map.h>
30
31#include "mm.h"
32
33DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
34
35/*
36 * empty_zero_page is a special page that is used for
37 * zero-initialized data and COW.
38 */
39struct page *empty_zero_page;
40EXPORT_SYMBOL(empty_zero_page);
41
42/*
43 * The pmd table for the upper-most set of pages.
44 */
45pmd_t *top_pmd;
46
47pgprot_t pgprot_user;
48EXPORT_SYMBOL(pgprot_user);
49
50pgprot_t pgprot_kernel;
51EXPORT_SYMBOL(pgprot_kernel);
52
53static int __init noalign_setup(char *__unused)
54{
55 cr_alignment &= ~CR_A;
56 cr_no_alignment &= ~CR_A;
57 set_cr(cr_alignment);
58 return 1;
59}
60__setup("noalign", noalign_setup);
61
62void adjust_cr(unsigned long mask, unsigned long set)
63{
64 unsigned long flags;
65
66 mask &= ~CR_A;
67
68 set &= mask;
69
70 local_irq_save(flags);
71
72 cr_no_alignment = (cr_no_alignment & ~mask) | set;
73 cr_alignment = (cr_alignment & ~mask) | set;
74
75 set_cr((get_cr() & ~mask) | set);
76
77 local_irq_restore(flags);
78}
79
80struct map_desc {
81 unsigned long virtual;
82 unsigned long pfn;
83 unsigned long length;
84 unsigned int type;
85};
86
87#define PROT_PTE_DEVICE (PTE_PRESENT | PTE_YOUNG | \
88 PTE_DIRTY | PTE_READ | PTE_WRITE)
89#define PROT_SECT_DEVICE (PMD_TYPE_SECT | PMD_PRESENT | \
90 PMD_SECT_READ | PMD_SECT_WRITE)
91
92static struct mem_type mem_types[] = {
93 [MT_DEVICE] = { /* Strongly ordered */
94 .prot_pte = PROT_PTE_DEVICE,
95 .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,
96 .prot_sect = PROT_SECT_DEVICE,
97 },
98 /*
99 * MT_KUSER: pte for vecpage -- cacheable,
100 * and sect for unigfx mmap -- noncacheable
101 */
102 [MT_KUSER] = {
103 .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |
104 PTE_CACHEABLE | PTE_READ | PTE_EXEC,
105 .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,
106 .prot_sect = PROT_SECT_DEVICE,
107 },
108 [MT_HIGH_VECTORS] = {
109 .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |
110 PTE_CACHEABLE | PTE_READ | PTE_WRITE |
111 PTE_EXEC,
112 .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,
113 },
114 [MT_MEMORY] = {
115 .prot_pte = PTE_PRESENT | PTE_YOUNG | PTE_DIRTY |
116 PTE_WRITE | PTE_EXEC,
117 .prot_l1 = PMD_TYPE_TABLE | PMD_PRESENT,
118 .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE |
119 PMD_SECT_READ | PMD_SECT_WRITE | PMD_SECT_EXEC,
120 },
121 [MT_ROM] = {
122 .prot_sect = PMD_TYPE_SECT | PMD_PRESENT | PMD_SECT_CACHEABLE |
123 PMD_SECT_READ,
124 },
125};
126
127const struct mem_type *get_mem_type(unsigned int type)
128{
129 return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
130}
131EXPORT_SYMBOL(get_mem_type);
132
133/*
134 * Adjust the PMD section entries according to the CPU in use.
135 */
136static void __init build_mem_type_table(void)
137{
138 pgprot_user = __pgprot(PTE_PRESENT | PTE_YOUNG | PTE_CACHEABLE);
139 pgprot_kernel = __pgprot(PTE_PRESENT | PTE_YOUNG |
140 PTE_DIRTY | PTE_READ | PTE_WRITE |
141 PTE_EXEC | PTE_CACHEABLE);
142}
143
144#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
145
146static void __init *early_alloc(unsigned long sz)
147{
148 void *ptr = __va(memblock_alloc(sz, sz));
149 memset(ptr, 0, sz);
150 return ptr;
151}
152
153static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr,
154 unsigned long prot)
155{
156 if (pmd_none(*pmd)) {
157 pte_t *pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t));
158 __pmd_populate(pmd, __pa(pte) | prot);
159 }
160 BUG_ON(pmd_bad(*pmd));
161 return pte_offset_kernel(pmd, addr);
162}
163
164static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
165 unsigned long end, unsigned long pfn,
166 const struct mem_type *type)
167{
168 pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
169 do {
170 set_pte(pte, pfn_pte(pfn, __pgprot(type->prot_pte)));
171 pfn++;
172 } while (pte++, addr += PAGE_SIZE, addr != end);
173}
174
175static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
176 unsigned long end, unsigned long phys,
177 const struct mem_type *type)
178{
179 pmd_t *pmd = pmd_offset((pud_t *)pgd, addr);
180
181 /*
182 * Try a section mapping - end, addr and phys must all be aligned
183 * to a section boundary.
184 */
185 if (((addr | end | phys) & ~SECTION_MASK) == 0) {
186 pmd_t *p = pmd;
187
188 do {
189 set_pmd(pmd, __pmd(phys | type->prot_sect));
190 phys += SECTION_SIZE;
191 } while (pmd++, addr += SECTION_SIZE, addr != end);
192
193 flush_pmd_entry(p);
194 } else {
195 /*
196 * No need to loop; pte's aren't interested in the
197 * individual L1 entries.
198 */
199 alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
200 }
201}
202
203/*
204 * Create the page directory entries and any necessary
205 * page tables for the mapping specified by `md'. We
206 * are able to cope here with varying sizes and address
207 * offsets, and we take full advantage of sections.
208 */
209static void __init create_mapping(struct map_desc *md)
210{
211 unsigned long phys, addr, length, end;
212 const struct mem_type *type;
213 pgd_t *pgd;
214
215 if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
216 printk(KERN_WARNING "BUG: not creating mapping for "
217 "0x%08llx at 0x%08lx in user region\n",
218 __pfn_to_phys((u64)md->pfn), md->virtual);
219 return;
220 }
221
222 if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
223 md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
224 printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
225 "overlaps vmalloc space\n",
226 __pfn_to_phys((u64)md->pfn), md->virtual);
227 }
228
229 type = &mem_types[md->type];
230
231 addr = md->virtual & PAGE_MASK;
232 phys = (unsigned long)__pfn_to_phys(md->pfn);
233 length = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
234
235 if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
236 printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
237 "be mapped using pages, ignoring.\n",
238 __pfn_to_phys(md->pfn), addr);
239 return;
240 }
241
242 pgd = pgd_offset_k(addr);
243 end = addr + length;
244 do {
245 unsigned long next = pgd_addr_end(addr, end);
246
247 alloc_init_section(pgd, addr, next, phys, type);
248
249 phys += next - addr;
250 addr = next;
251 } while (pgd++, addr != end);
252}
253
254static void * __initdata vmalloc_min = (void *)(VMALLOC_END - SZ_128M);
255
256/*
257 * vmalloc=size forces the vmalloc area to be exactly 'size'
258 * bytes. This can be used to increase (or decrease) the vmalloc
259 * area - the default is 128m.
260 */
261static int __init early_vmalloc(char *arg)
262{
263 unsigned long vmalloc_reserve = memparse(arg, NULL);
264
265 if (vmalloc_reserve < SZ_16M) {
266 vmalloc_reserve = SZ_16M;
267 printk(KERN_WARNING
268 "vmalloc area too small, limiting to %luMB\n",
269 vmalloc_reserve >> 20);
270 }
271
272 if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {
273 vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);
274 printk(KERN_WARNING
275 "vmalloc area is too big, limiting to %luMB\n",
276 vmalloc_reserve >> 20);
277 }
278
279 vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve);
280 return 0;
281}
282early_param("vmalloc", early_vmalloc);
283
284static phys_addr_t lowmem_limit __initdata = SZ_1G;
285
286static void __init sanity_check_meminfo(void)
287{
288 int i, j;
289
290 lowmem_limit = __pa(vmalloc_min - 1) + 1;
291 memblock_set_current_limit(lowmem_limit);
292
293 for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
294 struct membank *bank = &meminfo.bank[j];
295 *bank = meminfo.bank[i];
296 j++;
297 }
298 meminfo.nr_banks = j;
299}
300
301static inline void prepare_page_table(void)
302{
303 unsigned long addr;
304 phys_addr_t end;
305
306 /*
307 * Clear out all the mappings below the kernel image.
308 */
309 for (addr = 0; addr < MODULES_VADDR; addr += PGDIR_SIZE)
310 pmd_clear(pmd_off_k(addr));
311
312 for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
313 pmd_clear(pmd_off_k(addr));
314
315 /*
316 * Find the end of the first block of lowmem.
317 */
318 end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
319 if (end >= lowmem_limit)
320 end = lowmem_limit;
321
322 /*
323 * Clear out all the kernel space mappings, except for the first
324 * memory bank, up to the end of the vmalloc region.
325 */
326 for (addr = __phys_to_virt(end);
327 addr < VMALLOC_END; addr += PGDIR_SIZE)
328 pmd_clear(pmd_off_k(addr));
329}
330
331/*
332 * Reserve the special regions of memory
333 */
334void __init uc32_mm_memblock_reserve(void)
335{
336 /*
337 * Reserve the page tables. These are already in use,
338 * and can only be in node 0.
339 */
340 memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t));
341
342#ifdef CONFIG_PUV3_UNIGFX
343 /*
344 * These should likewise go elsewhere. They pre-reserve the
345 * screen/video memory region at the 48M~64M of main system memory.
346 */
347 memblock_reserve(PKUNITY_UNIGFX_MMAP_BASE, PKUNITY_UNIGFX_MMAP_SIZE);
348 memblock_reserve(PKUNITY_UVC_MMAP_BASE, PKUNITY_UVC_MMAP_SIZE);
349#endif
350}
351
352/*
353 * Set up device the mappings. Since we clear out the page tables for all
354 * mappings above VMALLOC_END, we will remove any debug device mappings.
355 * This means you have to be careful how you debug this function, or any
356 * called function. This means you can't use any function or debugging
357 * method which may touch any device, otherwise the kernel _will_ crash.
358 */
359static void __init devicemaps_init(void)
360{
361 struct map_desc map;
362 unsigned long addr;
363 void *vectors;
364
365 /*
366 * Allocate the vector page early.
367 */
368 vectors = early_alloc(PAGE_SIZE);
369
370 for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
371 pmd_clear(pmd_off_k(addr));
372
373 /*
374 * Create a mapping for UniGFX VRAM
375 */
376#ifdef CONFIG_PUV3_UNIGFX
377 map.pfn = __phys_to_pfn(PKUNITY_UNIGFX_MMAP_BASE);
378 map.virtual = KUSER_UNIGFX_BASE;
379 map.length = PKUNITY_UNIGFX_MMAP_SIZE;
380 map.type = MT_KUSER;
381 create_mapping(&map);
382#endif
383
384 /*
385 * Create a mapping for the machine vectors at the high-vectors
386 * location (0xffff0000). If we aren't using high-vectors, also
387 * create a mapping at the low-vectors virtual address.
388 */
389 map.pfn = __phys_to_pfn(virt_to_phys(vectors));
390 map.virtual = VECTORS_BASE;
391 map.length = PAGE_SIZE;
392 map.type = MT_HIGH_VECTORS;
393 create_mapping(&map);
394
395 /*
396 * Create a mapping for the kuser page at the special
397 * location (0xbfff0000) to the same vectors location.
398 */
399 map.pfn = __phys_to_pfn(virt_to_phys(vectors));
400 map.virtual = KUSER_VECPAGE_BASE;
401 map.length = PAGE_SIZE;
402 map.type = MT_KUSER;
403 create_mapping(&map);
404
405 /*
406 * Finally flush the caches and tlb to ensure that we're in a
407 * consistent state wrt the writebuffer. This also ensures that
408 * any write-allocated cache lines in the vector page are written
409 * back. After this point, we can start to touch devices again.
410 */
411 local_flush_tlb_all();
412 flush_cache_all();
413}
414
415static void __init map_lowmem(void)
416{
417 struct memblock_region *reg;
418
419 /* Map all the lowmem memory banks. */
420 for_each_memblock(memory, reg) {
421 phys_addr_t start = reg->base;
422 phys_addr_t end = start + reg->size;
423 struct map_desc map;
424
425 if (end > lowmem_limit)
426 end = lowmem_limit;
427 if (start >= end)
428 break;
429
430 map.pfn = __phys_to_pfn(start);
431 map.virtual = __phys_to_virt(start);
432 map.length = end - start;
433 map.type = MT_MEMORY;
434
435 create_mapping(&map);
436 }
437}
438
439/*
440 * paging_init() sets up the page tables, initialises the zone memory
441 * maps, and sets up the zero page, bad page and bad page tables.
442 */
443void __init paging_init(void)
444{
445 void *zero_page;
446
447 build_mem_type_table();
448 sanity_check_meminfo();
449 prepare_page_table();
450 map_lowmem();
451 devicemaps_init();
452
453 top_pmd = pmd_off_k(0xffff0000);
454
455 /* allocate the zero page. */
456 zero_page = early_alloc(PAGE_SIZE);
457
458 bootmem_init();
459
460 empty_zero_page = virt_to_page(zero_page);
461 __flush_dcache_page(NULL, empty_zero_page);
462}
463
464/*
465 * In order to soft-boot, we need to insert a 1:1 mapping in place of
466 * the user-mode pages. This will then ensure that we have predictable
467 * results when turning the mmu off
468 */
469void setup_mm_for_reboot(char mode)
470{
471 unsigned long base_pmdval;
472 pgd_t *pgd;
473 int i;
474
475 /*
476 * We need to access to user-mode page tables here. For kernel threads
477 * we don't have any user-mode mappings so we use the context that we
478 * "borrowed".
479 */
480 pgd = current->active_mm->pgd;
481
482 base_pmdval = PMD_SECT_WRITE | PMD_SECT_READ | PMD_TYPE_SECT;
483
484 for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
485 unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
486 pmd_t *pmd;
487
488 pmd = pmd_off(pgd, i << PGDIR_SHIFT);
489 set_pmd(pmd, __pmd(pmdval));
490 flush_pmd_entry(pmd);
491 }
492
493 local_flush_tlb_all();
494}
495
496/*
497 * Take care of architecture specific things when placing a new PTE into
498 * a page table, or changing an existing PTE. Basically, there are two
499 * things that we need to take care of:
500 *
501 * 1. If PG_dcache_clean is not set for the page, we need to ensure
502 * that any cache entries for the kernels virtual memory
503 * range are written back to the page.
504 * 2. If we have multiple shared mappings of the same space in
505 * an object, we need to deal with the cache aliasing issues.
506 *
507 * Note that the pte lock will be held.
508 */
509void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
510 pte_t *ptep)
511{
512 unsigned long pfn = pte_pfn(*ptep);
513 struct address_space *mapping;
514 struct page *page;
515
516 if (!pfn_valid(pfn))
517 return;
518
519 /*
520 * The zero page is never written to, so never has any dirty
521 * cache lines, and therefore never needs to be flushed.
522 */
523 page = pfn_to_page(pfn);
524 if (page == ZERO_PAGE(0))
525 return;
526
527 mapping = page_mapping(page);
528 if (!test_and_set_bit(PG_dcache_clean, &page->flags))
529 __flush_dcache_page(mapping, page);
530 if (mapping)
531 if (vma->vm_flags & VM_EXEC)
532 __flush_icache_all();
533}
diff --git a/arch/unicore32/mm/pgd.c b/arch/unicore32/mm/pgd.c
new file mode 100644
index 00000000000..08b8d4295e7
--- /dev/null
+++ b/arch/unicore32/mm/pgd.c
@@ -0,0 +1,102 @@
1/*
2 * linux/arch/unicore32/mm/pgd.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/mm.h>
13#include <linux/gfp.h>
14#include <linux/highmem.h>
15
16#include <asm/pgalloc.h>
17#include <asm/page.h>
18#include <asm/tlbflush.h>
19
20#include "mm.h"
21
22#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
23
24/*
25 * need to get a 4k page for level 1
26 */
27pgd_t *get_pgd_slow(struct mm_struct *mm)
28{
29 pgd_t *new_pgd, *init_pgd;
30 pmd_t *new_pmd, *init_pmd;
31 pte_t *new_pte, *init_pte;
32
33 new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 0);
34 if (!new_pgd)
35 goto no_pgd;
36
37 memset(new_pgd, 0, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
38
39 /*
40 * Copy over the kernel and IO PGD entries
41 */
42 init_pgd = pgd_offset_k(0);
43 memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
44 (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
45
46 clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
47
48 if (!vectors_high()) {
49 /*
50 * On UniCore, first page must always be allocated since it
51 * contains the machine vectors.
52 */
53 new_pmd = pmd_alloc(mm, (pud_t *)new_pgd, 0);
54 if (!new_pmd)
55 goto no_pmd;
56
57 new_pte = pte_alloc_map(mm, NULL, new_pmd, 0);
58 if (!new_pte)
59 goto no_pte;
60
61 init_pmd = pmd_offset((pud_t *)init_pgd, 0);
62 init_pte = pte_offset_map(init_pmd, 0);
63 set_pte(new_pte, *init_pte);
64 pte_unmap(init_pte);
65 pte_unmap(new_pte);
66 }
67
68 return new_pgd;
69
70no_pte:
71 pmd_free(mm, new_pmd);
72no_pmd:
73 free_pages((unsigned long)new_pgd, 0);
74no_pgd:
75 return NULL;
76}
77
78void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
79{
80 pmd_t *pmd;
81 pgtable_t pte;
82
83 if (!pgd)
84 return;
85
86 /* pgd is always present and good */
87 pmd = pmd_off(pgd, 0);
88 if (pmd_none(*pmd))
89 goto free;
90 if (pmd_bad(*pmd)) {
91 pmd_ERROR(*pmd);
92 pmd_clear(pmd);
93 goto free;
94 }
95
96 pte = pmd_pgtable(*pmd);
97 pmd_clear(pmd);
98 pte_free(mm, pte);
99 pmd_free(mm, pmd);
100free:
101 free_pages((unsigned long) pgd, 0);
102}
diff --git a/arch/unicore32/mm/proc-macros.S b/arch/unicore32/mm/proc-macros.S
new file mode 100644
index 00000000000..51560d68c89
--- /dev/null
+++ b/arch/unicore32/mm/proc-macros.S
@@ -0,0 +1,145 @@
1/*
2 * linux/arch/unicore32/mm/proc-macros.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * We need constants.h for:
13 * VMA_VM_MM
14 * VMA_VM_FLAGS
15 * VM_EXEC
16 */
17#include <generated/asm-offsets.h>
18#include <asm/thread_info.h>
19#include <asm/memory.h>
20
21/*
22 * the cache line sizes of the I and D cache are the same
23 */
24#define CACHE_LINESIZE 32
25
26/*
27 * This is the maximum size of an area which will be invalidated
28 * using the single invalidate entry instructions. Anything larger
29 * than this, and we go for the whole cache.
30 *
31 * This value should be chosen such that we choose the cheapest
32 * alternative.
33 */
34#ifdef CONFIG_CPU_UCV2
35#define MAX_AREA_SIZE 0x800 /* 64 cache line */
36#endif
37
38/*
39 * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
40 */
41 .macro vma_vm_mm, rd, rn
42 ldw \rd, [\rn+], #VMA_VM_MM
43 .endm
44
45/*
46 * vma_vm_flags - get vma->vm_flags
47 */
48 .macro vma_vm_flags, rd, rn
49 ldw \rd, [\rn+], #VMA_VM_FLAGS
50 .endm
51
52 .macro tsk_mm, rd, rn
53 ldw \rd, [\rn+], #TI_TASK
54 ldw \rd, [\rd+], #TSK_ACTIVE_MM
55 .endm
56
57/*
58 * act_mm - get current->active_mm
59 */
60 .macro act_mm, rd
61 andn \rd, sp, #8128
62 andn \rd, \rd, #63
63 ldw \rd, [\rd+], #TI_TASK
64 ldw \rd, [\rd+], #TSK_ACTIVE_MM
65 .endm
66
67/*
68 * mmid - get context id from mm pointer (mm->context.id)
69 */
70 .macro mmid, rd, rn
71 ldw \rd, [\rn+], #MM_CONTEXT_ID
72 .endm
73
74/*
75 * mask_asid - mask the ASID from the context ID
76 */
77 .macro asid, rd, rn
78 and \rd, \rn, #255
79 .endm
80
81 .macro crval, clear, mmuset, ucset
82 .word \clear
83 .word \mmuset
84 .endm
85
86#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
87/*
88 * va2pa va, pa, tbl, msk, off, err
89 * This macro is used to translate virtual address to its physical address.
90 *
91 * va: virtual address
92 * pa: physical address, result is stored in this register
93 * tbl, msk, off: temp registers, will be destroyed
94 * err: jump to error label if the physical address not exist
95 * NOTE: all regs must be different
96 */
97 .macro va2pa, va, pa, tbl, msk, off, err=990f
98 movc \pa, p0.c2, #0
99 mov \off, \va >> #22 @ off <- index of 1st page table
100 adr \tbl, 910f @ tbl <- table of 1st page table
101900: @ ---- handle 1, 2 page table
102 add \pa, \pa, #PAGE_OFFSET @ pa <- virt addr of page table
103 ldw \pa, [\pa+], \off << #2 @ pa <- the content of pt
104 cand.a \pa, #4 @ test exist bit
105 beq \err @ if not exist
106 and \off, \pa, #3 @ off <- the last 2 bits
107 add \tbl, \tbl, \off << #3 @ cmove table pointer
108 ldw \msk, [\tbl+], #0 @ get the mask
109 ldw pc, [\tbl+], #4
110930: @ ---- handle 2nd page table
111 and \pa, \pa, \msk @ pa <- phys addr of 2nd pt
112 mov \off, \va << #10
113 cntlo \tbl, \msk @ use tbl as temp reg
114 mov \off, \off >> \tbl
115 mov \off, \off >> #2 @ off <- index of 2nd pt
116 adr \tbl, 920f @ tbl <- table of 2nd pt
117 b 900b
118910: @ 1st level page table
119 .word 0xfffff000, 930b @ second level page table
120 .word 0xfffffc00, 930b @ second level large page table
121 .word 0x00000000, \err @ invalid
122 .word 0xffc00000, 980f @ super page
123
124920: @ 2nd level page table
125 .word 0xfffff000, 980f @ page
126 .word 0xffffc000, 980f @ middle page
127 .word 0xffff0000, 980f @ large page
128 .word 0x00000000, \err @ invalid
129980:
130 andn \tbl, \va, \msk
131 and \pa, \pa, \msk
132 or \pa, \pa, \tbl
133990:
134 .endm
135#endif
136
137 .macro dcacheline_flush, addr, t1, t2
138 mov \t1, \addr << #20
139 ldw \t2, =_stext @ _stext must ALIGN(4096)
140 add \t2, \t2, \t1 >> #20
141 ldw \t1, [\t2+], #0x0000
142 ldw \t1, [\t2+], #0x1000
143 ldw \t1, [\t2+], #0x2000
144 ldw \t1, [\t2+], #0x3000
145 .endm
diff --git a/arch/unicore32/mm/proc-syms.c b/arch/unicore32/mm/proc-syms.c
new file mode 100644
index 00000000000..f30071e3665
--- /dev/null
+++ b/arch/unicore32/mm/proc-syms.c
@@ -0,0 +1,23 @@
1/*
2 * linux/arch/unicore32/mm/proc-syms.c
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/mm.h>
14
15#include <asm/cacheflush.h>
16#include <asm/tlbflush.h>
17#include <asm/page.h>
18
19EXPORT_SYMBOL(cpu_dcache_clean_area);
20EXPORT_SYMBOL(cpu_set_pte);
21
22EXPORT_SYMBOL(__cpuc_dma_flush_range);
23EXPORT_SYMBOL(__cpuc_dma_clean_range);
diff --git a/arch/unicore32/mm/proc-ucv2.S b/arch/unicore32/mm/proc-ucv2.S
new file mode 100644
index 00000000000..9d296092e36
--- /dev/null
+++ b/arch/unicore32/mm/proc-ucv2.S
@@ -0,0 +1,134 @@
1/*
2 * linux/arch/unicore32/mm/proc-ucv2.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/init.h>
13#include <linux/linkage.h>
14#include <asm/assembler.h>
15#include <asm/hwcap.h>
16#include <asm/pgtable-hwdef.h>
17#include <asm/pgtable.h>
18
19#include "proc-macros.S"
20
21ENTRY(cpu_proc_fin)
22 stm.w (lr), [sp-]
23 mov ip, #PSR_R_BIT | PSR_I_BIT | PRIV_MODE
24 mov.a asr, ip
25 b.l __cpuc_flush_kern_all
26 ldm.w (pc), [sp]+
27
28/*
29 * cpu_reset(loc)
30 *
31 * Perform a soft reset of the system. Put the CPU into the
32 * same state as it would be if it had been reset, and branch
33 * to what would be the reset vector.
34 *
35 * - loc - location to jump to for soft reset
36 */
37 .align 5
38ENTRY(cpu_reset)
39 mov ip, #0
40 movc p0.c5, ip, #28 @ Cache invalidate all
41 nop8
42
43 movc p0.c6, ip, #6 @ TLB invalidate all
44 nop8
45
46 movc ip, p0.c1, #0 @ ctrl register
47 or ip, ip, #0x2000 @ vector base address
48 andn ip, ip, #0x000f @ ............idam
49 movc p0.c1, ip, #0 @ disable caches and mmu
50 nop
51 mov pc, r0 @ jump to loc
52 nop8
53
54/*
55 * cpu_do_idle()
56 *
57 * Idle the processor (eg, wait for interrupt).
58 *
59 * IRQs are already disabled.
60 */
61ENTRY(cpu_do_idle)
62 mov r0, #0 @ PCI address
63 .rept 8
64 ldw r1, [r0]
65 .endr
66 mov pc, lr
67
68ENTRY(cpu_dcache_clean_area)
69#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
70 csub.a r1, #MAX_AREA_SIZE
71 bsg 101f
72 mov r9, #PAGE_SZ
73 sub r9, r9, #1 @ PAGE_MASK
741: va2pa r0, r10, r11, r12, r13 @ r10 is PA
75 b 3f
762: cand.a r0, r9
77 beq 1b
783: movc p0.c5, r10, #11 @ clean D entry
79 nop8
80 add r0, r0, #CACHE_LINESIZE
81 add r10, r10, #CACHE_LINESIZE
82 sub.a r1, r1, #CACHE_LINESIZE
83 bua 2b
84 mov pc, lr
85#endif
86101: mov ip, #0
87 movc p0.c5, ip, #10 @ Dcache clean all
88 nop8
89
90 mov pc, lr
91
92/*
93 * cpu_do_switch_mm(pgd_phys)
94 *
95 * Set the translation table base pointer to be pgd_phys
96 *
97 * - pgd_phys - physical address of new pgd
98 *
99 * It is assumed that:
100 * - we are not using split page tables
101 */
102 .align 5
103ENTRY(cpu_do_switch_mm)
104 movc p0.c2, r0, #0 @ update page table ptr
105 nop8
106
107 movc p0.c6, ip, #6 @ TLB invalidate all
108 nop8
109
110 mov pc, lr
111
112/*
113 * cpu_set_pte(ptep, pte)
114 *
115 * Set a level 2 translation table entry.
116 *
117 * - ptep - pointer to level 2 translation table entry
118 * - pte - PTE value to store
119 */
120 .align 5
121ENTRY(cpu_set_pte)
122 stw r1, [r0]
123#ifndef CONFIG_CPU_DCACHE_LINE_DISABLE
124 sub r2, r0, #PAGE_OFFSET
125 movc p0.c5, r2, #11 @ Dcache clean line
126 nop8
127#else
128 mov ip, #0
129 movc p0.c5, ip, #10 @ Dcache clean all
130 nop8
131 @dcacheline_flush r0, r2, ip
132#endif
133 mov pc, lr
134
diff --git a/arch/unicore32/mm/tlb-ucv2.S b/arch/unicore32/mm/tlb-ucv2.S
new file mode 100644
index 00000000000..061d455f9a1
--- /dev/null
+++ b/arch/unicore32/mm/tlb-ucv2.S
@@ -0,0 +1,89 @@
1/*
2 * linux/arch/unicore32/mm/tlb-ucv2.S
3 *
4 * Code specific to PKUnity SoC and UniCore ISA
5 *
6 * Copyright (C) 2001-2010 GUAN Xue-tao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/init.h>
13#include <linux/linkage.h>
14#include <asm/assembler.h>
15#include <asm/page.h>
16#include <asm/tlbflush.h>
17#include "proc-macros.S"
18
19/*
20 * __cpu_flush_user_tlb_range(start, end, vma)
21 *
22 * Invalidate a range of TLB entries in the specified address space.
23 *
24 * - start - start address (may not be aligned)
25 * - end - end address (exclusive, may not be aligned)
26 * - vma - vma_struct describing address range
27 */
28ENTRY(__cpu_flush_user_tlb_range)
29#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
30 mov r0, r0 >> #PAGE_SHIFT @ align address
31 mov r0, r0 << #PAGE_SHIFT
32 vma_vm_flags r2, r2 @ get vma->vm_flags
331:
34 movc p0.c6, r0, #3
35 nop8
36
37 cand.a r2, #VM_EXEC @ Executable area ?
38 beq 2f
39
40 movc p0.c6, r0, #5
41 nop8
422:
43 add r0, r0, #PAGE_SZ
44 csub.a r0, r1
45 beb 1b
46#else
47 movc p0.c6, r0, #2
48 nop8
49
50 cand.a r2, #VM_EXEC @ Executable area ?
51 beq 2f
52
53 movc p0.c6, r0, #4
54 nop8
552:
56#endif
57 mov pc, lr
58
59/*
60 * __cpu_flush_kern_tlb_range(start,end)
61 *
62 * Invalidate a range of kernel TLB entries
63 *
64 * - start - start address (may not be aligned)
65 * - end - end address (exclusive, may not be aligned)
66 */
67ENTRY(__cpu_flush_kern_tlb_range)
68#ifndef CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE
69 mov r0, r0 >> #PAGE_SHIFT @ align address
70 mov r0, r0 << #PAGE_SHIFT
711:
72 movc p0.c6, r0, #3
73 nop8
74
75 movc p0.c6, r0, #5
76 nop8
77
78 add r0, r0, #PAGE_SZ
79 csub.a r0, r1
80 beb 1b
81#else
82 movc p0.c6, r0, #2
83 nop8
84
85 movc p0.c6, r0, #4
86 nop8
87#endif
88 mov pc, lr
89
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 113505a6434..cbfcf6fb4a6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -523,6 +523,17 @@ config I2C_PNX
523 This driver can also be built as a module. If so, the module 523 This driver can also be built as a module. If so, the module
524 will be called i2c-pnx. 524 will be called i2c-pnx.
525 525
526config I2C_PUV3
527 tristate "PKUnity v3 I2C bus support"
528 depends on UNICORE32 && ARCH_PUV3
529 select I2C_ALGOBIT
530 help
531 This driver supports the I2C IP inside the PKUnity-v3 SoC.
532 This I2C bus controller is under AMBA/AXI bus.
533
534 This driver can also be built as a module. If so, the module
535 will be called i2c-puv3.
536
526config I2C_PXA 537config I2C_PXA
527 tristate "Intel PXA2XX I2C adapter" 538 tristate "Intel PXA2XX I2C adapter"
528 depends on ARCH_PXA || ARCH_MMP 539 depends on ARCH_PXA || ARCH_MMP
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 9d2d0ec7fb2..a83966acc5a 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
51obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o 51obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
52obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o 52obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
53obj-$(CONFIG_I2C_PNX) += i2c-pnx.o 53obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
54obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
54obj-$(CONFIG_I2C_PXA) += i2c-pxa.o 55obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
55obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o 56obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
56obj-$(CONFIG_I2C_S6000) += i2c-s6000.o 57obj-$(CONFIG_I2C_S6000) += i2c-s6000.o
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
new file mode 100644
index 00000000000..fac67394084
--- /dev/null
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -0,0 +1,306 @@
1/*
2 * I2C driver for PKUnity-v3 SoC
3 * Code specific to PKUnity SoC and UniCore ISA
4 *
5 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
6 * Copyright (C) 2001-2010 Guan Xuetao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/slab.h>
17#include <linux/types.h>
18#include <linux/delay.h>
19#include <linux/i2c.h>
20#include <linux/init.h>
21#include <linux/clk.h>
22#include <linux/platform_device.h>
23#include <linux/io.h>
24#include <mach/hardware.h>
25
26/*
27 * Poll the i2c status register until the specified bit is set.
28 * Returns 0 if timed out (100 msec).
29 */
30static short poll_status(unsigned long bit)
31{
32 int loop_cntr = 1000;
33
34 if (bit & I2C_STATUS_TFNF) {
35 do {
36 udelay(10);
37 } while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0));
38 } else {
39 /* RXRDY handler */
40 do {
41 if (readl(I2C_TAR) == I2C_TAR_EEPROM)
42 msleep(20);
43 else
44 udelay(10);
45 } while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0));
46 }
47
48 return (loop_cntr > 0);
49}
50
51static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
52{
53 int i2c_reg = *buf;
54
55 /* Read data */
56 while (length--) {
57 if (!poll_status(I2C_STATUS_TFNF)) {
58 dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n");
59 return -ETIMEDOUT;
60 }
61
62 /* send addr */
63 writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
64
65 /* get ready to next write */
66 i2c_reg++;
67
68 /* send read CMD */
69 writel(I2C_DATACMD_READ, I2C_DATACMD);
70
71 /* wait until the Rx FIFO have available */
72 if (!poll_status(I2C_STATUS_RFNE)) {
73 dev_dbg(&adap->dev, "RXRDY timeout\n");
74 return -ETIMEDOUT;
75 }
76
77 /* read the data to buf */
78 *buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK);
79 buf++;
80 }
81
82 return 0;
83}
84
85static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
86{
87 int i2c_reg = *buf;
88
89 /* Do nothing but storing the reg_num to a static variable */
90 if (i2c_reg == -1) {
91 printk(KERN_WARNING "Error i2c reg\n");
92 return -ETIMEDOUT;
93 }
94
95 if (length == 1)
96 return 0;
97
98 buf++;
99 length--;
100 while (length--) {
101 /* send addr */
102 writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
103
104 /* send write CMD */
105 writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD);
106
107 /* wait until the Rx FIFO have available */
108 msleep(20);
109
110 /* read the data to buf */
111 i2c_reg++;
112 buf++;
113 }
114
115 return 0;
116}
117
118/*
119 * Generic i2c master transfer entrypoint.
120 *
121 */
122static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg,
123 int num)
124{
125 int i, ret;
126 unsigned char swap;
127
128 /* Disable i2c */
129 writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
130
131 /* Set the work mode and speed*/
132 writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON);
133
134 writel(pmsg->addr, I2C_TAR);
135
136 /* Enable i2c */
137 writel(I2C_ENABLE_ENABLE, I2C_ENABLE);
138
139 dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num);
140
141 for (i = 0; i < num; i++) {
142 dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
143 pmsg->flags & I2C_M_RD ? "read" : "writ",
144 pmsg->len, pmsg->len > 1 ? "s" : "",
145 pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
146
147 if (pmsg->len && pmsg->buf) { /* sanity check */
148 if (pmsg->flags & I2C_M_RD)
149 ret = xfer_read(adap, pmsg->buf, pmsg->len);
150 else
151 ret = xfer_write(adap, pmsg->buf, pmsg->len);
152
153 if (ret)
154 return ret;
155
156 }
157 dev_dbg(&adap->dev, "transfer complete\n");
158 pmsg++; /* next message */
159 }
160
161 /* XXX: fixup be16_to_cpu in bq27x00_battery.c */
162 if (pmsg->addr == I2C_TAR_PWIC) {
163 swap = pmsg->buf[0];
164 pmsg->buf[0] = pmsg->buf[1];
165 pmsg->buf[1] = swap;
166 }
167
168 return i;
169}
170
171/*
172 * Return list of supported functionality.
173 */
174static u32 puv3_i2c_func(struct i2c_adapter *adapter)
175{
176 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
177}
178
179static struct i2c_algorithm puv3_i2c_algorithm = {
180 .master_xfer = puv3_i2c_xfer,
181 .functionality = puv3_i2c_func,
182};
183
184/*
185 * Main initialization routine.
186 */
187static int __devinit puv3_i2c_probe(struct platform_device *pdev)
188{
189 struct i2c_adapter *adapter;
190 struct resource *mem;
191 int rc;
192
193 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
194 if (!mem)
195 return -ENODEV;
196
197 if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c"))
198 return -EBUSY;
199
200 adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
201 if (adapter == NULL) {
202 dev_err(&pdev->dev, "can't allocate inteface!\n");
203 rc = -ENOMEM;
204 goto fail_nomem;
205 }
206 snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x",
207 mem->start);
208 adapter->algo = &puv3_i2c_algorithm;
209 adapter->class = I2C_CLASS_HWMON;
210 adapter->dev.parent = &pdev->dev;
211
212 platform_set_drvdata(pdev, adapter);
213
214 adapter->nr = pdev->id;
215 rc = i2c_add_numbered_adapter(adapter);
216 if (rc) {
217 dev_err(&pdev->dev, "Adapter '%s' registration failed\n",
218 adapter->name);
219 goto fail_add_adapter;
220 }
221
222 dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n");
223 return 0;
224
225fail_add_adapter:
226 platform_set_drvdata(pdev, NULL);
227 kfree(adapter);
228fail_nomem:
229 release_mem_region(mem->start, resource_size(mem));
230
231 return rc;
232}
233
234static int __devexit puv3_i2c_remove(struct platform_device *pdev)
235{
236 struct i2c_adapter *adapter = platform_get_drvdata(pdev);
237 struct resource *mem;
238 int rc;
239
240 rc = i2c_del_adapter(adapter);
241 if (rc) {
242 dev_err(&pdev->dev, "Adapter '%s' delete fail\n",
243 adapter->name);
244 return rc;
245 }
246
247 put_device(&pdev->dev);
248 platform_set_drvdata(pdev, NULL);
249
250 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
251 release_mem_region(mem->start, resource_size(mem));
252
253 return rc;
254}
255
256#ifdef CONFIG_PM
257static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
258{
259 int poll_count;
260 /* Disable the IIC */
261 writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
262 for (poll_count = 0; poll_count < 50; poll_count++) {
263 if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE)
264 udelay(25);
265 }
266
267 return 0;
268}
269
270static int puv3_i2c_resume(struct platform_device *dev)
271{
272 return 0 ;
273}
274#else
275#define puv3_i2c_suspend NULL
276#define puv3_i2c_resume NULL
277#endif
278
279MODULE_ALIAS("platform:puv3_i2c");
280
281static struct platform_driver puv3_i2c_driver = {
282 .probe = puv3_i2c_probe,
283 .remove = __devexit_p(puv3_i2c_remove),
284 .suspend = puv3_i2c_suspend,
285 .resume = puv3_i2c_resume,
286 .driver = {
287 .name = "PKUnity-v3-I2C",
288 .owner = THIS_MODULE,
289 }
290};
291
292static int __init puv3_i2c_init(void)
293{
294 return platform_driver_register(&puv3_i2c_driver);
295}
296
297static void __exit puv3_i2c_exit(void)
298{
299 platform_driver_unregister(&puv3_i2c_driver);
300}
301
302module_init(puv3_i2c_init);
303module_exit(puv3_i2c_exit);
304
305MODULE_DESCRIPTION("PKUnity v3 I2C driver");
306MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/serio/i8042-unicore32io.h b/drivers/input/serio/i8042-unicore32io.h
new file mode 100644
index 00000000000..73f5cc124a3
--- /dev/null
+++ b/drivers/input/serio/i8042-unicore32io.h
@@ -0,0 +1,73 @@
1/*
2 * Code specific to PKUnity SoC and UniCore ISA
3 *
4 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
5 * Copyright (C) 2001-2011 Guan Xuetao
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _I8042_UNICORE32_H
12#define _I8042_UNICORE32_H
13
14#include <mach/hardware.h>
15
16/*
17 * Names.
18 */
19#define I8042_KBD_PHYS_DESC "isa0060/serio0"
20#define I8042_AUX_PHYS_DESC "isa0060/serio1"
21#define I8042_MUX_PHYS_DESC "isa0060/serio%d"
22
23/*
24 * IRQs.
25 */
26#define I8042_KBD_IRQ IRQ_PS2_KBD
27#define I8042_AUX_IRQ IRQ_PS2_AUX
28
29/*
30 * Register numbers.
31 */
32#define I8042_COMMAND_REG PS2_COMMAND
33#define I8042_STATUS_REG PS2_STATUS
34#define I8042_DATA_REG PS2_DATA
35
36#define I8042_REGION_START (resource_size_t)(PS2_DATA)
37#define I8042_REGION_SIZE (resource_size_t)(16)
38
39static inline int i8042_read_data(void)
40{
41 return readb(I8042_DATA_REG);
42}
43
44static inline int i8042_read_status(void)
45{
46 return readb(I8042_STATUS_REG);
47}
48
49static inline void i8042_write_data(int val)
50{
51 writeb(val, I8042_DATA_REG);
52}
53
54static inline void i8042_write_command(int val)
55{
56 writeb(val, I8042_COMMAND_REG);
57}
58
59static inline int i8042_platform_init(void)
60{
61 if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
62 return -EBUSY;
63
64 i8042_reset = 1;
65 return 0;
66}
67
68static inline void i8042_platform_exit(void)
69{
70 release_mem_region(I8042_REGION_START, I8042_REGION_SIZE);
71}
72
73#endif /* _I8042_UNICORE32_H */
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index ac1d759d0f5..3452708fbe3 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -26,6 +26,8 @@
26#include "i8042-sparcio.h" 26#include "i8042-sparcio.h"
27#elif defined(CONFIG_X86) || defined(CONFIG_IA64) 27#elif defined(CONFIG_X86) || defined(CONFIG_IA64)
28#include "i8042-x86ia64io.h" 28#include "i8042-x86ia64io.h"
29#elif defined(CONFIG_UNICORE32)
30#include "i8042-unicore32io.h"
29#else 31#else
30#include "i8042-io.h" 32#include "i8042-io.h"
31#endif 33#endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 98e6fdf34d3..77cf813ba26 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
42obj-$(CONFIG_X86) += setup-bus.o 42obj-$(CONFIG_X86) += setup-bus.o
43obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o 43obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
44obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o 44obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
45obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
45obj-$(CONFIG_PARISC) += setup-bus.o 46obj-$(CONFIG_PARISC) += setup-bus.o
46obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o 47obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
47obj-$(CONFIG_PPC) += setup-bus.o 48obj-$(CONFIG_PPC) += setup-bus.o
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e6791f7ecfb..2a753f1e918 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2303,6 +2303,17 @@ config FB_JZ4740
2303 help 2303 help
2304 Framebuffer support for the JZ4740 SoC. 2304 Framebuffer support for the JZ4740 SoC.
2305 2305
2306config FB_PUV3_UNIGFX
2307 tristate "PKUnity v3 Unigfx framebuffer support"
2308 depends on FB && UNICORE32 && ARCH_PUV3
2309 select FB_SYS_FILLRECT
2310 select FB_SYS_COPYAREA
2311 select FB_SYS_IMAGEBLIT
2312 select FB_SYS_FOPS
2313 help
2314 Choose this option if you want to use the Unigfx device as a
2315 framebuffer device. Without the support of PCI & AGP.
2316
2306source "drivers/video/omap/Kconfig" 2317source "drivers/video/omap/Kconfig"
2307source "drivers/video/omap2/Kconfig" 2318source "drivers/video/omap2/Kconfig"
2308 2319
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8c8fabdff9d..b0eb3da2467 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -139,6 +139,7 @@ obj-$(CONFIG_FB_MB862XX) += mb862xx/
139obj-$(CONFIG_FB_MSM) += msm/ 139obj-$(CONFIG_FB_MSM) += msm/
140obj-$(CONFIG_FB_NUC900) += nuc900fb.o 140obj-$(CONFIG_FB_NUC900) += nuc900fb.o
141obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o 141obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
142obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o
142 143
143# Platform or fallback drivers go here 144# Platform or fallback drivers go here
144obj-$(CONFIG_FB_UVESA) += uvesafb.o 145obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c
new file mode 100644
index 00000000000..dbd2dc4745d
--- /dev/null
+++ b/drivers/video/fb-puv3.c
@@ -0,0 +1,846 @@
1/*
2 * Frame Buffer Driver for PKUnity-v3 Unigfx
3 * Code specific to PKUnity SoC and UniCore ISA
4 *
5 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
6 * Copyright (C) 2001-2010 Guan Xuetao
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/vmalloc.h>
17#include <linux/platform_device.h>
18#include <linux/clk.h>
19#include <linux/fb.h>
20#include <linux/init.h>
21#include <linux/console.h>
22
23#include <asm/sizes.h>
24#include <mach/hardware.h>
25
26/* Platform_data reserved for unifb registers. */
27#define UNIFB_REGS_NUM 10
28/* RAM reserved for the frame buffer. */
29#define UNIFB_MEMSIZE (SZ_4M) /* 4 MB for 1024*768*32b */
30
31/*
32 * cause UNIGFX don not have EDID
33 * all the modes are organized as follow
34 */
35static const struct fb_videomode unifb_modes[] = {
36 /* 0 640x480-60 VESA */
37 { "640x480@60", 60, 640, 480, 25175000, 48, 16, 34, 10, 96, 1,
38 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
39 /* 1 640x480-75 VESA */
40 { "640x480@75", 75, 640, 480, 31500000, 120, 16, 18, 1, 64, 1,
41 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
42 /* 2 800x600-60 VESA */
43 { "800x600@60", 60, 800, 600, 40000000, 88, 40, 26, 1, 128, 1,
44 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
45 /* 3 800x600-75 VESA */
46 { "800x600@75", 75, 800, 600, 49500000, 160, 16, 23, 1, 80, 1,
47 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
48 /* 4 1024x768-60 VESA */
49 { "1024x768@60", 60, 1024, 768, 65000000, 160, 24, 34, 3, 136, 1,
50 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
51 /* 5 1024x768-75 VESA */
52 { "1024x768@75", 75, 1024, 768, 78750000, 176, 16, 30, 1, 96, 1,
53 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
54 /* 6 1280x960-60 VESA */
55 { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38, 1, 112, 1,
56 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
57 /* 7 1440x900-60 VESA */
58 { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30, 3, 152, 1,
59 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
60 /* 8 FIXME 9 1024x600-60 VESA UNTESTED */
61 { "1024x600@60", 60, 1024, 600, 50650000, 160, 24, 26, 1, 136, 1,
62 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
63 /* 9 FIXME 10 1024x600-75 VESA UNTESTED */
64 { "1024x600@75", 75, 1024, 600, 61500000, 176, 16, 23, 1, 96, 1,
65 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
66 /* 10 FIXME 11 1366x768-60 VESA UNTESTED */
67 { "1366x768@60", 60, 1366, 768, 85500000, 256, 58, 18, 1, 112, 3,
68 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
69};
70
71static struct fb_var_screeninfo unifb_default = {
72 .xres = 640,
73 .yres = 480,
74 .xres_virtual = 640,
75 .yres_virtual = 480,
76 .bits_per_pixel = 16,
77 .red = { 11, 5, 0 },
78 .green = { 5, 6, 0 },
79 .blue = { 0, 5, 0 },
80 .activate = FB_ACTIVATE_NOW,
81 .height = -1,
82 .width = -1,
83 .pixclock = 25175000,
84 .left_margin = 48,
85 .right_margin = 16,
86 .upper_margin = 33,
87 .lower_margin = 10,
88 .hsync_len = 96,
89 .vsync_len = 2,
90 .vmode = FB_VMODE_NONINTERLACED,
91};
92
93static struct fb_fix_screeninfo unifb_fix = {
94 .id = "UNIGFX FB",
95 .type = FB_TYPE_PACKED_PIXELS,
96 .visual = FB_VISUAL_TRUECOLOR,
97 .xpanstep = 1,
98 .ypanstep = 1,
99 .ywrapstep = 1,
100 .accel = FB_ACCEL_NONE,
101};
102
103static void unifb_sync(struct fb_info *info)
104{
105 /* TODO: may, this can be replaced by interrupt */
106 int cnt;
107
108 for (cnt = 0; cnt < 0x10000000; cnt++) {
109 if (readl(UGE_COMMAND) & 0x1000000)
110 return;
111 }
112
113 if (cnt > 0x8000000)
114 dev_warn(info->device, "Warning: UniGFX GE time out ...\n");
115}
116
117static void unifb_prim_fillrect(struct fb_info *info,
118 const struct fb_fillrect *region)
119{
120 int awidth = region->width;
121 int aheight = region->height;
122 int m_iBpp = info->var.bits_per_pixel;
123 int screen_width = info->var.xres;
124 int src_sel = 1; /* from fg_color */
125 int pat_sel = 1;
126 int src_x0 = 0;
127 int dst_x0 = region->dx;
128 int src_y0 = 0;
129 int dst_y0 = region->dy;
130 int rop_alpha_sel = 0;
131 int rop_alpha_code = 0xCC;
132 int x_dir = 1;
133 int y_dir = 1;
134 int alpha_r = 0;
135 int alpha_sel = 0;
136 int dst_pitch = screen_width * (m_iBpp / 8);
137 int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
138 int src_pitch = screen_width * (m_iBpp / 8);
139 int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
140 unsigned int command = 0;
141 int clip_region = 0;
142 int clip_en = 0;
143 int tp_en = 0;
144 int fg_color = 0;
145 int bottom = info->var.yres - 1;
146 int right = info->var.xres - 1;
147 int top = 0;
148
149 bottom = (bottom << 16) | right;
150 command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16)
151 | (x_dir << 20) | (y_dir << 21) | (command << 24)
152 | (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
153 src_pitch = (dst_pitch << 16) | src_pitch;
154 awidth = awidth | (aheight << 16);
155 alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff)
156 | (alpha_sel << 16);
157 src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
158 dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
159 fg_color = region->color;
160
161 unifb_sync(info);
162
163 writel(((u32 *)(info->pseudo_palette))[fg_color], UGE_FCOLOR);
164 writel(0, UGE_BCOLOR);
165 writel(src_pitch, UGE_PITCH);
166 writel(src_offset, UGE_SRCSTART);
167 writel(dst_offset, UGE_DSTSTART);
168 writel(awidth, UGE_WIDHEIGHT);
169 writel(top, UGE_CLIP0);
170 writel(bottom, UGE_CLIP1);
171 writel(alpha_r, UGE_ROPALPHA);
172 writel(src_x0, UGE_SRCXY);
173 writel(dst_x0, UGE_DSTXY);
174 writel(command, UGE_COMMAND);
175}
176
177static void unifb_fillrect(struct fb_info *info,
178 const struct fb_fillrect *region)
179{
180 struct fb_fillrect modded;
181 int vxres, vyres;
182
183 if (info->flags & FBINFO_HWACCEL_DISABLED) {
184 sys_fillrect(info, region);
185 return;
186 }
187
188 vxres = info->var.xres_virtual;
189 vyres = info->var.yres_virtual;
190
191 memcpy(&modded, region, sizeof(struct fb_fillrect));
192
193 if (!modded.width || !modded.height ||
194 modded.dx >= vxres || modded.dy >= vyres)
195 return;
196
197 if (modded.dx + modded.width > vxres)
198 modded.width = vxres - modded.dx;
199 if (modded.dy + modded.height > vyres)
200 modded.height = vyres - modded.dy;
201
202 unifb_prim_fillrect(info, &modded);
203}
204
205static void unifb_prim_copyarea(struct fb_info *info,
206 const struct fb_copyarea *area)
207{
208 int awidth = area->width;
209 int aheight = area->height;
210 int m_iBpp = info->var.bits_per_pixel;
211 int screen_width = info->var.xres;
212 int src_sel = 2; /* from mem */
213 int pat_sel = 0;
214 int src_x0 = area->sx;
215 int dst_x0 = area->dx;
216 int src_y0 = area->sy;
217 int dst_y0 = area->dy;
218
219 int rop_alpha_sel = 0;
220 int rop_alpha_code = 0xCC;
221 int x_dir = 1;
222 int y_dir = 1;
223
224 int alpha_r = 0;
225 int alpha_sel = 0;
226 int dst_pitch = screen_width * (m_iBpp / 8);
227 int dst_offset = dst_y0 * dst_pitch + dst_x0 * (m_iBpp / 8);
228 int src_pitch = screen_width * (m_iBpp / 8);
229 int src_offset = src_y0 * src_pitch + src_x0 * (m_iBpp / 8);
230 unsigned int command = 0;
231 int clip_region = 0;
232 int clip_en = 1;
233 int tp_en = 0;
234 int top = 0;
235 int bottom = info->var.yres;
236 int right = info->var.xres;
237 int fg_color = 0;
238 int bg_color = 0;
239
240 if (src_x0 < 0)
241 src_x0 = 0;
242 if (src_y0 < 0)
243 src_y0 = 0;
244
245 if (src_y0 - dst_y0 > 0) {
246 y_dir = 1;
247 } else {
248 y_dir = 0;
249 src_offset = (src_y0 + aheight) * src_pitch +
250 src_x0 * (m_iBpp / 8);
251 dst_offset = (dst_y0 + aheight) * dst_pitch +
252 dst_x0 * (m_iBpp / 8);
253 src_y0 += aheight;
254 dst_y0 += aheight;
255 }
256
257 command = (rop_alpha_sel << 26) | (pat_sel << 18) | (src_sel << 16) |
258 (x_dir << 20) | (y_dir << 21) | (command << 24) |
259 (clip_region << 23) | (clip_en << 22) | (tp_en << 27);
260 src_pitch = (dst_pitch << 16) | src_pitch;
261 awidth = awidth | (aheight << 16);
262 alpha_r = ((rop_alpha_code & 0xff) << 8) | (alpha_r & 0xff) |
263 (alpha_sel << 16);
264 src_x0 = (src_x0 & 0x1fff) | ((src_y0 & 0x1fff) << 16);
265 dst_x0 = (dst_x0 & 0x1fff) | ((dst_y0 & 0x1fff) << 16);
266 bottom = (bottom << 16) | right;
267
268 unifb_sync(info);
269
270 writel(src_pitch, UGE_PITCH);
271 writel(src_offset, UGE_SRCSTART);
272 writel(dst_offset, UGE_DSTSTART);
273 writel(awidth, UGE_WIDHEIGHT);
274 writel(top, UGE_CLIP0);
275 writel(bottom, UGE_CLIP1);
276 writel(bg_color, UGE_BCOLOR);
277 writel(fg_color, UGE_FCOLOR);
278 writel(alpha_r, UGE_ROPALPHA);
279 writel(src_x0, UGE_SRCXY);
280 writel(dst_x0, UGE_DSTXY);
281 writel(command, UGE_COMMAND);
282}
283
284static void unifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
285{
286 struct fb_copyarea modded;
287 u32 vxres, vyres;
288 modded.sx = area->sx;
289 modded.sy = area->sy;
290 modded.dx = area->dx;
291 modded.dy = area->dy;
292 modded.width = area->width;
293 modded.height = area->height;
294
295 if (info->flags & FBINFO_HWACCEL_DISABLED) {
296 sys_copyarea(info, area);
297 return;
298 }
299
300 vxres = info->var.xres_virtual;
301 vyres = info->var.yres_virtual;
302
303 if (!modded.width || !modded.height ||
304 modded.sx >= vxres || modded.sy >= vyres ||
305 modded.dx >= vxres || modded.dy >= vyres)
306 return;
307
308 if (modded.sx + modded.width > vxres)
309 modded.width = vxres - modded.sx;
310 if (modded.dx + modded.width > vxres)
311 modded.width = vxres - modded.dx;
312 if (modded.sy + modded.height > vyres)
313 modded.height = vyres - modded.sy;
314 if (modded.dy + modded.height > vyres)
315 modded.height = vyres - modded.dy;
316
317 unifb_prim_copyarea(info, &modded);
318}
319
320static void unifb_imageblit(struct fb_info *info, const struct fb_image *image)
321{
322 sys_imageblit(info, image);
323}
324
325static u_long get_line_length(int xres_virtual, int bpp)
326{
327 u_long length;
328
329 length = xres_virtual * bpp;
330 length = (length + 31) & ~31;
331 length >>= 3;
332 return length;
333}
334
335/*
336 * Setting the video mode has been split into two parts.
337 * First part, xxxfb_check_var, must not write anything
338 * to hardware, it should only verify and adjust var.
339 * This means it doesn't alter par but it does use hardware
340 * data from it to check this var.
341 */
342static int unifb_check_var(struct fb_var_screeninfo *var,
343 struct fb_info *info)
344{
345 u_long line_length;
346
347 /*
348 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
349 * as FB_VMODE_SMOOTH_XPAN is only used internally
350 */
351
352 if (var->vmode & FB_VMODE_CONUPDATE) {
353 var->vmode |= FB_VMODE_YWRAP;
354 var->xoffset = info->var.xoffset;
355 var->yoffset = info->var.yoffset;
356 }
357
358 /*
359 * Some very basic checks
360 */
361 if (!var->xres)
362 var->xres = 1;
363 if (!var->yres)
364 var->yres = 1;
365 if (var->xres > var->xres_virtual)
366 var->xres_virtual = var->xres;
367 if (var->yres > var->yres_virtual)
368 var->yres_virtual = var->yres;
369 if (var->bits_per_pixel <= 1)
370 var->bits_per_pixel = 1;
371 else if (var->bits_per_pixel <= 8)
372 var->bits_per_pixel = 8;
373 else if (var->bits_per_pixel <= 16)
374 var->bits_per_pixel = 16;
375 else if (var->bits_per_pixel <= 24)
376 var->bits_per_pixel = 24;
377 else if (var->bits_per_pixel <= 32)
378 var->bits_per_pixel = 32;
379 else
380 return -EINVAL;
381
382 if (var->xres_virtual < var->xoffset + var->xres)
383 var->xres_virtual = var->xoffset + var->xres;
384 if (var->yres_virtual < var->yoffset + var->yres)
385 var->yres_virtual = var->yoffset + var->yres;
386
387 /*
388 * Memory limit
389 */
390 line_length =
391 get_line_length(var->xres_virtual, var->bits_per_pixel);
392 if (line_length * var->yres_virtual > UNIFB_MEMSIZE)
393 return -ENOMEM;
394
395 /*
396 * Now that we checked it we alter var. The reason being is that the
397 * video mode passed in might not work but slight changes to it might
398 * make it work. This way we let the user know what is acceptable.
399 */
400 switch (var->bits_per_pixel) {
401 case 1:
402 case 8:
403 var->red.offset = 0;
404 var->red.length = 8;
405 var->green.offset = 0;
406 var->green.length = 8;
407 var->blue.offset = 0;
408 var->blue.length = 8;
409 var->transp.offset = 0;
410 var->transp.length = 0;
411 break;
412 case 16: /* RGBA 5551 */
413 if (var->transp.length) {
414 var->red.offset = 0;
415 var->red.length = 5;
416 var->green.offset = 5;
417 var->green.length = 5;
418 var->blue.offset = 10;
419 var->blue.length = 5;
420 var->transp.offset = 15;
421 var->transp.length = 1;
422 } else { /* RGB 565 */
423 var->red.offset = 11;
424 var->red.length = 5;
425 var->green.offset = 5;
426 var->green.length = 6;
427 var->blue.offset = 0;
428 var->blue.length = 5;
429 var->transp.offset = 0;
430 var->transp.length = 0;
431 }
432 break;
433 case 24: /* RGB 888 */
434 var->red.offset = 0;
435 var->red.length = 8;
436 var->green.offset = 8;
437 var->green.length = 8;
438 var->blue.offset = 16;
439 var->blue.length = 8;
440 var->transp.offset = 0;
441 var->transp.length = 0;
442 break;
443 case 32: /* RGBA 8888 */
444 var->red.offset = 16;
445 var->red.length = 8;
446 var->green.offset = 8;
447 var->green.length = 8;
448 var->blue.offset = 0;
449 var->blue.length = 8;
450 var->transp.offset = 24;
451 var->transp.length = 8;
452 break;
453 }
454 var->red.msb_right = 0;
455 var->green.msb_right = 0;
456 var->blue.msb_right = 0;
457 var->transp.msb_right = 0;
458
459 return 0;
460}
461
462/*
463 * This routine actually sets the video mode. It's in here where we
464 * the hardware state info->par and fix which can be affected by the
465 * change in par. For this driver it doesn't do much.
466 */
467static int unifb_set_par(struct fb_info *info)
468{
469 int hTotal, vTotal, hSyncStart, hSyncEnd, vSyncStart, vSyncEnd;
470 int format;
471
472#ifdef CONFIG_PUV3_PM
473 struct clk *clk_vga;
474 u32 pixclk = 0;
475 int i;
476
477 for (i = 0; i <= 10; i++) {
478 if (info->var.xres == unifb_modes[i].xres
479 && info->var.yres == unifb_modes[i].yres
480 && info->var.upper_margin == unifb_modes[i].upper_margin
481 && info->var.lower_margin == unifb_modes[i].lower_margin
482 && info->var.left_margin == unifb_modes[i].left_margin
483 && info->var.right_margin == unifb_modes[i].right_margin
484 && info->var.hsync_len == unifb_modes[i].hsync_len
485 && info->var.vsync_len == unifb_modes[i].vsync_len) {
486 pixclk = unifb_modes[i].pixclock;
487 break;
488 }
489 }
490
491 /* set clock rate */
492 clk_vga = clk_get(info->device, "VGA_CLK");
493 if (clk_vga == ERR_PTR(-ENOENT))
494 return -ENOENT;
495
496 if (pixclk != 0) {
497 if (clk_set_rate(clk_vga, pixclk)) { /* set clock failed */
498 info->fix = unifb_fix;
499 info->var = unifb_default;
500 if (clk_set_rate(clk_vga, unifb_default.pixclock))
501 return -EINVAL;
502 }
503 }
504#endif
505
506 info->fix.line_length = get_line_length(info->var.xres_virtual,
507 info->var.bits_per_pixel);
508
509 hSyncStart = info->var.xres + info->var.right_margin;
510 hSyncEnd = hSyncStart + info->var.hsync_len;
511 hTotal = hSyncEnd + info->var.left_margin;
512
513 vSyncStart = info->var.yres + info->var.lower_margin;
514 vSyncEnd = vSyncStart + info->var.vsync_len;
515 vTotal = vSyncEnd + info->var.upper_margin;
516
517 switch (info->var.bits_per_pixel) {
518 case 8:
519 format = UDE_CFG_DST8;
520 break;
521 case 16:
522 format = UDE_CFG_DST16;
523 break;
524 case 24:
525 format = UDE_CFG_DST24;
526 break;
527 case 32:
528 format = UDE_CFG_DST32;
529 break;
530 default:
531 return -EINVAL;
532 }
533
534 writel(PKUNITY_UNIGFX_MMAP_BASE, UDE_FSA);
535 writel(info->var.yres, UDE_LS);
536 writel(get_line_length(info->var.xres,
537 info->var.bits_per_pixel) >> 3, UDE_PS);
538 /* >> 3 for hardware required. */
539 writel((hTotal << 16) | (info->var.xres), UDE_HAT);
540 writel(((hTotal - 1) << 16) | (info->var.xres - 1), UDE_HBT);
541 writel(((hSyncEnd - 1) << 16) | (hSyncStart - 1), UDE_HST);
542 writel((vTotal << 16) | (info->var.yres), UDE_VAT);
543 writel(((vTotal - 1) << 16) | (info->var.yres - 1), UDE_VBT);
544 writel(((vSyncEnd - 1) << 16) | (vSyncStart - 1), UDE_VST);
545 writel(UDE_CFG_GDEN_ENABLE | UDE_CFG_TIMEUP_ENABLE
546 | format | 0xC0000001, UDE_CFG);
547
548 return 0;
549}
550
551/*
552 * Set a single color register. The values supplied are already
553 * rounded down to the hardware's capabilities (according to the
554 * entries in the var structure). Return != 0 for invalid regno.
555 */
556static int unifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
557 u_int transp, struct fb_info *info)
558{
559 if (regno >= 256) /* no. of hw registers */
560 return 1;
561
562 /* grayscale works only partially under directcolor */
563 if (info->var.grayscale) {
564 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
565 red = green = blue =
566 (red * 77 + green * 151 + blue * 28) >> 8;
567 }
568
569#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
570 switch (info->fix.visual) {
571 case FB_VISUAL_TRUECOLOR:
572 case FB_VISUAL_PSEUDOCOLOR:
573 red = CNVT_TOHW(red, info->var.red.length);
574 green = CNVT_TOHW(green, info->var.green.length);
575 blue = CNVT_TOHW(blue, info->var.blue.length);
576 transp = CNVT_TOHW(transp, info->var.transp.length);
577 break;
578 case FB_VISUAL_DIRECTCOLOR:
579 red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */
580 green = CNVT_TOHW(green, 8);
581 blue = CNVT_TOHW(blue, 8);
582 /* hey, there is bug in transp handling... */
583 transp = CNVT_TOHW(transp, 8);
584 break;
585 }
586#undef CNVT_TOHW
587 /* Truecolor has hardware independent palette */
588 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
589 u32 v;
590
591 if (regno >= 16)
592 return 1;
593
594 v = (red << info->var.red.offset) |
595 (green << info->var.green.offset) |
596 (blue << info->var.blue.offset) |
597 (transp << info->var.transp.offset);
598 switch (info->var.bits_per_pixel) {
599 case 8:
600 break;
601 case 16:
602 case 24:
603 case 32:
604 ((u32 *) (info->pseudo_palette))[regno] = v;
605 break;
606 default:
607 return 1;
608 }
609 return 0;
610 }
611 return 0;
612}
613
614/*
615 * Pan or Wrap the Display
616 *
617 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
618 */
619static int unifb_pan_display(struct fb_var_screeninfo *var,
620 struct fb_info *info)
621{
622 if (var->vmode & FB_VMODE_YWRAP) {
623 if (var->yoffset < 0
624 || var->yoffset >= info->var.yres_virtual
625 || var->xoffset)
626 return -EINVAL;
627 } else {
628 if (var->xoffset + var->xres > info->var.xres_virtual ||
629 var->yoffset + var->yres > info->var.yres_virtual)
630 return -EINVAL;
631 }
632 info->var.xoffset = var->xoffset;
633 info->var.yoffset = var->yoffset;
634 if (var->vmode & FB_VMODE_YWRAP)
635 info->var.vmode |= FB_VMODE_YWRAP;
636 else
637 info->var.vmode &= ~FB_VMODE_YWRAP;
638 return 0;
639}
640
641int unifb_mmap(struct fb_info *info,
642 struct vm_area_struct *vma)
643{
644 unsigned long size = vma->vm_end - vma->vm_start;
645 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
646 unsigned long pos = info->fix.smem_start + offset;
647
648 if (offset + size > info->fix.smem_len)
649 return -EINVAL;
650
651 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
652
653 if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size,
654 vma->vm_page_prot))
655 return -EAGAIN;
656
657 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
658 return 0;
659
660}
661
662static struct fb_ops unifb_ops = {
663 .fb_read = fb_sys_read,
664 .fb_write = fb_sys_write,
665 .fb_check_var = unifb_check_var,
666 .fb_set_par = unifb_set_par,
667 .fb_setcolreg = unifb_setcolreg,
668 .fb_pan_display = unifb_pan_display,
669 .fb_fillrect = unifb_fillrect,
670 .fb_copyarea = unifb_copyarea,
671 .fb_imageblit = unifb_imageblit,
672 .fb_mmap = unifb_mmap,
673};
674
675/*
676 * Initialisation
677 */
678static int unifb_probe(struct platform_device *dev)
679{
680 struct fb_info *info;
681 u32 unifb_regs[UNIFB_REGS_NUM];
682 int retval = -ENOMEM;
683 struct resource *iomem, *mapmem;
684
685 info = framebuffer_alloc(sizeof(u32)*256, &dev->dev);
686 if (!info)
687 goto err;
688
689 info->screen_base = (char __iomem *)KUSER_UNIGFX_BASE;
690 info->fbops = &unifb_ops;
691
692 retval = fb_find_mode(&info->var, info, NULL,
693 unifb_modes, 10, &unifb_modes[0], 16);
694
695 if (!retval || (retval == 4))
696 info->var = unifb_default;
697
698 iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
699 unifb_fix.mmio_start = iomem->start;
700
701 mapmem = platform_get_resource(dev, IORESOURCE_MEM, 1);
702 unifb_fix.smem_start = mapmem->start;
703 unifb_fix.smem_len = UNIFB_MEMSIZE;
704
705 info->fix = unifb_fix;
706 info->pseudo_palette = info->par;
707 info->par = NULL;
708 info->flags = FBINFO_FLAG_DEFAULT;
709#ifdef FB_ACCEL_PUV3_UNIGFX
710 info->fix.accel = FB_ACCEL_PUV3_UNIGFX;
711#endif
712
713 retval = fb_alloc_cmap(&info->cmap, 256, 0);
714 if (retval < 0)
715 goto err1;
716
717 retval = register_framebuffer(info);
718 if (retval < 0)
719 goto err2;
720 platform_set_drvdata(dev, info);
721 platform_device_add_data(dev, unifb_regs, sizeof(u32) * UNIFB_REGS_NUM);
722
723 printk(KERN_INFO
724 "fb%d: Virtual frame buffer device, using %dM of video memory\n",
725 info->node, UNIFB_MEMSIZE >> 20);
726 return 0;
727err2:
728 fb_dealloc_cmap(&info->cmap);
729err1:
730 framebuffer_release(info);
731err:
732 return retval;
733}
734
735static int unifb_remove(struct platform_device *dev)
736{
737 struct fb_info *info = platform_get_drvdata(dev);
738
739 if (info) {
740 unregister_framebuffer(info);
741 fb_dealloc_cmap(&info->cmap);
742 framebuffer_release(info);
743 }
744 return 0;
745}
746
747#ifdef CONFIG_PM
748static int unifb_resume(struct platform_device *dev)
749{
750 int rc = 0;
751 u32 *unifb_regs = dev->dev.platform_data;
752
753 if (dev->dev.power.power_state.event == PM_EVENT_ON)
754 return 0;
755
756 console_lock();
757
758 if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
759 writel(unifb_regs[0], UDE_FSA);
760 writel(unifb_regs[1], UDE_LS);
761 writel(unifb_regs[2], UDE_PS);
762 writel(unifb_regs[3], UDE_HAT);
763 writel(unifb_regs[4], UDE_HBT);
764 writel(unifb_regs[5], UDE_HST);
765 writel(unifb_regs[6], UDE_VAT);
766 writel(unifb_regs[7], UDE_VBT);
767 writel(unifb_regs[8], UDE_VST);
768 writel(unifb_regs[9], UDE_CFG);
769 }
770 dev->dev.power.power_state = PMSG_ON;
771
772 console_unlock();
773
774 return rc;
775}
776
777static int unifb_suspend(struct platform_device *dev, pm_message_t mesg)
778{
779 u32 *unifb_regs = dev->dev.platform_data;
780
781 unifb_regs[0] = readl(UDE_FSA);
782 unifb_regs[1] = readl(UDE_LS);
783 unifb_regs[2] = readl(UDE_PS);
784 unifb_regs[3] = readl(UDE_HAT);
785 unifb_regs[4] = readl(UDE_HBT);
786 unifb_regs[5] = readl(UDE_HST);
787 unifb_regs[6] = readl(UDE_VAT);
788 unifb_regs[7] = readl(UDE_VBT);
789 unifb_regs[8] = readl(UDE_VST);
790 unifb_regs[9] = readl(UDE_CFG);
791
792 if (mesg.event == dev->dev.power.power_state.event)
793 return 0;
794
795 switch (mesg.event) {
796 case PM_EVENT_FREEZE: /* about to take snapshot */
797 case PM_EVENT_PRETHAW: /* before restoring snapshot */
798 goto done;
799 }
800
801 console_lock();
802
803 /* do nothing... */
804
805 console_unlock();
806
807done:
808 dev->dev.power.power_state = mesg;
809
810 return 0;
811}
812#else
813#define unifb_resume NULL
814#define unifb_suspend NULL
815#endif
816
817static struct platform_driver unifb_driver = {
818 .probe = unifb_probe,
819 .remove = unifb_remove,
820 .resume = unifb_resume,
821 .suspend = unifb_suspend,
822 .driver = {
823 .name = "PKUnity-v3-UNIGFX",
824 },
825};
826
827static int __init unifb_init(void)
828{
829#ifndef MODULE
830 if (fb_get_options("unifb", NULL))
831 return -ENODEV;
832#endif
833
834 return platform_driver_register(&unifb_driver);
835}
836
837module_init(unifb_init);
838
839static void __exit unifb_exit(void)
840{
841 platform_driver_unregister(&unifb_driver);
842}
843
844module_exit(unifb_exit);
845
846MODULE_LICENSE("GPL v2");
diff --git a/include/asm-generic/ftrace.h b/include/asm-generic/ftrace.h
new file mode 100644
index 00000000000..51abba9ea7a
--- /dev/null
+++ b/include/asm-generic/ftrace.h
@@ -0,0 +1,16 @@
1/*
2 * linux/include/asm-generic/ftrace.h
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#ifndef __ASM_GENERIC_FTRACE_H__
9#define __ASM_GENERIC_FTRACE_H__
10
11/*
12 * Not all architectures need their own ftrace.h, the most
13 * common definitions are already in linux/ftrace.h.
14 */
15
16#endif /* __ASM_GENERIC_FTRACE_H__ */
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 4644c9a7f72..e0ffa3ddb02 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -94,6 +94,10 @@ static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
94#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr) 94#define writeq(b,addr) __raw_writeq(__cpu_to_le64(b),addr)
95#endif 95#endif
96 96
97#ifndef PCI_IOBASE
98#define PCI_IOBASE ((void __iomem *) 0)
99#endif
100
97/*****************************************************************************/ 101/*****************************************************************************/
98/* 102/*
99 * traditional input/output functions 103 * traditional input/output functions
@@ -101,32 +105,32 @@ static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
101 105
102static inline u8 inb(unsigned long addr) 106static inline u8 inb(unsigned long addr)
103{ 107{
104 return readb((volatile void __iomem *) addr); 108 return readb(addr + PCI_IOBASE);
105} 109}
106 110
107static inline u16 inw(unsigned long addr) 111static inline u16 inw(unsigned long addr)
108{ 112{
109 return readw((volatile void __iomem *) addr); 113 return readw(addr + PCI_IOBASE);
110} 114}
111 115
112static inline u32 inl(unsigned long addr) 116static inline u32 inl(unsigned long addr)
113{ 117{
114 return readl((volatile void __iomem *) addr); 118 return readl(addr + PCI_IOBASE);
115} 119}
116 120
117static inline void outb(u8 b, unsigned long addr) 121static inline void outb(u8 b, unsigned long addr)
118{ 122{
119 writeb(b, (volatile void __iomem *) addr); 123 writeb(b, addr + PCI_IOBASE);
120} 124}
121 125
122static inline void outw(u16 b, unsigned long addr) 126static inline void outw(u16 b, unsigned long addr)
123{ 127{
124 writew(b, (volatile void __iomem *) addr); 128 writew(b, addr + PCI_IOBASE);
125} 129}
126 130
127static inline void outl(u32 b, unsigned long addr) 131static inline void outl(u32 b, unsigned long addr)
128{ 132{
129 writel(b, (volatile void __iomem *) addr); 133 writel(b, addr + PCI_IOBASE);
130} 134}
131 135
132#define inb_p(addr) inb(addr) 136#define inb_p(addr) inb(addr)
@@ -213,32 +217,32 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
213 217
214static inline void readsl(const void __iomem *addr, void *buf, int len) 218static inline void readsl(const void __iomem *addr, void *buf, int len)
215{ 219{
216 insl((unsigned long)addr, buf, len); 220 insl(addr - PCI_IOBASE, buf, len);
217} 221}
218 222
219static inline void readsw(const void __iomem *addr, void *buf, int len) 223static inline void readsw(const void __iomem *addr, void *buf, int len)
220{ 224{
221 insw((unsigned long)addr, buf, len); 225 insw(addr - PCI_IOBASE, buf, len);
222} 226}
223 227
224static inline void readsb(const void __iomem *addr, void *buf, int len) 228static inline void readsb(const void __iomem *addr, void *buf, int len)
225{ 229{
226 insb((unsigned long)addr, buf, len); 230 insb(addr - PCI_IOBASE, buf, len);
227} 231}
228 232
229static inline void writesl(const void __iomem *addr, const void *buf, int len) 233static inline void writesl(const void __iomem *addr, const void *buf, int len)
230{ 234{
231 outsl((unsigned long)addr, buf, len); 235 outsl(addr - PCI_IOBASE, buf, len);
232} 236}
233 237
234static inline void writesw(const void __iomem *addr, const void *buf, int len) 238static inline void writesw(const void __iomem *addr, const void *buf, int len)
235{ 239{
236 outsw((unsigned long)addr, buf, len); 240 outsw(addr - PCI_IOBASE, buf, len);
237} 241}
238 242
239static inline void writesb(const void __iomem *addr, const void *buf, int len) 243static inline void writesb(const void __iomem *addr, const void *buf, int len)
240{ 244{
241 outsb((unsigned long)addr, buf, len); 245 outsb(addr - PCI_IOBASE, buf, len);
242} 246}
243 247
244#ifndef CONFIG_GENERIC_IOMAP 248#ifndef CONFIG_GENERIC_IOMAP
@@ -269,8 +273,9 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len)
269 outsl((unsigned long) (p), (src), (count)) 273 outsl((unsigned long) (p), (src), (count))
270#endif /* CONFIG_GENERIC_IOMAP */ 274#endif /* CONFIG_GENERIC_IOMAP */
271 275
272 276#ifndef IO_SPACE_LIMIT
273#define IO_SPACE_LIMIT 0xffffffff 277#define IO_SPACE_LIMIT 0xffff
278#endif
274 279
275#ifdef __KERNEL__ 280#ifdef __KERNEL__
276 281
diff --git a/include/asm-generic/sizes.h b/include/asm-generic/sizes.h
new file mode 100644
index 00000000000..ea5d4ef8106
--- /dev/null
+++ b/include/asm-generic/sizes.h
@@ -0,0 +1,47 @@
1/*
2 * linux/include/asm-generic/sizes.h
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#ifndef __ASM_GENERIC_SIZES_H__
9#define __ASM_GENERIC_SIZES_H__
10
11#define SZ_1 0x00000001
12#define SZ_2 0x00000002
13#define SZ_4 0x00000004
14#define SZ_8 0x00000008
15#define SZ_16 0x00000010
16#define SZ_32 0x00000020
17#define SZ_64 0x00000040
18#define SZ_128 0x00000080
19#define SZ_256 0x00000100
20#define SZ_512 0x00000200
21
22#define SZ_1K 0x00000400
23#define SZ_2K 0x00000800
24#define SZ_4K 0x00001000
25#define SZ_8K 0x00002000
26#define SZ_16K 0x00004000
27#define SZ_32K 0x00008000
28#define SZ_64K 0x00010000
29#define SZ_128K 0x00020000
30#define SZ_256K 0x00040000
31#define SZ_512K 0x00080000
32
33#define SZ_1M 0x00100000
34#define SZ_2M 0x00200000
35#define SZ_4M 0x00400000
36#define SZ_8M 0x00800000
37#define SZ_16M 0x01000000
38#define SZ_32M 0x02000000
39#define SZ_64M 0x04000000
40#define SZ_128M 0x08000000
41#define SZ_256M 0x10000000
42#define SZ_512M 0x20000000
43
44#define SZ_1G 0x40000000
45#define SZ_2G 0x80000000
46
47#endif /* __ASM_GENERIC_SIZES_H__ */
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index b218b8513d0..ac68c999b6c 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -288,14 +288,16 @@ strncpy_from_user(char *dst, const char __user *src, long count)
288 * 288 *
289 * Return 0 on exception, a value greater than N if too long 289 * Return 0 on exception, a value greater than N if too long
290 */ 290 */
291#ifndef strnlen_user 291#ifndef __strnlen_user
292#define __strnlen_user strnlen
293#endif
294
292static inline long strnlen_user(const char __user *src, long n) 295static inline long strnlen_user(const char __user *src, long n)
293{ 296{
294 if (!access_ok(VERIFY_READ, src, 1)) 297 if (!access_ok(VERIFY_READ, src, 1))
295 return 0; 298 return 0;
296 return strlen((void * __force)src) + 1; 299 return __strnlen_user(src, n);
297} 300}
298#endif
299 301
300static inline long strlen_user(const char __user *src) 302static inline long strlen_user(const char __user *src)
301{ 303{
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 68ba85a00c0..b2a36391d2a 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -152,6 +152,8 @@
152#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */ 152#define FB_ACCEL_PROSAVAGE_DDR 0x8d /* S3 ProSavage DDR */
153#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */ 153#define FB_ACCEL_PROSAVAGE_DDRK 0x8e /* S3 ProSavage DDR-K */
154 154
155#define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */
156
155struct fb_fix_screeninfo { 157struct fb_fix_screeninfo {
156 char id[16]; /* identification string eg "TT Builtin" */ 158 char id[16]; /* identification string eg "TT Builtin" */
157 unsigned long smem_start; /* Start of frame buffer mem */ 159 unsigned long smem_start; /* Start of frame buffer mem */