diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2011-03-17 15:46:58 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-03-17 15:48:06 -0400 |
commit | 2dd22997679a88874c131f6e6ffb963e6d43b3a6 (patch) | |
tree | bfe1707dda7e755b8b550c6796e2649813bcfbb9 /arch/unicore32 | |
parent | 36885ff0e6563687e6152da6d311abbf83c0198f (diff) | |
parent | 7b7adc4a016a1decb806eb71ecab98721fa7f146 (diff) |
Merge remote-tracking branch 'origin' into spi/next
Pull in Linus' tree to pick up changes required for the langwell gpio fixes
Diffstat (limited to 'arch/unicore32')
148 files changed, 18051 insertions, 0 deletions
diff --git a/arch/unicore32/.gitignore b/arch/unicore32/.gitignore new file mode 100644 index 000000000000..947e99c2a957 --- /dev/null +++ b/arch/unicore32/.gitignore | |||
@@ -0,0 +1,21 @@ | |||
1 | # | ||
2 | # Generated include files | ||
3 | # | ||
4 | include/generated | ||
5 | # | ||
6 | # Generated ld script file | ||
7 | # | ||
8 | kernel/vmlinux.lds | ||
9 | # | ||
10 | # Generated images in boot | ||
11 | # | ||
12 | boot/Image | ||
13 | boot/zImage | ||
14 | boot/uImage | ||
15 | # | ||
16 | # Generated files in boot/compressed | ||
17 | # | ||
18 | boot/compressed/piggy.S | ||
19 | boot/compressed/piggy.gzip | ||
20 | boot/compressed/vmlinux | ||
21 | boot/compressed/vmlinux.lds | ||
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig new file mode 100644 index 000000000000..4a36db45fb3d --- /dev/null +++ b/arch/unicore32/Kconfig | |||
@@ -0,0 +1,275 @@ | |||
1 | config 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 | |||
21 | config HAVE_PWM | ||
22 | bool | ||
23 | |||
24 | config GENERIC_GPIO | ||
25 | def_bool y | ||
26 | |||
27 | config GENERIC_CLOCKEVENTS | ||
28 | bool | ||
29 | |||
30 | config GENERIC_CSUM | ||
31 | def_bool y | ||
32 | |||
33 | config GENERIC_IOMAP | ||
34 | def_bool y | ||
35 | |||
36 | config NO_IOPORT | ||
37 | bool | ||
38 | |||
39 | config STACKTRACE_SUPPORT | ||
40 | def_bool y | ||
41 | |||
42 | config HAVE_LATENCYTOP_SUPPORT | ||
43 | def_bool y | ||
44 | |||
45 | config LOCKDEP_SUPPORT | ||
46 | def_bool y | ||
47 | |||
48 | config RWSEM_GENERIC_SPINLOCK | ||
49 | def_bool y | ||
50 | |||
51 | config RWSEM_XCHGADD_ALGORITHM | ||
52 | bool | ||
53 | |||
54 | config ARCH_HAS_ILOG2_U32 | ||
55 | bool | ||
56 | |||
57 | config ARCH_HAS_ILOG2_U64 | ||
58 | bool | ||
59 | |||
60 | config ARCH_HAS_CPUFREQ | ||
61 | bool | ||
62 | |||
63 | config GENERIC_HWEIGHT | ||
64 | def_bool y | ||
65 | |||
66 | config GENERIC_CALIBRATE_DELAY | ||
67 | def_bool y | ||
68 | |||
69 | config ARCH_MAY_HAVE_PC_FDC | ||
70 | bool | ||
71 | |||
72 | config NEED_DMA_MAP_STATE | ||
73 | def_bool y | ||
74 | |||
75 | source "init/Kconfig" | ||
76 | |||
77 | source "kernel/Kconfig.freezer" | ||
78 | |||
79 | menu "System Type" | ||
80 | |||
81 | config MMU | ||
82 | def_bool y | ||
83 | |||
84 | config ARCH_FPGA | ||
85 | bool | ||
86 | |||
87 | config 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 | |||
97 | if ARCH_PUV3 | ||
98 | |||
99 | choice | ||
100 | prompt "Board Selection" | ||
101 | default PUV3_DB0913 | ||
102 | |||
103 | config PUV3_FPGA_DLX200 | ||
104 | select ARCH_FPGA | ||
105 | bool "FPGA board" | ||
106 | |||
107 | config PUV3_DB0913 | ||
108 | bool "DEBUG board (0913)" | ||
109 | |||
110 | config PUV3_NB0916 | ||
111 | bool "NetBook board (0916)" | ||
112 | select HAVE_PWM | ||
113 | |||
114 | config PUV3_SMW0919 | ||
115 | bool "Security Mini-Workstation board (0919)" | ||
116 | |||
117 | endchoice | ||
118 | |||
119 | config PUV3_PM | ||
120 | def_bool y if !ARCH_FPGA | ||
121 | |||
122 | endif | ||
123 | |||
124 | source "arch/unicore32/mm/Kconfig" | ||
125 | |||
126 | comment "Floating poing support" | ||
127 | |||
128 | config UNICORE_FPU_F64 | ||
129 | def_bool y if !ARCH_FPGA | ||
130 | |||
131 | endmenu | ||
132 | |||
133 | menu "Bus support" | ||
134 | |||
135 | config 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 | |||
143 | source "drivers/pci/Kconfig" | ||
144 | |||
145 | source "drivers/pcmcia/Kconfig" | ||
146 | |||
147 | endmenu | ||
148 | |||
149 | menu "Kernel Features" | ||
150 | |||
151 | source "kernel/time/Kconfig" | ||
152 | |||
153 | source "kernel/Kconfig.preempt" | ||
154 | |||
155 | source "kernel/Kconfig.hz" | ||
156 | |||
157 | source "mm/Kconfig" | ||
158 | |||
159 | config LEDS | ||
160 | def_bool y | ||
161 | depends on GENERIC_GPIO | ||
162 | |||
163 | config 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 | |||
174 | endmenu | ||
175 | |||
176 | menu "Boot options" | ||
177 | |||
178 | config CMDLINE | ||
179 | string "Default kernel command string" | ||
180 | default "" | ||
181 | |||
182 | config 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 | |||
193 | endmenu | ||
194 | |||
195 | menu "Userspace binary formats" | ||
196 | |||
197 | source "fs/Kconfig.binfmt" | ||
198 | |||
199 | endmenu | ||
200 | |||
201 | menu "Power management options" | ||
202 | |||
203 | source "kernel/power/Kconfig" | ||
204 | |||
205 | if ARCH_HAS_CPUFREQ | ||
206 | source "drivers/cpufreq/Kconfig" | ||
207 | endif | ||
208 | |||
209 | config ARCH_SUSPEND_POSSIBLE | ||
210 | def_bool y if !ARCH_FPGA | ||
211 | |||
212 | config ARCH_HIBERNATION_POSSIBLE | ||
213 | def_bool y if !ARCH_FPGA | ||
214 | |||
215 | endmenu | ||
216 | |||
217 | source "net/Kconfig" | ||
218 | |||
219 | if ARCH_PUV3 | ||
220 | |||
221 | config PUV3_GPIO | ||
222 | bool | ||
223 | depends on !ARCH_FPGA | ||
224 | select GENERIC_GPIO | ||
225 | select GPIO_SYSFS if EXPERIMENTAL | ||
226 | default y | ||
227 | |||
228 | config PUV3_PWM | ||
229 | tristate | ||
230 | default BACKLIGHT_PWM | ||
231 | help | ||
232 | Enable support for NB0916 PWM controllers | ||
233 | |||
234 | config PUV3_RTC | ||
235 | tristate "PKUnity v3 RTC Support" | ||
236 | depends on !ARCH_FPGA | ||
237 | |||
238 | if PUV3_NB0916 | ||
239 | |||
240 | menu "PKUnity NetBook-0916 Features" | ||
241 | |||
242 | config I2C_BATTERY_BQ27200 | ||
243 | tristate "I2C Battery BQ27200 Support" | ||
244 | select PUV3_I2C | ||
245 | select POWER_SUPPLY | ||
246 | select BATTERY_BQ27x00 | ||
247 | |||
248 | config I2C_EEPROM_AT24 | ||
249 | tristate "I2C EEPROMs AT24 support" | ||
250 | select PUV3_I2C | ||
251 | select MISC_DEVICES | ||
252 | select EEPROM_AT24 | ||
253 | |||
254 | config LCD_BACKLIGHT | ||
255 | tristate "LCD Backlight support" | ||
256 | select BACKLIGHT_LCD_SUPPORT | ||
257 | select BACKLIGHT_PWM | ||
258 | |||
259 | endmenu | ||
260 | |||
261 | endif | ||
262 | |||
263 | endif | ||
264 | |||
265 | source "drivers/Kconfig" | ||
266 | |||
267 | source "fs/Kconfig" | ||
268 | |||
269 | source "arch/unicore32/Kconfig.debug" | ||
270 | |||
271 | source "security/Kconfig" | ||
272 | |||
273 | source "crypto/Kconfig" | ||
274 | |||
275 | source "lib/Kconfig" | ||
diff --git a/arch/unicore32/Kconfig.debug b/arch/unicore32/Kconfig.debug new file mode 100644 index 000000000000..3140151ede45 --- /dev/null +++ b/arch/unicore32/Kconfig.debug | |||
@@ -0,0 +1,68 @@ | |||
1 | menu "Kernel hacking" | ||
2 | |||
3 | source "lib/Kconfig.debug" | ||
4 | |||
5 | config 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 | |||
19 | config 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 | |||
30 | config 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. | ||
38 | config 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 | |||
46 | config 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 | |||
54 | config DEBUG_OCD_BREAKPOINT | ||
55 | bool "Breakpoint support via On-Chip-Debugger" | ||
56 | depends on DEBUG_OCD | ||
57 | |||
58 | config 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 | |||
68 | endmenu | ||
diff --git a/arch/unicore32/Makefile b/arch/unicore32/Makefile new file mode 100644 index 000000000000..e08d6d370a8a --- /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 | # | ||
13 | ifneq ($(SUBARCH),$(ARCH)) | ||
14 | ifeq ($(CROSS_COMPILE),) | ||
15 | CROSS_COMPILE := $(call cc-cross-prefix, unicore32-linux-) | ||
16 | endif | ||
17 | endif | ||
18 | |||
19 | LDFLAGS_vmlinux := -p --no-undefined -X | ||
20 | |||
21 | OBJCOPYFLAGS := -O binary -R .note -R .note.gnu.build-id -R .comment -S | ||
22 | |||
23 | # Never generate .eh_frame | ||
24 | KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm) | ||
25 | |||
26 | # Never use hard float in kernel | ||
27 | KBUILD_CFLAGS += -msoft-float | ||
28 | |||
29 | ifeq ($(CONFIG_FRAME_POINTER),y) | ||
30 | KBUILD_CFLAGS += -mno-sched-prolog | ||
31 | endif | ||
32 | |||
33 | CHECKFLAGS += -D__unicore32__ | ||
34 | |||
35 | head-y := arch/unicore32/kernel/head.o | ||
36 | head-y += arch/unicore32/kernel/init_task.o | ||
37 | |||
38 | core-y += arch/unicore32/kernel/ | ||
39 | core-y += arch/unicore32/mm/ | ||
40 | |||
41 | libs-y += arch/unicore32/lib/ | ||
42 | |||
43 | ASM_GENERATED_DIR := $(srctree)/arch/unicore32/include/generated | ||
44 | LINUXINCLUDE += -I$(ASM_GENERATED_DIR) | ||
45 | |||
46 | ASM_GENERIC_HEADERS := atomic.h auxvec.h | ||
47 | ASM_GENERIC_HEADERS += bitsperlong.h bug.h bugs.h | ||
48 | ASM_GENERIC_HEADERS += cputime.h current.h | ||
49 | ASM_GENERIC_HEADERS += device.h div64.h | ||
50 | ASM_GENERIC_HEADERS += emergency-restart.h errno.h | ||
51 | ASM_GENERIC_HEADERS += fb.h fcntl.h ftrace.h | ||
52 | ASM_GENERIC_HEADERS += hardirq.h hw_irq.h | ||
53 | ASM_GENERIC_HEADERS += ioctl.h ioctls.h ipcbuf.h irq_regs.h | ||
54 | ASM_GENERIC_HEADERS += kdebug.h kmap_types.h | ||
55 | ASM_GENERIC_HEADERS += local.h | ||
56 | ASM_GENERIC_HEADERS += mman.h module.h msgbuf.h | ||
57 | ASM_GENERIC_HEADERS += param.h parport.h percpu.h poll.h posix_types.h | ||
58 | ASM_GENERIC_HEADERS += resource.h | ||
59 | ASM_GENERIC_HEADERS += scatterlist.h sections.h segment.h sembuf.h serial.h | ||
60 | ASM_GENERIC_HEADERS += setup.h shmbuf.h shmparam.h | ||
61 | ASM_GENERIC_HEADERS += siginfo.h signal.h sizes.h | ||
62 | ASM_GENERIC_HEADERS += socket.h sockios.h stat.h statfs.h swab.h syscalls.h | ||
63 | ASM_GENERIC_HEADERS += termbits.h termios.h topology.h types.h | ||
64 | ASM_GENERIC_HEADERS += ucontext.h unaligned.h user.h | ||
65 | ASM_GENERIC_HEADERS += vga.h | ||
66 | ASM_GENERIC_HEADERS += xor.h | ||
67 | |||
68 | archprepare: | ||
69 | ifneq ($(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; ) | ||
74 | endif | ||
75 | |||
76 | boot := arch/unicore32/boot | ||
77 | |||
78 | # Default target when executing plain make | ||
79 | KBUILD_IMAGE := zImage | ||
80 | |||
81 | all: $(KBUILD_IMAGE) | ||
82 | |||
83 | zImage Image uImage: vmlinux | ||
84 | $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ | ||
85 | |||
86 | MRPROPER_DIRS += $(ASM_GENERATED_DIR) | ||
87 | |||
88 | archclean: | ||
89 | $(Q)$(MAKE) $(clean)=$(boot) | ||
90 | |||
91 | define 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' | ||
95 | endef | ||
diff --git a/arch/unicore32/boot/Makefile b/arch/unicore32/boot/Makefile new file mode 100644 index 000000000000..79e5f88845d9 --- /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 | |||
14 | MKIMAGE := $(srctree)/scripts/mkuboot.sh | ||
15 | |||
16 | targets := 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 | |||
29 | quiet_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 | |||
42 | PHONY += initrd FORCE | ||
43 | initrd: | ||
44 | @test "$(INITRD)" != "" || \ | ||
45 | (echo You must specify INITRD; exit -1) | ||
46 | |||
47 | subdir- := compressed | ||
diff --git a/arch/unicore32/boot/compressed/Makefile b/arch/unicore32/boot/compressed/Makefile new file mode 100644 index 000000000000..95373428cb3d --- /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 | |||
13 | EXTRA_CFLAGS := -fpic -fno-builtin | ||
14 | EXTRA_AFLAGS := -Wa,-march=all | ||
15 | |||
16 | OBJS := misc.o | ||
17 | |||
18 | # font.c and font.o | ||
19 | CFLAGS_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 | ||
24 | suffix_$(CONFIG_KERNEL_GZIP) := gzip | ||
25 | suffix_$(CONFIG_KERNEL_BZIP2) := bz2 | ||
26 | suffix_$(CONFIG_KERNEL_LZO) := lzo | ||
27 | suffix_$(CONFIG_KERNEL_LZMA) := lzma | ||
28 | |||
29 | $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE | ||
30 | $(call if_changed,$(suffix_y)) | ||
31 | |||
32 | SEDFLAGS_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 | |||
38 | targets := 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 | ||
42 | extra-y += piggy.gzip piggy.bz2 piggy.lzo piggy.lzma | ||
43 | |||
44 | # ? | ||
45 | LDFLAGS_vmlinux += -p | ||
46 | # Report unresolved symbol references | ||
47 | LDFLAGS_vmlinux += --no-undefined | ||
48 | # Delete all temporary local symbols | ||
49 | LDFLAGS_vmlinux += -X | ||
50 | # Next argument is a linker script | ||
51 | LDFLAGS_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) | ||
62 | ZTEXTADDR := 0 | ||
63 | ZBSSADDR := ALIGN(4) | ||
64 | |||
65 | SEDFLAGS_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 000000000000..fbd1e374c685 --- /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 | ||
21 | start: | ||
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 | */ | ||
66 | 1001: ldw r1, [r7+], #0 | ||
67 | add r1, r1, r0 | ||
68 | stw.w r1, [r7]+, #4 | ||
69 | csub.a r7, r8 | ||
70 | bub 1001b | ||
71 | |||
72 | not_relocated: | ||
73 | /* | ||
74 | * Clear BSS region. | ||
75 | * r2 - BSS start | ||
76 | * r3 - BSS end | ||
77 | */ | ||
78 | mov r0, #0 | ||
79 | 1002: 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 | */ | ||
129 | wont_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 | ||
162 | LC0: .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 | |||
172 | print_string: | ||
173 | #ifdef CONFIG_DEBUG_OCD | ||
174 | 2001: ldb.w r1, [r0]+, #1 | ||
175 | csub.a r1, #0 | ||
176 | bne 2002f | ||
177 | mov pc, lr | ||
178 | 2002: | ||
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 | ||
194 | 2001: nop8 | ||
195 | b 2001b | ||
196 | str_error: .asciz "\nError: Kernel address OVERWRITE\n" | ||
197 | .align | ||
198 | |||
199 | .ltorg | ||
200 | |||
201 | .align 4 | ||
202 | .section ".stack", "aw", %nobits | ||
203 | decompress_stack: .space 4096 | ||
204 | decompress_stack_end: | ||
diff --git a/arch/unicore32/boot/compressed/misc.c b/arch/unicore32/boot/compressed/misc.c new file mode 100644 index 000000000000..176d5bda3559 --- /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 | */ | ||
19 | unsigned char *output_data; | ||
20 | unsigned long output_ptr; | ||
21 | |||
22 | unsigned int free_mem_ptr; | ||
23 | unsigned 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 | |||
43 | void *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 | |||
77 | void 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 | |||
106 | unsigned 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 000000000000..b79704d58026 --- /dev/null +++ b/arch/unicore32/boot/compressed/piggy.S.in | |||
@@ -0,0 +1,6 @@ | |||
1 | .section .piggydata,#alloc | ||
2 | .globl input_data | ||
3 | input_data: | ||
4 | .incbin "arch/unicore32/boot/compressed/piggy.DECOMP_SUFFIX" | ||
5 | .globl input_data_end | ||
6 | input_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 000000000000..d5a3ce296239 --- /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 | */ | ||
12 | OUTPUT_ARCH(unicore32) | ||
13 | ENTRY(_start) | ||
14 | SECTIONS | ||
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 000000000000..b5fbde9f1cb2 --- /dev/null +++ b/arch/unicore32/configs/debug_defconfig | |||
@@ -0,0 +1,215 @@ | |||
1 | ### General setup | ||
2 | CONFIG_EXPERIMENTAL=y | ||
3 | CONFIG_LOCALVERSION="-debug" | ||
4 | CONFIG_SWAP=y | ||
5 | CONFIG_SYSVIPC=y | ||
6 | CONFIG_POSIX_MQUEUE=y | ||
7 | CONFIG_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 | ||
13 | CONFIG_MODULES=n | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | |||
16 | ### System Type | ||
17 | CONFIG_ARCH_PUV3=y | ||
18 | # Board Selection | ||
19 | CONFIG_PUV3_NB0916=y | ||
20 | # Processor Features | ||
21 | CONFIG_CPU_DCACHE_LINE_DISABLE=y | ||
22 | CONFIG_CPU_TLB_SINGLE_ENTRY_DISABLE=n | ||
23 | |||
24 | ### Bus support | ||
25 | CONFIG_PCI=y | ||
26 | CONFIG_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 | ||
32 | CONFIG_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 | ||
36 | CONFIG_CMDLINE_FORCE=y | ||
37 | |||
38 | ### Power management options | ||
39 | CONFIG_PM=y | ||
40 | CONFIG_HIBERNATION=y | ||
41 | CONFIG_PM_STD_PARTITION="/dev/sda3" | ||
42 | CONFIG_CPU_FREQ=n | ||
43 | CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y | ||
44 | |||
45 | ### Networking support | ||
46 | CONFIG_NET=y | ||
47 | # Networking options | ||
48 | CONFIG_PACKET=m | ||
49 | CONFIG_UNIX=m | ||
50 | # TCP/IP networking | ||
51 | CONFIG_INET=y | ||
52 | CONFIG_IP_MULTICAST=y | ||
53 | CONFIG_IP_PNP=y | ||
54 | CONFIG_IPV6=n | ||
55 | # Wireless | ||
56 | CONFIG_WIRELESS=y | ||
57 | CONFIG_WIRELESS_EXT=y | ||
58 | CONFIG_MAC80211=m | ||
59 | |||
60 | ### PKUnity SoC Features | ||
61 | CONFIG_USB_WLAN_HED_AQ3=n | ||
62 | CONFIG_USB_CMMB_INNOFIDEI=n | ||
63 | CONFIG_I2C_BATTERY_BQ27200=n | ||
64 | CONFIG_I2C_EEPROM_AT24=n | ||
65 | CONFIG_LCD_BACKLIGHT=n | ||
66 | |||
67 | CONFIG_PUV3_RTC=y | ||
68 | CONFIG_PUV3_UMAL=y | ||
69 | CONFIG_PUV3_MUSB=n | ||
70 | CONFIG_PUV3_AC97=n | ||
71 | CONFIG_PUV3_NAND=n | ||
72 | CONFIG_PUV3_MMC=n | ||
73 | CONFIG_PUV3_UART=n | ||
74 | |||
75 | ### Device Drivers | ||
76 | # Memory Technology Device (MTD) support | ||
77 | CONFIG_MTD=m | ||
78 | CONFIG_MTD_UBI=m | ||
79 | CONFIG_MTD_PARTITIONS=y | ||
80 | CONFIG_MTD_CHAR=m | ||
81 | CONFIG_MTD_BLKDEVS=m | ||
82 | # RAM/ROM/Flash chip drivers | ||
83 | CONFIG_MTD_CFI=m | ||
84 | CONFIG_MTD_JEDECPROBE=m | ||
85 | CONFIG_MTD_CFI_AMDSTD=m | ||
86 | # Mapping drivers for chip access | ||
87 | CONFIG_MTD_PHYSMAP=m | ||
88 | |||
89 | # Block devices | ||
90 | CONFIG_BLK_DEV_LOOP=m | ||
91 | |||
92 | # SCSI device support | ||
93 | CONFIG_SCSI=y | ||
94 | CONFIG_BLK_DEV_SD=y | ||
95 | CONFIG_BLK_DEV_SR=m | ||
96 | CONFIG_CHR_DEV_SG=m | ||
97 | |||
98 | # Serial ATA (prod) and Parallel ATA (experimental) drivers | ||
99 | CONFIG_ATA=y | ||
100 | CONFIG_SATA_VIA=y | ||
101 | |||
102 | # Network device support | ||
103 | CONFIG_NETDEVICES=y | ||
104 | CONFIG_NET_ETHERNET=y | ||
105 | CONFIG_NETDEV_1000=y | ||
106 | # Wireless LAN | ||
107 | CONFIG_WLAN_80211=n | ||
108 | CONFIG_RT2X00=n | ||
109 | CONFIG_RT73USB=n | ||
110 | |||
111 | # Input device support | ||
112 | CONFIG_INPUT_EVDEV=m | ||
113 | # Keyboards | ||
114 | CONFIG_KEYBOARD_GPIO=m | ||
115 | |||
116 | # I2C support | ||
117 | CONFIG_I2C=y | ||
118 | CONFIG_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 | ||
127 | CONFIG_MEDIA_SUPPORT=n | ||
128 | CONFIG_VIDEO_DEV=n | ||
129 | CONFIG_USB_VIDEO_CLASS=n | ||
130 | |||
131 | # Graphics support | ||
132 | CONFIG_FB=y | ||
133 | CONFIG_FB_PUV3_UNIGFX=y | ||
134 | # Console display driver support | ||
135 | CONFIG_VGA_CONSOLE=n | ||
136 | CONFIG_FRAMEBUFFER_CONSOLE=y | ||
137 | CONFIG_FONTS=y | ||
138 | CONFIG_FONT_8x8=y | ||
139 | CONFIG_FONT_8x16=y | ||
140 | # Bootup logo | ||
141 | CONFIG_LOGO=n | ||
142 | |||
143 | # Sound card support | ||
144 | CONFIG_SOUND=m | ||
145 | # Advanced Linux Sound Architecture | ||
146 | CONFIG_SND=m | ||
147 | CONFIG_SND_MIXER_OSS=m | ||
148 | CONFIG_SND_PCM_OSS=m | ||
149 | |||
150 | # USB support | ||
151 | CONFIG_USB_ARCH_HAS_HCD=n | ||
152 | CONFIG_USB=n | ||
153 | CONFIG_USB_DEVICEFS=n | ||
154 | CONFIG_USB_PRINTER=n | ||
155 | CONFIG_USB_STORAGE=n | ||
156 | # Inventra Highspeed Dual Role Controller | ||
157 | CONFIG_USB_MUSB_HDRC=n | ||
158 | |||
159 | # LED Support | ||
160 | CONFIG_NEW_LEDS=y | ||
161 | CONFIG_LEDS_CLASS=y | ||
162 | CONFIG_LEDS_GPIO=y | ||
163 | # LED Triggers | ||
164 | CONFIG_LEDS_TRIGGERS=y | ||
165 | CONFIG_LEDS_TRIGGER_TIMER=y | ||
166 | CONFIG_LEDS_TRIGGER_IDE_DISK=y | ||
167 | CONFIG_LEDS_TRIGGER_HEARTBEAT=y | ||
168 | |||
169 | # Real Time Clock | ||
170 | CONFIG_RTC_LIB=m | ||
171 | CONFIG_RTC_CLASS=m | ||
172 | |||
173 | ### File systems | ||
174 | CONFIG_EXT2_FS=m | ||
175 | CONFIG_EXT3_FS=y | ||
176 | CONFIG_EXT4_FS=y | ||
177 | CONFIG_FUSE_FS=m | ||
178 | # CD-ROM/DVD Filesystems | ||
179 | CONFIG_ISO9660_FS=m | ||
180 | CONFIG_JOLIET=y | ||
181 | CONFIG_UDF_FS=m | ||
182 | # DOS/FAT/NT Filesystems | ||
183 | CONFIG_VFAT_FS=m | ||
184 | # Pseudo filesystems | ||
185 | CONFIG_PROC_FS=y | ||
186 | CONFIG_SYSFS=y | ||
187 | CONFIG_TMPFS=y | ||
188 | # Miscellaneous filesystems | ||
189 | CONFIG_MISC_FILESYSTEMS=y | ||
190 | CONFIG_JFFS2_FS=m | ||
191 | CONFIG_UBIFS_FS=m | ||
192 | # Network File Systems | ||
193 | CONFIG_NETWORK_FILESYSTEMS=y | ||
194 | CONFIG_NFS_FS=y | ||
195 | CONFIG_NFS_V3=y | ||
196 | CONFIG_ROOT_NFS=y | ||
197 | # Partition Types | ||
198 | CONFIG_PARTITION_ADVANCED=y | ||
199 | CONFIG_MSDOS_PARTITION=y | ||
200 | # Native language support | ||
201 | CONFIG_NLS=y | ||
202 | CONFIG_NLS_CODEPAGE_437=m | ||
203 | CONFIG_NLS_CODEPAGE_936=m | ||
204 | CONFIG_NLS_ISO8859_1=m | ||
205 | CONFIG_NLS_UTF8=m | ||
206 | |||
207 | ### Kernel hacking | ||
208 | CONFIG_FRAME_WARN=8096 | ||
209 | CONFIG_MAGIC_SYSRQ=y | ||
210 | CONFIG_DEBUG_KERNEL=y | ||
211 | CONFIG_PROVE_LOCKING=n | ||
212 | CONFIG_DEBUG_BUGVERBOSE=y | ||
213 | CONFIG_FRAME_POINTER=y | ||
214 | CONFIG_DEBUG_LL=y | ||
215 | |||
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild new file mode 100644 index 000000000000..b200fdaca44d --- /dev/null +++ b/arch/unicore32/include/asm/Kbuild | |||
@@ -0,0 +1,2 @@ | |||
1 | include 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 000000000000..8e87ed7faeba --- /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...) \ | ||
58 | 9999: 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 | ||
103 | 9999 : | ||
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 000000000000..1628a6328994 --- /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 | |||
31 | static 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 000000000000..ebe1b3fef3e3 --- /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 000000000000..ad8f795d86ca --- /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 000000000000..c0301e6c8b81 --- /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 | |||
95 | extern void __cpuc_flush_icache_all(void); | ||
96 | extern void __cpuc_flush_kern_all(void); | ||
97 | extern void __cpuc_flush_user_all(void); | ||
98 | extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); | ||
99 | extern void __cpuc_coherent_kern_range(unsigned long, unsigned long); | ||
100 | extern void __cpuc_coherent_user_range(unsigned long, unsigned long); | ||
101 | extern void __cpuc_flush_dcache_area(void *, size_t); | ||
102 | extern 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 | */ | ||
110 | extern void __cpuc_dma_clean_range(unsigned long, unsigned long); | ||
111 | extern 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 | */ | ||
118 | extern 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 */ | ||
129 | static 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 | |||
139 | extern void flush_cache_mm(struct mm_struct *mm); | ||
140 | extern void flush_cache_range(struct vm_area_struct *vma, | ||
141 | unsigned long start, unsigned long end); | ||
142 | extern 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 | ||
180 | extern 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 | */ | ||
203 | static inline void flush_cache_vmap(unsigned long start, unsigned long end) | ||
204 | { | ||
205 | } | ||
206 | |||
207 | static 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 000000000000..f55c3f937c3e --- /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 | |||
22 | static inline __wsum | ||
23 | csum_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 000000000000..0f55d1823439 --- /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 | |||
32 | struct mm_struct; | ||
33 | |||
34 | /* declare all the functions as extern */ | ||
35 | extern void cpu_proc_fin(void); | ||
36 | extern int cpu_do_idle(void); | ||
37 | extern void cpu_dcache_clean_area(void *, int); | ||
38 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); | ||
39 | extern void cpu_set_pte(pte_t *ptep, pte_t pte); | ||
40 | extern 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 000000000000..ec1a30f98077 --- /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 000000000000..164ae61cd6f7 --- /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 | |||
19 | extern 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 | */ | ||
28 | extern 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 | */ | ||
40 | extern void __udelay(unsigned long usecs); | ||
41 | extern 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 000000000000..9258e592f414 --- /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 | |||
26 | extern struct dma_map_ops swiotlb_dma_map_ops; | ||
27 | |||
28 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) | ||
29 | { | ||
30 | return &swiotlb_dma_map_ops; | ||
31 | } | ||
32 | |||
33 | static 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 | |||
43 | static 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 | |||
55 | static 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 | |||
63 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | ||
64 | { | ||
65 | return paddr; | ||
66 | } | ||
67 | |||
68 | static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) | ||
69 | { | ||
70 | return daddr; | ||
71 | } | ||
72 | |||
73 | static inline void dma_mark_clean(void *addr, size_t size) {} | ||
74 | |||
75 | static 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 | |||
85 | static 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 | |||
93 | static 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 | |||
104 | static 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 000000000000..38dfff9df32f --- /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 | ||
20 | extern 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 000000000000..829042d07722 --- /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 | |||
23 | typedef unsigned long elf_greg_t; | ||
24 | typedef unsigned long elf_freg_t[3]; | ||
25 | |||
26 | #define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) | ||
27 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | ||
28 | |||
29 | typedef 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 | |||
55 | extern char elf_platform[]; | ||
56 | |||
57 | struct elf32_hdr; | ||
58 | |||
59 | /* | ||
60 | * This is used to ensure we don't load something for the wrong architecture. | ||
61 | */ | ||
62 | extern int elf_check_arch(const struct elf32_hdr *); | ||
63 | #define elf_check_arch elf_check_arch | ||
64 | |||
65 | struct task_struct; | ||
66 | int 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 | |||
83 | extern void elf_set_personality(const struct elf32_hdr *); | ||
84 | #define SET_PERSONALITY(ex) elf_set_personality(&(ex)) | ||
85 | |||
86 | struct mm_struct; | ||
87 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); | ||
88 | #define arch_randomize_brk arch_randomize_brk | ||
89 | |||
90 | extern 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 000000000000..ba97fac6220d --- /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 | |||
20 | struct 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 000000000000..16c1457882ee --- /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 000000000000..07dea6170558 --- /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 | |||
42 | static inline int | ||
43 | futex_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 | |||
109 | static inline int | ||
110 | futex_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 000000000000..2716f14e3ff6 --- /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 | |||
67 | static 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 | |||
75 | static 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 | |||
88 | static 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 | |||
96 | static 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 000000000000..97bd40fdd4ac --- /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 000000000000..4bd87f3d13d4 --- /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 | */ | ||
27 | extern void __iomem *__uc32_ioremap(unsigned long, size_t); | ||
28 | extern void __iomem *__uc32_ioremap_cached(unsigned long, size_t); | ||
29 | extern 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 000000000000..baea93e2a6e6 --- /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__ | ||
98 | struct pt_regs; | ||
99 | |||
100 | extern 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 000000000000..6d8a28dfdbae --- /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 | */ | ||
25 | static 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 | */ | ||
37 | static 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 000000000000..d1618bd35b67 --- /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 000000000000..a8a5d8d0a26e --- /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 | |||
21 | struct membank { | ||
22 | unsigned long start; | ||
23 | unsigned long size; | ||
24 | unsigned int highmem; | ||
25 | }; | ||
26 | |||
27 | struct meminfo { | ||
28 | int nr_banks; | ||
29 | struct membank bank[NR_BANKS]; | ||
30 | }; | ||
31 | |||
32 | extern 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 | |||
44 | extern 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 000000000000..5eddb997defe --- /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 000000000000..66fa341dc2c6 --- /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 | |||
15 | typedef 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 000000000000..fb5e4c658f7a --- /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 | */ | ||
35 | static inline void | ||
36 | enter_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 | */ | ||
46 | static inline void | ||
47 | switch_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) \ | ||
67 | do { \ | ||
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 | |||
82 | static 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 000000000000..fab7d0e8adf6 --- /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 000000000000..594b3226250e --- /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 | |||
22 | struct page; | ||
23 | struct vm_area_struct; | ||
24 | |||
25 | #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) | ||
26 | extern 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 | */ | ||
37 | typedef struct { unsigned long pte; } pte_t; | ||
38 | typedef struct { unsigned long pgd; } pgd_t; | ||
39 | typedef 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 | */ | ||
53 | typedef unsigned long pte_t; | ||
54 | typedef unsigned long pgd_t; | ||
55 | typedef 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 | |||
67 | typedef struct page *pgtable_t; | ||
68 | |||
69 | extern 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 000000000000..c5b28b459535 --- /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 | |||
20 | static inline void pcibios_set_master(struct pci_dev *dev) | ||
21 | { | ||
22 | /* No special bus mastering setup handling */ | ||
23 | } | ||
24 | |||
25 | static 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 | ||
31 | static 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 | ||
41 | extern 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 000000000000..0213e373a895 --- /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 | |||
25 | extern pgd_t *get_pgd_slow(struct mm_struct *mm); | ||
26 | extern 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 | */ | ||
36 | static inline pte_t * | ||
37 | pte_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 | |||
48 | static inline pgtable_t | ||
49 | pte_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 | */ | ||
68 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
69 | { | ||
70 | if (pte) | ||
71 | free_page((unsigned long)pte); | ||
72 | } | ||
73 | |||
74 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
75 | { | ||
76 | pgtable_page_dtor(pte); | ||
77 | __free_page(pte); | ||
78 | } | ||
79 | |||
80 | static 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 | */ | ||
90 | static inline void | ||
91 | pmd_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 | |||
102 | static inline void | ||
103 | pmd_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 000000000000..7314e859cca0 --- /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 000000000000..68b2f297ac97 --- /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__ | ||
49 | extern void __pte_error(const char *file, int line, unsigned long val); | ||
50 | extern 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 | |||
85 | extern pgprot_t pgprot_user; | ||
86 | extern 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 | */ | ||
149 | extern 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) \ | ||
185 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } | ||
186 | |||
187 | PTE_BIT_FUNC(wrprotect, &= ~PTE_WRITE); | ||
188 | PTE_BIT_FUNC(mkwrite, |= PTE_WRITE); | ||
189 | PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); | ||
190 | PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); | ||
191 | PTE_BIT_FUNC(mkold, &= ~PTE_YOUNG); | ||
192 | PTE_BIT_FUNC(mkyoung, |= PTE_YOUNG); | ||
193 | |||
194 | static 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 | |||
243 | static 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 | |||
250 | extern 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 000000000000..e11cb0786578 --- /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 | |||
32 | struct debug_entry { | ||
33 | u32 address; | ||
34 | u32 insn; | ||
35 | }; | ||
36 | |||
37 | struct debug_info { | ||
38 | int nsaved; | ||
39 | struct debug_entry bp[2]; | ||
40 | }; | ||
41 | |||
42 | struct 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 */ | ||
67 | struct task_struct; | ||
68 | |||
69 | /* Free all resources held by a thread. */ | ||
70 | extern 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 | |||
75 | unsigned long get_wchan(struct task_struct *p); | ||
76 | |||
77 | #define cpu_relax() barrier() | ||
78 | |||
79 | /* | ||
80 | * Create a new kernel thread | ||
81 | */ | ||
82 | extern 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 000000000000..b9caf9b0997b --- /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 | */ | ||
48 | struct 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 | */ | ||
104 | static 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 000000000000..6a2d7671c052 --- /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 | */ | ||
21 | struct 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 000000000000..76edc65a5871 --- /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 | |||
16 | struct stackframe { | ||
17 | unsigned long fp; | ||
18 | unsigned long sp; | ||
19 | unsigned long lr; | ||
20 | unsigned long pc; | ||
21 | }; | ||
22 | |||
23 | #ifdef CONFIG_FRAME_POINTER | ||
24 | extern int unwind_frame(struct stackframe *frame); | ||
25 | #else | ||
26 | #define unwind_frame(f) (-EINVAL) | ||
27 | #endif | ||
28 | extern 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 000000000000..55264c84369a --- /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 | ||
21 | extern char *strrchr(const char *s, int c); | ||
22 | |||
23 | #define __HAVE_ARCH_STRCHR | ||
24 | extern char *strchr(const char *s, int c); | ||
25 | |||
26 | #define __HAVE_ARCH_MEMCPY | ||
27 | extern void *memcpy(void *, const void *, __kernel_size_t); | ||
28 | |||
29 | #define __HAVE_ARCH_MEMMOVE | ||
30 | extern void *memmove(void *, const void *, __kernel_size_t); | ||
31 | |||
32 | #define __HAVE_ARCH_MEMCHR | ||
33 | extern void *memchr(const void *, int, __kernel_size_t); | ||
34 | |||
35 | #define __HAVE_ARCH_MEMSET | ||
36 | extern 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 000000000000..88a9c0f32b21 --- /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__ | ||
17 | static inline int arch_prepare_suspend(void) { return 0; } | ||
18 | |||
19 | #include <asm/ptrace.h> | ||
20 | |||
21 | struct 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 000000000000..246b71c17fda --- /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 | |||
33 | struct thread_info; | ||
34 | struct task_struct; | ||
35 | |||
36 | struct pt_regs; | ||
37 | |||
38 | void die(const char *msg, struct pt_regs *regs, int err); | ||
39 | |||
40 | struct siginfo; | ||
41 | void uc32_notify_die(const char *str, struct pt_regs *regs, | ||
42 | struct siginfo *info, unsigned long err, unsigned long trap); | ||
43 | |||
44 | void 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 | |||
51 | extern asmlinkage void __backtrace(void); | ||
52 | extern asmlinkage void c_backtrace(unsigned long fp, int pmode); | ||
53 | |||
54 | struct mm_struct; | ||
55 | extern void show_pte(struct mm_struct *mm, unsigned long addr); | ||
56 | extern void __show_regs(struct pt_regs *); | ||
57 | |||
58 | extern int cpu_architecture(void); | ||
59 | extern 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 | |||
79 | extern unsigned long cr_no_alignment; /* defined in entry-unicore.S */ | ||
80 | extern unsigned long cr_alignment; /* defined in entry-unicore.S */ | ||
81 | |||
82 | static 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 | |||
89 | static 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 | |||
96 | extern 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 | */ | ||
103 | extern struct task_struct *__switch_to(struct task_struct *, | ||
104 | struct thread_info *, struct thread_info *); | ||
105 | extern void panic(const char *fmt, ...); | ||
106 | |||
107 | #define switch_to(prev, next, last) \ | ||
108 | do { \ | ||
109 | last = __switch_to(prev, \ | ||
110 | task_thread_info(prev), task_thread_info(next)); \ | ||
111 | } while (0) | ||
112 | |||
113 | static 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 000000000000..c270e9e04861 --- /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 | |||
26 | struct task_struct; | ||
27 | struct exec_domain; | ||
28 | |||
29 | #include <asm/types.h> | ||
30 | |||
31 | typedef struct { | ||
32 | unsigned long seg; | ||
33 | } mm_segment_t; | ||
34 | |||
35 | struct 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 | */ | ||
68 | struct 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 | */ | ||
103 | static inline struct thread_info *current_thread_info(void) __attribute_const__; | ||
104 | |||
105 | static 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 000000000000..faf16ba46544 --- /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 000000000000..9cca15cdae94 --- /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 000000000000..e446ac8bb9e5 --- /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 | |||
19 | extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, | ||
20 | struct vm_area_struct *); | ||
21 | extern 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 | |||
66 | static 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 | |||
75 | static 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 | |||
87 | static inline void | ||
88 | local_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 | |||
106 | static 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 | */ | ||
135 | static 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 | |||
154 | static 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 | */ | ||
187 | extern void update_mmu_cache(struct vm_area_struct *vma, | ||
188 | unsigned long addr, pte_t *ptep); | ||
189 | |||
190 | extern 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 000000000000..66e17a724bfe --- /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 | |||
15 | extern void __init early_trap_init(void); | ||
16 | extern void dump_backtrace_entry(unsigned long where, | ||
17 | unsigned long from, unsigned long frame); | ||
18 | |||
19 | extern 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 000000000000..2acda503a6d9 --- /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 | |||
32 | extern unsigned long __must_check | ||
33 | __copy_from_user(void *to, const void __user *from, unsigned long n); | ||
34 | extern unsigned long __must_check | ||
35 | __copy_to_user(void __user *to, const void *from, unsigned long n); | ||
36 | extern unsigned long __must_check | ||
37 | __clear_user(void __user *addr, unsigned long n); | ||
38 | extern unsigned long __must_check | ||
39 | __strncpy_from_user(char *to, const char __user *from, unsigned long count); | ||
40 | extern unsigned long | ||
41 | __strnlen_user(const char __user *s, long n); | ||
42 | |||
43 | #include <asm-generic/uaccess.h> | ||
44 | |||
45 | extern 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 000000000000..9b2428019961 --- /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 000000000000..a18bdc3810e6 --- /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 000000000000..128a70281efc --- /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 000000000000..d655c1b6e083 --- /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 | |||
20 | typedef 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 | |||
30 | extern 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 | |||
36 | extern void puv3_free_dma(int dma_ch); | ||
37 | |||
38 | static inline void puv3_stop_dma(int ch) | ||
39 | { | ||
40 | writel(readl(DMAC_CONFIG(ch)) & ~DMAC_CONFIG_EN, DMAC_CONFIG(ch)); | ||
41 | } | ||
42 | |||
43 | static 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 000000000000..930bea6e129a --- /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 000000000000..55c936573741 --- /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 000000000000..0bf21c944710 --- /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 | |||
31 | void 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 000000000000..189fd71bfa34 --- /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) | ||
17 | static 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 000000000000..4dcd34ae194c --- /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 | |||
17 | struct 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 | |||
27 | extern struct puv3_cpu_pm_fns *puv3_cpu_pm_fns; | ||
28 | |||
29 | /* sleep.S */ | ||
30 | extern void puv3_cpu_suspend(unsigned int); | ||
31 | |||
32 | extern void puv3_cpu_resume(void); | ||
33 | |||
34 | extern int puv3_pm_enter(suspend_state_t state); | ||
35 | |||
36 | /* Defined in hibernate_asm.S */ | ||
37 | extern int restore_image(pgd_t *resume_pg_dir, struct pbe *restore_pblist); | ||
38 | |||
39 | /* References to section boundaries */ | ||
40 | extern const void __nosave_begin, __nosave_end; | ||
41 | |||
42 | extern 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 000000000000..b7563e9d6503 --- /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 000000000000..66de9e7d1c8f --- /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 000000000000..0273b861ef96 --- /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 000000000000..463d108f8bfb --- /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 000000000000..25648f89cbd3 --- /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 000000000000..a7c5563bb550 --- /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 000000000000..7b91fe698eed --- /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 000000000000..6a9341686bf8 --- /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 000000000000..854844aa8f4b --- /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 000000000000..17d4e6dc0069 --- /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 000000000000..39900cf4c936 --- /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 000000000000..e94ca193271d --- /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 000000000000..1303ecf660ba --- /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 000000000000..de16895e2dc0 --- /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 000000000000..9fa6b1938b77 --- /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 000000000000..885bb62fee71 --- /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 000000000000..faf8b287fccf --- /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 000000000000..142d3e7958a9 --- /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 | |||
19 | extern char input_data[]; | ||
20 | extern char input_data_end[]; | ||
21 | |||
22 | static 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 000000000000..ec23a2fb2f50 --- /dev/null +++ b/arch/unicore32/kernel/Makefile | |||
@@ -0,0 +1,33 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | # Object file lists. | ||
6 | obj-y := dma.o elf.o entry.o process.o ptrace.o | ||
7 | obj-y += setup.o signal.o sys.o stacktrace.o traps.o | ||
8 | |||
9 | obj-$(CONFIG_MODULES) += ksyms.o module.o | ||
10 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
11 | |||
12 | obj-$(CONFIG_CPU_FREQ) += cpu-ucv2.o | ||
13 | obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o | ||
14 | |||
15 | # obj-y for architecture PKUnity v3 | ||
16 | obj-$(CONFIG_ARCH_PUV3) += clock.o irq.o time.o | ||
17 | |||
18 | obj-$(CONFIG_PUV3_GPIO) += gpio.o | ||
19 | obj-$(CONFIG_PUV3_RTC) += rtc.o | ||
20 | obj-$(CONFIG_PUV3_PWM) += pwm.o | ||
21 | obj-$(CONFIG_PUV3_PM) += pm.o sleep.o | ||
22 | obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o | ||
23 | |||
24 | obj-$(CONFIG_PCI) += pci.o | ||
25 | |||
26 | # obj-y for specific machines | ||
27 | obj-$(CONFIG_ARCH_PUV3) += puv3-core.o | ||
28 | obj-$(CONFIG_PUV3_NB0916) += puv3-nb0916.o | ||
29 | |||
30 | head-y := head.o | ||
31 | obj-$(CONFIG_DEBUG_LL) += debug.o | ||
32 | |||
33 | extra-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 000000000000..ffcbe7536ca7 --- /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 | |||
37 | int 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 000000000000..18d4563e6fa5 --- /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 | */ | ||
30 | struct clk { | ||
31 | struct list_head node; | ||
32 | unsigned long rate; | ||
33 | const char *name; | ||
34 | }; | ||
35 | |||
36 | static struct clk clk_ost_clk = { | ||
37 | .name = "OST_CLK", | ||
38 | .rate = CLOCK_TICK_RATE, | ||
39 | }; | ||
40 | |||
41 | static struct clk clk_mclk_clk = { | ||
42 | .name = "MAIN_CLK", | ||
43 | }; | ||
44 | |||
45 | static struct clk clk_bclk32_clk = { | ||
46 | .name = "BUS32_CLK", | ||
47 | }; | ||
48 | |||
49 | static struct clk clk_ddr_clk = { | ||
50 | .name = "DDR_CLK", | ||
51 | }; | ||
52 | |||
53 | static struct clk clk_vga_clk = { | ||
54 | .name = "VGA_CLK", | ||
55 | }; | ||
56 | |||
57 | static LIST_HEAD(clocks); | ||
58 | static DEFINE_MUTEX(clocks_mutex); | ||
59 | |||
60 | struct 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 | } | ||
75 | EXPORT_SYMBOL(clk_get); | ||
76 | |||
77 | void clk_put(struct clk *clk) | ||
78 | { | ||
79 | } | ||
80 | EXPORT_SYMBOL(clk_put); | ||
81 | |||
82 | int clk_enable(struct clk *clk) | ||
83 | { | ||
84 | return 0; | ||
85 | } | ||
86 | EXPORT_SYMBOL(clk_enable); | ||
87 | |||
88 | void clk_disable(struct clk *clk) | ||
89 | { | ||
90 | } | ||
91 | EXPORT_SYMBOL(clk_disable); | ||
92 | |||
93 | unsigned long clk_get_rate(struct clk *clk) | ||
94 | { | ||
95 | return clk->rate; | ||
96 | } | ||
97 | EXPORT_SYMBOL(clk_get_rate); | ||
98 | |||
99 | struct { | ||
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 | |||
117 | struct { | ||
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 | |||
136 | int 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 | } | ||
215 | EXPORT_SYMBOL(clk_set_rate); | ||
216 | |||
217 | int 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 | } | ||
226 | EXPORT_SYMBOL(clk_register); | ||
227 | |||
228 | void clk_unregister(struct clk *clk) | ||
229 | { | ||
230 | mutex_lock(&clocks_mutex); | ||
231 | list_del(&clk->node); | ||
232 | mutex_unlock(&clocks_mutex); | ||
233 | } | ||
234 | EXPORT_SYMBOL(clk_unregister); | ||
235 | |||
236 | struct { | ||
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 | |||
304 | struct { | ||
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 | |||
325 | static 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 | } | ||
390 | core_initcall(clk_init); | ||
diff --git a/arch/unicore32/kernel/cpu-ucv2.c b/arch/unicore32/kernel/cpu-ucv2.c new file mode 100644 index 000000000000..4a99f62584c7 --- /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 | |||
22 | static 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 | */ | ||
27 | int 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 | |||
38 | static 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 | |||
47 | static 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 | |||
68 | static 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 | |||
79 | static 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 | |||
88 | static int __init ucv2_cpufreq_init(void) | ||
89 | { | ||
90 | return cpufreq_register_driver(&ucv2_driver); | ||
91 | } | ||
92 | |||
93 | arch_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 000000000000..2711d6d87d8e --- /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 | ||
18 | 1001: 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 | ||
78 | 1001: ldr \rd, [\rx, #UART_LSR_OFFSET] | ||
79 | tst \rd, #UART_LSR_THRE | ||
80 | beq 1001b | ||
81 | .endm | ||
82 | |||
83 | .macro busyuart,rd,rx | ||
84 | 1001: 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 000000000000..029fd12f6ab0 --- /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 | */ | ||
29 | ENTRY(printhex8) | ||
30 | mov r1, #8 | ||
31 | b printhex | ||
32 | ENDPROC(printhex8) | ||
33 | |||
34 | ENTRY(printhex4) | ||
35 | mov r1, #4 | ||
36 | b printhex | ||
37 | ENDPROC(printhex4) | ||
38 | |||
39 | ENTRY(printhex2) | ||
40 | mov r1, #2 | ||
41 | printhex: adr r2, hexbuf | ||
42 | add r3, r2, r1 | ||
43 | mov r1, #0 | ||
44 | stb r1, [r3] | ||
45 | 1: and r1, r0, #15 | ||
46 | mov r0, r0 >> #4 | ||
47 | csub.a r1, #10 | ||
48 | beg 2f | ||
49 | add r1, r1, #'0' - 'a' + 10 | ||
50 | 2: 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 | ||
56 | ENDPROC(printhex2) | ||
57 | |||
58 | .ltorg | ||
59 | |||
60 | ENTRY(printascii) | ||
61 | addruart r3 | ||
62 | b 2f | ||
63 | 1: waituart r2, r3 | ||
64 | senduart r1, r3 | ||
65 | busyuart r2, r3 | ||
66 | cxor.a r1, #'\n' | ||
67 | cmoveq r1, #'\r' | ||
68 | beq 1b | ||
69 | 2: cxor.a r0, #0 | ||
70 | beq 3f | ||
71 | ldb.w r1, [r0]+, #1 | ||
72 | cxor.a r1, #0 | ||
73 | bne 1b | ||
74 | 3: mov pc, lr | ||
75 | ENDPROC(printascii) | ||
76 | |||
77 | ENTRY(printch) | ||
78 | addruart r3 | ||
79 | mov r1, r0 | ||
80 | mov r0, #0 | ||
81 | b 1b | ||
82 | ENDPROC(printch) | ||
83 | |||
84 | hexbuf: .space 16 | ||
85 | |||
diff --git a/arch/unicore32/kernel/dma.c b/arch/unicore32/kernel/dma.c new file mode 100644 index 000000000000..ae441bc3122c --- /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 | |||
26 | struct 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 | |||
34 | static struct dma_channel dma_channels[MAX_DMA_CHANNELS]; | ||
35 | |||
36 | int 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 | } | ||
76 | EXPORT_SYMBOL(puv3_request_dma); | ||
77 | |||
78 | void 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 | } | ||
94 | EXPORT_SYMBOL(puv3_free_dma); | ||
95 | |||
96 | static 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 | |||
124 | static 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 | |||
152 | int __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 | |||
183 | postcore_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 000000000000..3922255f1fa8 --- /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 | |||
19 | static 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 | |||
29 | static 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 */ | ||
37 | static struct console *early_console = &early_ocd_console; | ||
38 | |||
39 | static int __initdata keep_early; | ||
40 | |||
41 | static 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 | } | ||
59 | early_param("earlyprintk", setup_early_printk); | ||
diff --git a/arch/unicore32/kernel/elf.c b/arch/unicore32/kernel/elf.c new file mode 100644 index 000000000000..0a176734fefa --- /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 | |||
18 | int 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 | } | ||
30 | EXPORT_SYMBOL(elf_check_arch); | ||
31 | |||
32 | void elf_set_personality(const struct elf32_hdr *x) | ||
33 | { | ||
34 | unsigned int personality = PER_LINUX; | ||
35 | |||
36 | set_personality(personality); | ||
37 | } | ||
38 | EXPORT_SYMBOL(elf_set_personality); | ||
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S new file mode 100644 index 000000000000..00a259f9819e --- /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 | ||
101 | 1001: /* 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 | ||
121 | 901: .word 0, 0, 0, 0, 0 @ r0-r3, lr | ||
122 | 902: .asciz ": epip4d\n" | ||
123 | .align | ||
124 | 903: | ||
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 | */ | ||
136 | scno .req r21 @ syscall number | ||
137 | tbl .req r22 @ syscall table pointer | ||
138 | why .req r22 @ Linux syscall (!= 0) | ||
139 | tsk .req r23 @ current thread_info | ||
140 | |||
141 | /* | ||
142 | * Interrupt handling. Preserves r17, r18, r19 | ||
143 | */ | ||
144 | .macro intr_handler | ||
145 | 1: 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 | ||
153 | 2: | ||
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 | ||
250 | ENDPROC(__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 | ||
263 | 1: | ||
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 | ||
294 | ENDPROC(__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 | ||
309 | ENDPROC(__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 | ||
320 | ENDPROC(__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 | ||
333 | 1: | ||
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 | ||
357 | ENDPROC(__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 | @ | ||
382 | 1: 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 | ||
426 | 209: | ||
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 | ||
447 | ENDPROC(__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 | ||
459 | ENDPROC(__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 | ||
470 | ENDPROC(__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 | */ | ||
485 | ENTRY(ret_from_exception) | ||
486 | get_thread_info tsk | ||
487 | mov why, #0 | ||
488 | b ret_to_user | ||
489 | ENDPROC(__pabt_user) | ||
490 | ENDPROC(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 | */ | ||
497 | ENTRY(__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 | ||
522 | ENDPROC(__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 | */ | ||
530 | ret_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 | */ | ||
542 | fast_work_pending: | ||
543 | stw.w r0, [sp+], #S_R0+S_OFF @ returned r0 | ||
544 | work_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 | |||
556 | work_resched: | ||
557 | b.l schedule | ||
558 | /* | ||
559 | * "slow" syscall return path. "why" tells us if this was a real syscall. | ||
560 | */ | ||
561 | ENTRY(ret_to_user) | ||
562 | ret_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 | ||
568 | no_work_pending: | ||
569 | @ slow_restore_user_regs | ||
570 | restore_user_regs fast = 0, offset = 0 | ||
571 | ENDPROC(ret_to_user) | ||
572 | |||
573 | /* | ||
574 | * This is how we return from a fork. | ||
575 | */ | ||
576 | ENTRY(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 | ||
587 | ENDPROC(ret_from_fork) | ||
588 | |||
589 | /*============================================================================= | ||
590 | * SWI handler | ||
591 | *----------------------------------------------------------------------------- | ||
592 | */ | ||
593 | .align 5 | ||
594 | ENTRY(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 | ||
635 | 1: | ||
636 | add r1, sp, #S_OFF | ||
637 | 2: 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 | |||
674 | ENTRY(sys_execve) | ||
675 | add r3, sp, #S_OFF | ||
676 | b __sys_execve | ||
677 | ENDPROC(sys_execve) | ||
678 | |||
679 | ENTRY(sys_clone) | ||
680 | add ip, sp, #S_OFF | ||
681 | stw ip, [sp+], #4 | ||
682 | b __sys_clone | ||
683 | ENDPROC(sys_clone) | ||
684 | |||
685 | ENTRY(sys_rt_sigreturn) | ||
686 | add r0, sp, #S_OFF | ||
687 | mov why, #0 @ prevent syscall restart handling | ||
688 | b __sys_rt_sigreturn | ||
689 | ENDPROC(sys_rt_sigreturn) | ||
690 | |||
691 | ENTRY(sys_sigaltstack) | ||
692 | ldw r2, [sp+], #S_OFF + S_SP | ||
693 | b do_sigaltstack | ||
694 | ENDPROC(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 | |||
714 | vector_\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 | ||
739 | ENDPROC(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 | ||
821 | cr_alignment: | ||
822 | .space 4 | ||
823 | cr_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 000000000000..282a60ac82ba --- /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 | */ | ||
55 | void 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 | */ | ||
78 | void 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 | */ | ||
117 | static 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 | |||
126 | late_initcall(ucf64_init); | ||
diff --git a/arch/unicore32/kernel/gpio.c b/arch/unicore32/kernel/gpio.c new file mode 100644 index 000000000000..cb12ec39552c --- /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 | |||
24 | static 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 | |||
31 | static 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 | |||
36 | static 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 | |||
44 | static int __init puv3_gpio_leds_init(void) | ||
45 | { | ||
46 | platform_device_register(&puv3_gpio_gpio_leds); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | device_initcall(puv3_gpio_leds_init); | ||
51 | #endif | ||
52 | |||
53 | static int puv3_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
54 | { | ||
55 | return readl(GPIO_GPLR) & GPIO_GPIO(offset); | ||
56 | } | ||
57 | |||
58 | static 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 | |||
66 | static 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 | |||
76 | static 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 | |||
88 | static 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 | |||
98 | void __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 000000000000..92255f3ab6a7 --- /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 | ||
61 | ENTRY(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 | ||
81 | 101: 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 | ||
113 | 102: csub.a r0, r6 | ||
114 | add r1, r1, #1 << 22 | ||
115 | bua 103f | ||
116 | stw.w r1, [r0]+, #4 | ||
117 | b 102b | ||
118 | 103: | ||
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 | ||
164 | ENDPROC(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 | ||
180 | ENDPROC(__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) | ||
218 | 203: csub.a r6, r7 | ||
219 | bea 204f | ||
220 | stw.w fp, [r6]+,#4 | ||
221 | b 203b | ||
222 | 204: | ||
223 | andn r1, r0, #CR_A @ Clear 'A' bit | ||
224 | stm (r0, r1), [r8]+ @ Save control register values | ||
225 | b start_kernel | ||
226 | ENDPROC(__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 | ||
245 | 901: nop8 | ||
246 | b 901b | ||
247 | str_p1: .asciz "\nError: unrecognized processor variant (0x" | ||
248 | str_p2: .asciz ").\n" | ||
249 | .align | ||
250 | #endif | ||
251 | ENDPROC(__error_p) | ||
252 | |||
diff --git a/arch/unicore32/kernel/hibernate.c b/arch/unicore32/kernel/hibernate.c new file mode 100644 index 000000000000..7d0f0b7983a0 --- /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 */ | ||
27 | pgd_t *resume_pg_dir; | ||
28 | |||
29 | struct 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 | */ | ||
36 | static 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 | */ | ||
51 | static 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 | */ | ||
73 | static 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 | |||
119 | static inline void resume_init_first_level_page_table(pgd_t *pg_dir) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | int 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 | |||
145 | int 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 | |||
153 | void save_processor_state(void) | ||
154 | { | ||
155 | } | ||
156 | |||
157 | void 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 000000000000..cc3c65253c8c --- /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 | @ | ||
28 | ENTRY(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 | ||
42 | 101: | ||
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 | ||
50 | 102: 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 | ||
59 | 109: | ||
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 | ||
91 | 1: .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 | |||
99 | ENTRY(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 | |||
117 | 1: .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 000000000000..a35a1e50e4f4 --- /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 | |||
23 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
24 | static 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 | */ | ||
35 | union 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 | */ | ||
43 | struct task_struct init_task = INIT_TASK(init_task); | ||
44 | EXPORT_SYMBOL(init_task); | ||
diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c new file mode 100644 index 000000000000..b23624cf3062 --- /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 | */ | ||
39 | static int GPIO_IRQ_rising_edge; | ||
40 | static int GPIO_IRQ_falling_edge; | ||
41 | static int GPIO_IRQ_mask = 0; | ||
42 | |||
43 | #define GPIO_MASK(irq) (1 << (irq - IRQ_GPIO0)) | ||
44 | |||
45 | static 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 | */ | ||
78 | static void puv3_low_gpio_ack(struct irq_data *d) | ||
79 | { | ||
80 | writel((1 << d->irq), GPIO_GEDR); | ||
81 | } | ||
82 | |||
83 | static void puv3_low_gpio_mask(struct irq_data *d) | ||
84 | { | ||
85 | writel(readl(INTC_ICMR) & ~(1 << d->irq), INTC_ICMR); | ||
86 | } | ||
87 | |||
88 | static void puv3_low_gpio_unmask(struct irq_data *d) | ||
89 | { | ||
90 | writel(readl(INTC_ICMR) | (1 << d->irq), INTC_ICMR); | ||
91 | } | ||
92 | |||
93 | static 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 | |||
102 | static 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 | */ | ||
116 | static void | ||
117 | puv3_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 | */ | ||
145 | static 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 | |||
152 | static 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 | |||
162 | static 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 | |||
172 | static 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 | |||
181 | static 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 | */ | ||
194 | static void puv3_mask_irq(struct irq_data *d) | ||
195 | { | ||
196 | writel(readl(INTC_ICMR) & ~(1 << d->irq), INTC_ICMR); | ||
197 | } | ||
198 | |||
199 | static 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 | */ | ||
207 | static 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 | |||
219 | static 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 | |||
227 | static struct resource irq_resource = { | ||
228 | .name = "irqs", | ||
229 | .start = io_v2p(PKUNITY_INTC_BASE), | ||
230 | .end = io_v2p(PKUNITY_INTC_BASE) + 0xFFFFF, | ||
231 | }; | ||
232 | |||
233 | static 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 | |||
240 | static 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 | |||
268 | static 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 | |||
284 | static struct sysdev_class puv3_irq_sysclass = { | ||
285 | .name = "pkunity-irq", | ||
286 | .suspend = puv3_irq_suspend, | ||
287 | .resume = puv3_irq_resume, | ||
288 | }; | ||
289 | |||
290 | static struct sys_device puv3_irq_device = { | ||
291 | .id = 0, | ||
292 | .cls = &puv3_irq_sysclass, | ||
293 | }; | ||
294 | |||
295 | static int __init puv3_irq_init_devicefs(void) | ||
296 | { | ||
297 | sysdev_class_register(&puv3_irq_sysclass); | ||
298 | return sysdev_register(&puv3_irq_device); | ||
299 | } | ||
300 | |||
301 | device_initcall(puv3_irq_init_devicefs); | ||
302 | |||
303 | void __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 | |||
358 | int 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'); | ||
392 | unlock: | ||
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 | */ | ||
405 | asmlinkage 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 000000000000..a8970809428a --- /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 | |||
27 | EXPORT_SYMBOL(__uc32_find_next_zero_bit); | ||
28 | EXPORT_SYMBOL(__uc32_find_next_bit); | ||
29 | |||
30 | EXPORT_SYMBOL(__backtrace); | ||
31 | |||
32 | /* platform dependent support */ | ||
33 | EXPORT_SYMBOL(__udelay); | ||
34 | EXPORT_SYMBOL(__const_udelay); | ||
35 | |||
36 | /* networking */ | ||
37 | EXPORT_SYMBOL(csum_partial); | ||
38 | EXPORT_SYMBOL(csum_partial_copy_from_user); | ||
39 | EXPORT_SYMBOL(csum_partial_copy_nocheck); | ||
40 | EXPORT_SYMBOL(__csum_ipv6_magic); | ||
41 | |||
42 | /* io */ | ||
43 | #ifndef __raw_readsb | ||
44 | EXPORT_SYMBOL(__raw_readsb); | ||
45 | #endif | ||
46 | #ifndef __raw_readsw | ||
47 | EXPORT_SYMBOL(__raw_readsw); | ||
48 | #endif | ||
49 | #ifndef __raw_readsl | ||
50 | EXPORT_SYMBOL(__raw_readsl); | ||
51 | #endif | ||
52 | #ifndef __raw_writesb | ||
53 | EXPORT_SYMBOL(__raw_writesb); | ||
54 | #endif | ||
55 | #ifndef __raw_writesw | ||
56 | EXPORT_SYMBOL(__raw_writesw); | ||
57 | #endif | ||
58 | #ifndef __raw_writesl | ||
59 | EXPORT_SYMBOL(__raw_writesl); | ||
60 | #endif | ||
61 | |||
62 | /* string / mem functions */ | ||
63 | EXPORT_SYMBOL(strchr); | ||
64 | EXPORT_SYMBOL(strrchr); | ||
65 | EXPORT_SYMBOL(memset); | ||
66 | EXPORT_SYMBOL(memcpy); | ||
67 | EXPORT_SYMBOL(memmove); | ||
68 | EXPORT_SYMBOL(memchr); | ||
69 | |||
70 | /* user mem (segment) */ | ||
71 | EXPORT_SYMBOL(__strnlen_user); | ||
72 | EXPORT_SYMBOL(__strncpy_from_user); | ||
73 | |||
74 | EXPORT_SYMBOL(copy_page); | ||
75 | |||
76 | EXPORT_SYMBOL(__copy_from_user); | ||
77 | EXPORT_SYMBOL(__copy_to_user); | ||
78 | EXPORT_SYMBOL(__clear_user); | ||
79 | |||
80 | EXPORT_SYMBOL(__get_user_1); | ||
81 | EXPORT_SYMBOL(__get_user_2); | ||
82 | EXPORT_SYMBOL(__get_user_4); | ||
83 | |||
84 | EXPORT_SYMBOL(__put_user_1); | ||
85 | EXPORT_SYMBOL(__put_user_2); | ||
86 | EXPORT_SYMBOL(__put_user_4); | ||
87 | EXPORT_SYMBOL(__put_user_8); | ||
88 | |||
89 | EXPORT_SYMBOL(__ashldi3); | ||
90 | EXPORT_SYMBOL(__ashrdi3); | ||
91 | EXPORT_SYMBOL(__divsi3); | ||
92 | EXPORT_SYMBOL(__lshrdi3); | ||
93 | EXPORT_SYMBOL(__modsi3); | ||
94 | EXPORT_SYMBOL(__muldi3); | ||
95 | EXPORT_SYMBOL(__ucmpdi2); | ||
96 | EXPORT_SYMBOL(__udivsi3); | ||
97 | EXPORT_SYMBOL(__umodsi3); | ||
98 | EXPORT_SYMBOL(__bswapsi2); | ||
99 | |||
diff --git a/arch/unicore32/kernel/ksyms.h b/arch/unicore32/kernel/ksyms.h new file mode 100644 index 000000000000..185cdc712d03 --- /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 | */ | ||
6 | extern void __ashldi3(void); | ||
7 | extern void __ashrdi3(void); | ||
8 | extern void __divsi3(void); | ||
9 | extern void __lshrdi3(void); | ||
10 | extern void __modsi3(void); | ||
11 | extern void __muldi3(void); | ||
12 | extern void __ucmpdi2(void); | ||
13 | extern void __udivsi3(void); | ||
14 | extern void __umodsi3(void); | ||
15 | extern void __bswapsi2(void); | ||
diff --git a/arch/unicore32/kernel/module.c b/arch/unicore32/kernel/module.c new file mode 100644 index 000000000000..3e5a38d71a1e --- /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 | |||
25 | void *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 | |||
40 | void module_free(struct module *module, void *region) | ||
41 | { | ||
42 | vfree(region); | ||
43 | } | ||
44 | |||
45 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
46 | Elf_Shdr *sechdrs, | ||
47 | char *secstrings, | ||
48 | struct module *mod) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | int | ||
54 | apply_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 | |||
132 | int | ||
133 | apply_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 | |||
142 | int | ||
143 | module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
144 | struct module *module) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | void | ||
150 | module_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 000000000000..100eab842e66 --- /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 | |||
23 | static int debug_pci; | ||
24 | static int use_firmware; | ||
25 | |||
26 | #define CONFIG_CMD(bus, devfn, where) \ | ||
27 | (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
28 | |||
29 | static int | ||
30 | puv3_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 | |||
48 | static int | ||
49 | puv3_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 | |||
69 | struct pci_ops pci_puv3_ops = { | ||
70 | .read = puv3_read_config, | ||
71 | .write = puv3_write_config, | ||
72 | }; | ||
73 | |||
74 | void 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 | |||
105 | static 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 | */ | ||
141 | void __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 | |||
158 | void __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 | */ | ||
170 | static 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 | */ | ||
179 | void __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 | ||
263 | EXPORT_SYMBOL(pcibios_fixup_bus); | ||
264 | #endif | ||
265 | |||
266 | static 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 | } | ||
298 | subsys_initcall(pci_common_init); | ||
299 | |||
300 | char * __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 | */ | ||
327 | resource_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 | */ | ||
344 | int 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 | |||
383 | int 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 000000000000..784bc2db3b28 --- /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 | |||
25 | struct puv3_cpu_pm_fns *puv3_cpu_pm_fns; | ||
26 | static unsigned long *sleep_save; | ||
27 | |||
28 | int 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 | } | ||
67 | EXPORT_SYMBOL_GPL(puv3_pm_enter); | ||
68 | |||
69 | unsigned long sleep_phys_sp(void *sp) | ||
70 | { | ||
71 | return virt_to_phys(sp); | ||
72 | } | ||
73 | |||
74 | static 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 | |||
82 | static 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 | |||
92 | static 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 | |||
98 | static 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 | |||
105 | static 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 | |||
123 | device_initcall(puv3_pm_init); | ||
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c new file mode 100644 index 000000000000..ba401df971ed --- /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 | |||
42 | static 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 | */ | ||
54 | void 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 | |||
73 | static char reboot_mode = 'h'; | ||
74 | |||
75 | int __init reboot_setup(char *str) | ||
76 | { | ||
77 | reboot_mode = str[0]; | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | __setup("reboot=", reboot_setup); | ||
82 | |||
83 | void machine_halt(void) | ||
84 | { | ||
85 | gpio_set_value(GPO_SOFT_OFF, 0); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Function pointers to optional machine specific functions | ||
90 | */ | ||
91 | void (*pm_power_off)(void) = NULL; | ||
92 | |||
93 | void machine_power_off(void) | ||
94 | { | ||
95 | if (pm_power_off) | ||
96 | pm_power_off(); | ||
97 | machine_halt(); | ||
98 | } | ||
99 | |||
100 | void 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 | |||
161 | void __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 | |||
227 | void 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 | */ | ||
239 | void exit_thread(void) | ||
240 | { | ||
241 | } | ||
242 | |||
243 | void 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 | |||
255 | void release_thread(struct task_struct *dead_task) | ||
256 | { | ||
257 | } | ||
258 | |||
259 | asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); | ||
260 | |||
261 | int | ||
262 | copy_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 | */ | ||
285 | int 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 | */ | ||
294 | int 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 | } | ||
305 | EXPORT_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 | */ | ||
312 | asm(".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 | */ | ||
326 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
327 | { | ||
328 | struct pt_regs regs; | ||
329 | |||
330 | memset(®s, 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, ®s, 0, NULL, NULL); | ||
340 | } | ||
341 | EXPORT_SYMBOL(kernel_thread); | ||
342 | |||
343 | unsigned 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 | |||
364 | unsigned 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 | |||
376 | int 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 | |||
386 | const 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 000000000000..9f07c08da050 --- /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 | */ | ||
25 | static 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 | */ | ||
36 | static inline int | ||
37 | put_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 | */ | ||
56 | void ptrace_disable(struct task_struct *child) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * We actually access the pt_regs stored on the kernel stack. | ||
62 | */ | ||
63 | static 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 | */ | ||
78 | static 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 | |||
87 | long 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 | |||
115 | asmlinkage 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 000000000000..8b1b6beb858e --- /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 | */ | ||
37 | unsigned 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 | |||
50 | static 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 | |||
65 | static 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 | |||
76 | static 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 | |||
83 | static 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 | |||
96 | static 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 | |||
109 | static 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 | |||
127 | static 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 | |||
135 | static 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 | |||
148 | static 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 | |||
161 | static 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 | */ | ||
184 | enum { | ||
185 | SLEEP_SAVE_PM_PLLDDRCFG, | ||
186 | SLEEP_SAVE_COUNT | ||
187 | }; | ||
188 | |||
189 | |||
190 | static void puv3_cpu_pm_save(unsigned long *sleep_save) | ||
191 | { | ||
192 | /* SAVE(PM_PLLDDRCFG); */ | ||
193 | } | ||
194 | |||
195 | static void puv3_cpu_pm_restore(unsigned long *sleep_save) | ||
196 | { | ||
197 | /* RESTORE(PM_PLLDDRCFG); */ | ||
198 | } | ||
199 | |||
200 | static 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 | |||
207 | static 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 | |||
224 | static int puv3_cpu_pm_valid(suspend_state_t state) | ||
225 | { | ||
226 | return state == PM_SUSPEND_MEM; | ||
227 | } | ||
228 | |||
229 | static void puv3_cpu_pm_finish(void) | ||
230 | { | ||
231 | /* ensure not to come back here if it wasn't intended */ | ||
232 | /* PSPR = 0; */ | ||
233 | } | ||
234 | |||
235 | static 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 | |||
245 | static void __init puv3_init_pm(void) | ||
246 | { | ||
247 | puv3_cpu_pm_fns = &puv3_cpu_pm_fnss; | ||
248 | } | ||
249 | #else | ||
250 | static inline void puv3_init_pm(void) {} | ||
251 | #endif | ||
252 | |||
253 | void 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 | |||
261 | void __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 000000000000..e731c561ed4e --- /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 | |||
30 | static struct physmap_flash_data physmap_flash_data = { | ||
31 | .width = 1, | ||
32 | }; | ||
33 | |||
34 | static struct resource physmap_flash_resource = { | ||
35 | .start = 0xFFF80000, | ||
36 | .end = 0xFFFFFFFF, | ||
37 | .flags = IORESOURCE_MEM, | ||
38 | }; | ||
39 | |||
40 | static 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 | |||
53 | static 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 | |||
60 | static 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 | |||
79 | static struct gpio_keys_platform_data nb0916_gpio_button_data = { | ||
80 | .buttons = nb0916_gpio_keys, | ||
81 | .nbuttons = ARRAY_SIZE(nb0916_gpio_keys), | ||
82 | }; | ||
83 | |||
84 | static 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 | |||
94 | static 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 | |||
101 | static 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 | |||
107 | int __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 | |||
145 | subsys_initcall_sync(mach_nb0916_init); | ||
diff --git a/arch/unicore32/kernel/pwm.c b/arch/unicore32/kernel/pwm.c new file mode 100644 index 000000000000..4615d51e3ba6 --- /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 | |||
26 | struct 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 | */ | ||
42 | int 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 | } | ||
79 | EXPORT_SYMBOL(pwm_config); | ||
80 | |||
81 | int 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 | } | ||
92 | EXPORT_SYMBOL(pwm_enable); | ||
93 | |||
94 | void pwm_disable(struct pwm_device *pwm) | ||
95 | { | ||
96 | if (pwm->clk_enabled) { | ||
97 | clk_disable(pwm->clk); | ||
98 | pwm->clk_enabled = 0; | ||
99 | } | ||
100 | } | ||
101 | EXPORT_SYMBOL(pwm_disable); | ||
102 | |||
103 | static DEFINE_MUTEX(pwm_lock); | ||
104 | static LIST_HEAD(pwm_list); | ||
105 | |||
106 | struct 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 | } | ||
132 | EXPORT_SYMBOL(pwm_request); | ||
133 | |||
134 | void 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 | } | ||
146 | EXPORT_SYMBOL(pwm_free); | ||
147 | |||
148 | static 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 | |||
155 | static 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 | |||
197 | err_free_clk: | ||
198 | clk_put(pwm->clk); | ||
199 | err_free: | ||
200 | kfree(pwm); | ||
201 | return ERR_PTR(ret); | ||
202 | } | ||
203 | |||
204 | static 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 | |||
214 | static 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 | |||
235 | static 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 | |||
243 | static 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 | } | ||
255 | arch_initcall(pwm_init); | ||
256 | |||
257 | static void __exit pwm_exit(void) | ||
258 | { | ||
259 | platform_driver_unregister(&puv3_pwm_driver); | ||
260 | } | ||
261 | module_exit(pwm_exit); | ||
262 | |||
263 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/unicore32/kernel/rtc.c b/arch/unicore32/kernel/rtc.c new file mode 100644 index 000000000000..c5f068295b51 --- /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 | |||
31 | static struct resource *puv3_rtc_mem; | ||
32 | |||
33 | static int puv3_rtc_alarmno = IRQ_RTCAlarm; | ||
34 | static int puv3_rtc_tickno = IRQ_RTC; | ||
35 | |||
36 | static DEFINE_SPINLOCK(puv3_rtc_pie_lock); | ||
37 | |||
38 | /* IRQ Handlers */ | ||
39 | |||
40 | static 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 | |||
49 | static 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 */ | ||
59 | static 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 | |||
73 | static 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 | |||
91 | static int puv3_rtc_setfreq(struct device *dev, int freq) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* Time read/write */ | ||
97 | |||
98 | static 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 | |||
109 | static 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 | |||
123 | static 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 | |||
139 | static 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 | |||
162 | static 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 | |||
169 | static 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 | |||
198 | static 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 | |||
210 | static 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 | |||
222 | static 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 | |||
236 | static 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 | |||
252 | static 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 | |||
329 | static int ticnt_save; | ||
330 | |||
331 | static 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 | |||
339 | static 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 | |||
350 | static 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 | |||
361 | static char __initdata banner[] = "PKUnity-v3 RTC, (c) 2009 PKUnity Co.\n"; | ||
362 | |||
363 | static int __init puv3_rtc_init(void) | ||
364 | { | ||
365 | printk(banner); | ||
366 | return platform_driver_register(&puv3_rtcdrv); | ||
367 | } | ||
368 | |||
369 | static void __exit puv3_rtc_exit(void) | ||
370 | { | ||
371 | platform_driver_unregister(&puv3_rtcdrv); | ||
372 | } | ||
373 | |||
374 | module_init(puv3_rtc_init); | ||
375 | module_exit(puv3_rtc_exit); | ||
376 | |||
377 | MODULE_DESCRIPTION("RTC Driver for the PKUnity v3 chip"); | ||
378 | MODULE_AUTHOR("Hu Dongliang"); | ||
379 | MODULE_LICENSE("GPL v2"); | ||
380 | |||
diff --git a/arch/unicore32/kernel/setup.c b/arch/unicore32/kernel/setup.c new file mode 100644 index 000000000000..1e175a82844d --- /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 | |||
47 | struct stack { | ||
48 | u32 irq[3]; | ||
49 | u32 abt[3]; | ||
50 | u32 und[3]; | ||
51 | } ____cacheline_aligned; | ||
52 | |||
53 | static struct stack stacks[NR_CPUS]; | ||
54 | |||
55 | char elf_platform[ELF_PLATFORM_SIZE]; | ||
56 | EXPORT_SYMBOL(elf_platform); | ||
57 | |||
58 | static char __initdata cmd_line[COMMAND_LINE_SIZE]; | ||
59 | |||
60 | static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; | ||
61 | |||
62 | /* | ||
63 | * Standard memory resources | ||
64 | */ | ||
65 | static 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 | */ | ||
94 | static 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 | */ | ||
108 | void 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 | |||
136 | static 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 | */ | ||
170 | static 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 | } | ||
195 | early_param("mem", early_mem); | ||
196 | |||
197 | static void __init | ||
198 | request_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 | |||
233 | static void (*init_machine)(void) __initdata; | ||
234 | |||
235 | static 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 | } | ||
242 | arch_initcall(customize_machine); | ||
243 | |||
244 | void __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 | |||
286 | static struct cpu cpuinfo_unicore; | ||
287 | |||
288 | static 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 | } | ||
297 | subsys_initcall(topology_init); | ||
298 | |||
299 | #ifdef CONFIG_HAVE_PROC_CPU | ||
300 | static 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 | } | ||
309 | fs_initcall(proc_cpu_init); | ||
310 | #endif | ||
311 | |||
312 | static 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 | |||
340 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
341 | { | ||
342 | return *pos < 1 ? (void *)1 : NULL; | ||
343 | } | ||
344 | |||
345 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
346 | { | ||
347 | ++*pos; | ||
348 | return NULL; | ||
349 | } | ||
350 | |||
351 | static void c_stop(struct seq_file *m, void *v) | ||
352 | { | ||
353 | } | ||
354 | |||
355 | const 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 000000000000..dcd1306eb5c6 --- /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 | |||
15 | extern void paging_init(void); | ||
16 | extern void puv3_core_init(void); | ||
17 | |||
18 | extern void puv3_ps2_init(void); | ||
19 | extern void pci_puv3_preinit(void); | ||
20 | extern void __init puv3_init_gpio(void); | ||
21 | |||
22 | extern void setup_mm_for_reboot(char mode); | ||
23 | |||
24 | extern char __stubs_start[], __stubs_end[]; | ||
25 | extern char __vectors_start[], __vectors_end[]; | ||
26 | |||
27 | extern void kernel_thread_helper(void); | ||
28 | |||
29 | extern 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 000000000000..b163fca56789 --- /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 | |||
36 | const unsigned long sigreturn_codes[3] = { | ||
37 | SWI_SYS_SIGRETURN, SWI_SYS_RT_SIGRETURN, | ||
38 | }; | ||
39 | |||
40 | const 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 | */ | ||
48 | struct sigframe { | ||
49 | struct ucontext uc; | ||
50 | unsigned long retcode[2]; | ||
51 | }; | ||
52 | |||
53 | struct rt_sigframe { | ||
54 | struct siginfo info; | ||
55 | struct sigframe sig; | ||
56 | }; | ||
57 | |||
58 | static 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(¤t->sighand->siglock); | ||
67 | current->blocked = set; | ||
68 | recalc_sigpending(); | ||
69 | spin_unlock_irq(¤t->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 | |||
111 | asmlinkage 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 | |||
140 | badframe: | ||
141 | force_sig(SIGSEGV, current); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static 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 | |||
197 | static 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 | |||
223 | static 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 | |||
250 | static 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 | |||
271 | static 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 | |||
309 | static 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 | */ | ||
318 | static 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 | */ | ||
395 | static 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 = ¤t->saved_sigmask; | ||
419 | else | ||
420 | oldset = ¤t->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, ¤t->saved_sigmask, NULL); | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | |||
469 | asmlinkage 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 | */ | ||
487 | void __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 000000000000..607a104aec59 --- /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 | |||
20 | pkunity_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 | |||
35 | pkunity_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 | |||
52 | ENTRY(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 | ||
118 | pkunity_cpu_do_suspend: | ||
119 | b 101f | ||
120 | @ put DDR2 into self-refresh | ||
121 | 100: stw r5, [r0+], #0x24 | ||
122 | @ change PLL | ||
123 | stw r6, [r1] | ||
124 | b 1f | ||
125 | |||
126 | .ltorg | ||
127 | .align 5 | ||
128 | 101: b 102f | ||
129 | @ wait for PLL changing complete | ||
130 | 1: ldw r6, [r1+], #0x44 | ||
131 | csub.a r6, #0x1 | ||
132 | bne 1b | ||
133 | b 2f | ||
134 | |||
135 | .ltorg | ||
136 | .align 5 | ||
137 | 102: b 100b | ||
138 | @ close PLL | ||
139 | 2: stw r7, [r1+], #0x4 | ||
140 | @ enter sleep mode | ||
141 | stw r8, [r1] | ||
142 | 3: 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 | ||
161 | ENTRY(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 | |||
185 | sleep_save_sp: | ||
186 | .word 0 @ preserve stack phys ptr here | ||
187 | |||
188 | .text | ||
189 | resume_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 000000000000..b34030bdabe3 --- /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 | */ | ||
35 | int 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 | |||
57 | void 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 | } | ||
70 | EXPORT_SYMBOL(walk_stackframe); | ||
71 | |||
72 | #ifdef CONFIG_STACKTRACE | ||
73 | struct stack_trace_data { | ||
74 | struct stack_trace *trace; | ||
75 | unsigned int no_sched_functions; | ||
76 | unsigned int skip; | ||
77 | }; | ||
78 | |||
79 | static 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 | |||
97 | void 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 | |||
126 | void save_stack_trace(struct stack_trace *trace) | ||
127 | { | ||
128 | save_stack_trace_tsk(current, trace); | ||
129 | } | ||
130 | EXPORT_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 000000000000..3afe60a39ac9 --- /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 | */ | ||
34 | asmlinkage 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 | */ | ||
48 | asmlinkage 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); | ||
62 | out: | ||
63 | return error; | ||
64 | } | ||
65 | |||
66 | int 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(®s, 0, sizeof(struct pt_regs)); | ||
74 | ret = do_execve(filename, | ||
75 | (const char __user *const __user *)argv, | ||
76 | (const char __user *const __user *)envp, ®s); | ||
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" (®s), | ||
101 | "Ir" (sizeof(regs)) | ||
102 | : "r0", "r1", "r2", "r3", "ip", "lr", "memory"); | ||
103 | |||
104 | out: | ||
105 | return ret; | ||
106 | } | ||
107 | EXPORT_SYMBOL(kernel_execve); | ||
108 | |||
109 | /* Note: used by the compat code even in 64-bit Linux. */ | ||
110 | SYSCALL_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> */ | ||
123 | void *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 000000000000..080710c09241 --- /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 | |||
24 | static 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 | |||
36 | static int | ||
37 | puv3_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 | |||
49 | static void | ||
50 | puv3_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 | |||
66 | static 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 | |||
74 | static cycle_t puv3_read_oscr(struct clocksource *cs) | ||
75 | { | ||
76 | return readl(OST_OSCR); | ||
77 | } | ||
78 | |||
79 | static 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 | |||
87 | static 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 | |||
94 | void __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 | ||
114 | unsigned long osmr[4], oier; | ||
115 | |||
116 | void 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 | |||
125 | void 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 | ||
140 | void puv3_timer_suspend(void) { }; | ||
141 | void 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 000000000000..25abbb101729 --- /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 | |||
35 | static void dump_mem(const char *, const char *, unsigned long, unsigned long); | ||
36 | |||
37 | void 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 | */ | ||
54 | static 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 | */ | ||
66 | static 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 | |||
106 | static 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 | |||
140 | static 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 | |||
175 | void dump_stack(void) | ||
176 | { | ||
177 | dump_backtrace(NULL, NULL); | ||
178 | } | ||
179 | EXPORT_SYMBOL(dump_stack); | ||
180 | |||
181 | void show_stack(struct task_struct *tsk, unsigned long *sp) | ||
182 | { | ||
183 | dump_backtrace(NULL, tsk); | ||
184 | barrier(); | ||
185 | } | ||
186 | |||
187 | static 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 | |||
219 | DEFINE_SPINLOCK(die_lock); | ||
220 | |||
221 | /* | ||
222 | * This function is protected against re-entrancy. | ||
223 | */ | ||
224 | void 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 | |||
249 | void 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 | */ | ||
267 | asmlinkage 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 | |||
278 | void __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 | |||
283 | void __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 | |||
288 | void __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 | |||
293 | asmlinkage void __div0(void) | ||
294 | { | ||
295 | printk(KERN_DEFAULT "Division by zero in kernel.\n"); | ||
296 | dump_stack(); | ||
297 | } | ||
298 | EXPORT_SYMBOL(__div0); | ||
299 | |||
300 | void abort(void) | ||
301 | { | ||
302 | BUG(); | ||
303 | |||
304 | /* if that doesn't kill us, halt */ | ||
305 | panic("Oops failed to kill thread"); | ||
306 | } | ||
307 | EXPORT_SYMBOL(abort); | ||
308 | |||
309 | void __init trap_init(void) | ||
310 | { | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | void __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 000000000000..0b4eb89729e7 --- /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 | |||
18 | OUTPUT_ARCH(unicore32) | ||
19 | ENTRY(stext) | ||
20 | |||
21 | jiffies = jiffies_64; | ||
22 | |||
23 | SECTIONS | ||
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 000000000000..87229a558b36 --- /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 | |||
7 | lib-y := backtrace.o delay.o findbit.o | ||
8 | lib-y += strncpy_from_user.o strnlen_user.o | ||
9 | lib-y += clear_user.o copy_page.o | ||
10 | lib-y += copy_from_user.o copy_to_user.o | ||
11 | |||
12 | GNU_LIBC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libc.a) | ||
13 | GNU_LIBC_A_OBJS := memchr.o memcpy.o memmove.o memset.o | ||
14 | GNU_LIBC_A_OBJS += strchr.o strrchr.o | ||
15 | GNU_LIBC_A_OBJS += rawmemchr.o # needed by strrchr.o | ||
16 | |||
17 | GNU_LIBGCC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a) | ||
18 | GNU_LIBGCC_A_OBJS := _ashldi3.o _ashrdi3.o _lshrdi3.o | ||
19 | GNU_LIBGCC_A_OBJS += _divsi3.o _modsi3.o _ucmpdi2.o _umodsi3.o _udivsi3.o | ||
20 | |||
21 | lib-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 000000000000..ef01d77f2f65 --- /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 | |||
23 | ENTRY(__backtrace) | ||
24 | mov r0, fp | ||
25 | |||
26 | ENTRY(c_backtrace) | ||
27 | |||
28 | #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) | ||
29 | mov pc, lr | ||
30 | ENDPROC(__backtrace) | ||
31 | ENDPROC(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 | |||
38 | 1: 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 | */ | ||
58 | for_each_frame: | ||
59 | |||
60 | 1001: ldw sv_pc, [frame+], #0 @ get saved pc | ||
61 | 1002: ldw sv_fp, [frame+], #-12 @ get saved fp | ||
62 | |||
63 | sub sv_pc, sv_pc, offset @ Correct PC for prefetching | ||
64 | |||
65 | 1003: 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 | ||
71 | 201: | ||
72 | sub r0, sv_pc, #8 @ allow for mov + stmia | ||
73 | 202: | ||
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 | |||
86 | 1004: 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 | ||
92 | 201: | ||
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 | |||
100 | 1006: adr r0, .Lbad | ||
101 | mov r1, frame | ||
102 | b.l printk | ||
103 | no_frame: ldm.w (v4 - v8, pc), [sp]+ | ||
104 | ENDPROC(__backtrace) | ||
105 | ENDPROC(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 | ||
124 | 1: mov r3, #1 | ||
125 | csub.a reg, #8 | ||
126 | bne 201f | ||
127 | sub reg, reg, #3 | ||
128 | 201: | ||
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 | ||
141 | 201: | ||
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 | ||
145 | 201: | ||
146 | adr r0, .Lfp | ||
147 | b.l printk | ||
148 | 2: sub.a reg, reg, #1 | ||
149 | bns 1b | ||
150 | cxor.a v7, #0 | ||
151 | beq 201f | ||
152 | adr r0, .Lcr | ||
153 | b.l printk | ||
154 | 201: 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 000000000000..20047f7224fd --- /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 | */ | ||
23 | WEAK(__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 | ||
37 | 1: 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 | ||
42 | 2: 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 | ||
46 | USER( stb.u r2, [r0]) | ||
47 | 3: mov r0, #0 | ||
48 | ldm.w (r1), [sp]+ | ||
49 | ldm.w (pc), [sp]+ | ||
50 | ENDPROC(__clear_user) | ||
51 | |||
52 | .pushsection .fixup,"ax" | ||
53 | .align 0 | ||
54 | 9001: 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 000000000000..ab0767ea5dbd --- /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 | ||
41 | 100: 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 | ||
49 | 100: 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 | ||
73 | 201: stb.w \reg, [\ptr]+, #1 | ||
74 | 202: | ||
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 | |||
90 | ENTRY(__copy_from_user) | ||
91 | |||
92 | #include "copy_template.S" | ||
93 | |||
94 | ENDPROC(__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 000000000000..3a448d755ade --- /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 | */ | ||
26 | ENTRY(copy_page) | ||
27 | stm.w (r17 - r19, lr), [sp-] | ||
28 | mov r17, r0 | ||
29 | mov r18, r1 | ||
30 | mov r19, #COPY_COUNT | ||
31 | 1: | ||
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]+ | ||
39 | ENDPROC(copy_page) | ||
diff --git a/arch/unicore32/lib/copy_template.S b/arch/unicore32/lib/copy_template.S new file mode 100644 index 000000000000..524287fc0120 --- /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 | |||
70 | 1: sub.a r2, r2, #(28) | ||
71 | stm.w (r5 - r8), [sp-] | ||
72 | bsl 5f | ||
73 | |||
74 | 3: | ||
75 | 4: 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 | |||
80 | 5: 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 | |||
105 | 7: ldm.w (r5 - r8), [sp]+ | ||
106 | |||
107 | 8: 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 | |||
117 | 9: 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 | |||
130 | 10: 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 | |||
142 | 11: stm.w (r5 - r9), [sp-] | ||
143 | |||
144 | 12: | ||
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 | |||
169 | 14: and.a ip, r2, #28 | ||
170 | beq 16f | ||
171 | |||
172 | 15: 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 | |||
179 | 16: sub r1, r1, #(\b / 8) | ||
180 | b 8b | ||
181 | |||
182 | .endm | ||
183 | |||
184 | |||
185 | forward_copy_shift a=8 b=24 | ||
186 | |||
187 | 17: forward_copy_shift a=16 b=16 | ||
188 | |||
189 | 18: 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 | ||
200 | 19: ldm.w (r5 - r9), [sp]+ | ||
201 | b 21f | ||
202 | 299: .word 0 @ store lr | ||
203 | @ to avoid function call in fixup | ||
204 | 20: ldm.w (r5 - r8), [sp]+ | ||
205 | 21: | ||
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 000000000000..6e22151c840d --- /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 | ||
58 | 100: 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 | |||
82 | WEAK(__copy_to_user) | ||
83 | |||
84 | #include "copy_template.S" | ||
85 | |||
86 | ENDPROC(__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 000000000000..24664c009e78 --- /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 | |||
26 | ENTRY(__udelay) | ||
27 | ldw r2, .LC1 | ||
28 | mul r0, r2, r0 | ||
29 | ENTRY(__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 | ||
45 | ENTRY(__delay) | ||
46 | sub.a r0, r0, #2 | ||
47 | bua __delay | ||
48 | mov pc, lr | ||
49 | ENDPROC(__udelay) | ||
50 | ENDPROC(__const_udelay) | ||
51 | ENDPROC(__delay) | ||
diff --git a/arch/unicore32/lib/findbit.S b/arch/unicore32/lib/findbit.S new file mode 100644 index 000000000000..c360ce905d8b --- /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 | ||
24 | 1: 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 | ||
28 | 2: csub.a r2, r1 @ any more? | ||
29 | bub 1b | ||
30 | 3: 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 | */ | ||
38 | ENTRY(__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 | ||
50 | ENDPROC(__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 | ||
61 | 1: 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 | ||
65 | 2: csub.a r2, r1 @ any more? | ||
66 | bub 1b | ||
67 | 3: 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 | */ | ||
75 | ENTRY(__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 | ||
86 | ENDPROC(__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 000000000000..ff6c304d5c7e --- /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 | */ | ||
25 | ENTRY(__strncpy_from_user) | ||
26 | mov ip, r1 | ||
27 | 1: 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 | ||
34 | 2: sub r0, r1, ip | ||
35 | mov pc, lr | ||
36 | ENDPROC(__strncpy_from_user) | ||
37 | |||
38 | .pushsection .fixup,"ax" | ||
39 | .align 0 | ||
40 | 9001: 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 000000000000..75863030f21d --- /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 | */ | ||
25 | ENTRY(__strnlen_user) | ||
26 | mov r2, r0 | ||
27 | 1: | ||
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 | ||
34 | 2: sub r0, r0, r2 | ||
35 | mov pc, lr | ||
36 | ENDPROC(__strnlen_user) | ||
37 | |||
38 | .pushsection .fixup,"ax" | ||
39 | .align 0 | ||
40 | 9001: 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 000000000000..5f77fb3c63be --- /dev/null +++ b/arch/unicore32/mm/Kconfig | |||
@@ -0,0 +1,50 @@ | |||
1 | comment "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 | |||
7 | config CPU_UCV2 | ||
8 | def_bool y | ||
9 | |||
10 | comment "Processor Features" | ||
11 | |||
12 | config 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 | |||
18 | config 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 | |||
24 | config 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 | |||
30 | config 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 | |||
36 | config 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 | |||
42 | config SWIOTLB | ||
43 | def_bool y | ||
44 | |||
45 | config IOMMU_HELPER | ||
46 | def_bool SWIOTLB | ||
47 | |||
48 | config 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 000000000000..46c166699319 --- /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 | |||
5 | obj-y := extable.o fault.o init.o pgd.o mmu.o | ||
6 | obj-y += flush.o ioremap.o | ||
7 | |||
8 | obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o | ||
9 | |||
10 | obj-$(CONFIG_MODULES) += proc-syms.o | ||
11 | |||
12 | obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o | ||
13 | |||
14 | obj-$(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 000000000000..28f576d733ee --- /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 | |||
54 | union 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 | |||
196 | static void | ||
197 | do_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 | |||
210 | static int | ||
211 | do_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 | |||
234 | swp: | ||
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 | |||
241 | fault: | ||
242 | return TYPE_FAULT; | ||
243 | } | ||
244 | |||
245 | static int | ||
246 | do_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 | |||
260 | trans: | ||
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 | |||
267 | fault: | ||
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 | */ | ||
284 | static int | ||
285 | do_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 | |||
343 | fault: | ||
344 | regs->UCreg_pc -= pc_correction; | ||
345 | return TYPE_FAULT; | ||
346 | |||
347 | bad: | ||
348 | printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); | ||
349 | return TYPE_ERROR; | ||
350 | } | ||
351 | |||
352 | static int | ||
353 | do_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 | |||
441 | bad_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 | |||
451 | bad: | ||
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 | } | ||
502 | fault: | ||
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 | */ | ||
515 | static 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 | |||
523 | fs_initcall(alignment_init); | ||
diff --git a/arch/unicore32/mm/cache-ucv2.S b/arch/unicore32/mm/cache-ucv2.S new file mode 100644 index 000000000000..ecaa1727f906 --- /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 | */ | ||
28 | ENTRY(__cpuc_flush_icache_all) | ||
29 | /*FALLTHROUGH*/ | ||
30 | ENTRY(__cpuc_flush_kern_all) | ||
31 | /*FALLTHROUGH*/ | ||
32 | ENTRY(__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 | */ | ||
52 | ENTRY(__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 | |||
65 | 101: 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 | ||
72 | 2: mov ip, #0 | ||
73 | movc p0.c5, ip, #14 @ Dcache flush all | ||
74 | nop8 | ||
75 | |||
76 | 3: 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 | */ | ||
93 | ENTRY(__cpuc_coherent_kern_range) | ||
94 | /* FALLTHROUGH */ | ||
95 | ENTRY(__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 | ||
108 | 101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA | ||
109 | b 103f | ||
110 | 102: cand.a r0, r9 | ||
111 | beq 101b | ||
112 | |||
113 | 103: 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 | ||
122 | 2: mov ip, #0 | ||
123 | movc p0.c5, ip, #10 @ Dcache clean all | ||
124 | nop8 | ||
125 | |||
126 | 3: 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 | */ | ||
138 | ENTRY(__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 | */ | ||
149 | ENTRY(__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 | ||
162 | 101: va2pa r0, r10, r11, r12, r13, 2f @ r10 is PA | ||
163 | b 1f | ||
164 | 102: cand.a r0, r9 | ||
165 | beq 101b | ||
166 | |||
167 | 1: 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 | ||
175 | 2: 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 */ | ||
189 | ENTRY(__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 | ||
200 | 101: 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 | ||
207 | 2: 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 000000000000..bfa9fbb2bbb1 --- /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 | |||
20 | struct 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 | }; | ||
34 | EXPORT_SYMBOL(swiotlb_dma_map_ops); | ||
diff --git a/arch/unicore32/mm/extable.c b/arch/unicore32/mm/extable.c new file mode 100644 index 000000000000..6564180eb285 --- /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 | |||
15 | int 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 000000000000..283aa4b50b7a --- /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 | |||
32 | static 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 | */ | ||
42 | void 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 | */ | ||
92 | static 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 | */ | ||
120 | static 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 | |||
136 | void 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 | */ | ||
159 | static 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 | |||
171 | static 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 | */ | ||
188 | good_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 | |||
208 | check_stack: | ||
209 | if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) | ||
210 | goto good_area; | ||
211 | out: | ||
212 | return fault; | ||
213 | } | ||
214 | |||
215 | static 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 | |||
301 | no_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 | */ | ||
323 | static 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 | |||
353 | bad_area: | ||
354 | do_bad_area(addr, fsr, regs); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * This abort handler always returns "fault". | ||
360 | */ | ||
361 | static int do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | ||
362 | { | ||
363 | return 1; | ||
364 | } | ||
365 | |||
366 | static 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 | |||
384 | static 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 | |||
427 | void __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 | */ | ||
443 | asmlinkage 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 | |||
462 | asmlinkage 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 000000000000..93478cc8b26d --- /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 | |||
20 | void flush_cache_mm(struct mm_struct *mm) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | void 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 | |||
31 | void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, | ||
32 | unsigned long pfn) | ||
33 | { | ||
34 | } | ||
35 | |||
36 | static 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 | */ | ||
54 | void 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 | |||
62 | void __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 | */ | ||
76 | void 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 | } | ||
98 | EXPORT_SYMBOL(flush_dcache_page); | ||
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c new file mode 100644 index 000000000000..3dbe3709b69d --- /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 | |||
32 | static unsigned long phys_initrd_start __initdata = 0x01000000; | ||
33 | static unsigned long phys_initrd_size __initdata = SZ_8M; | ||
34 | |||
35 | static 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 | } | ||
49 | early_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 | */ | ||
56 | struct meminfo meminfo; | ||
57 | |||
58 | void 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 | |||
102 | static 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 | |||
129 | static 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 | |||
181 | static 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 | |||
223 | int pfn_valid(unsigned long pfn) | ||
224 | { | ||
225 | return memblock_is_memory(pfn << PAGE_SHIFT); | ||
226 | } | ||
227 | EXPORT_SYMBOL(pfn_valid); | ||
228 | |||
229 | static void uc32_memory_present(void) | ||
230 | { | ||
231 | } | ||
232 | |||
233 | static 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 | |||
240 | void __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 | |||
270 | void __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 | |||
315 | static 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 | |||
333 | static inline void | ||
334 | free_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 | */ | ||
363 | static 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 | */ | ||
398 | void __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 | |||
491 | void 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 | |||
500 | static int keep_initrd; | ||
501 | |||
502 | void 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 | |||
510 | static 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 000000000000..b7a605597b08 --- /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 | |||
48 | int 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 | } | ||
54 | EXPORT_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 | */ | ||
66 | static 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 | |||
101 | static int | ||
102 | remap_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 | |||
129 | void __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 | |||
184 | void __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 | */ | ||
210 | void __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 | } | ||
217 | EXPORT_SYMBOL(__uc32_ioremap_pfn); | ||
218 | |||
219 | void __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 | } | ||
225 | EXPORT_SYMBOL(__uc32_ioremap); | ||
226 | |||
227 | void __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 | } | ||
233 | EXPORT_SYMBOL(__uc32_ioremap_cached); | ||
234 | |||
235 | void __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 | } | ||
261 | EXPORT_SYMBOL(__uc32_iounmap); | ||
diff --git a/arch/unicore32/mm/mm.h b/arch/unicore32/mm/mm.h new file mode 100644 index 000000000000..3296bca0f1f7 --- /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 */ | ||
13 | extern pmd_t *top_pmd; | ||
14 | extern int sysctl_overcommit_memory; | ||
15 | |||
16 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
17 | |||
18 | static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) | ||
19 | { | ||
20 | return pmd_offset((pud_t *)pgd, virt); | ||
21 | } | ||
22 | |||
23 | static inline pmd_t *pmd_off_k(unsigned long virt) | ||
24 | { | ||
25 | return pmd_off(pgd_offset_k(virt), virt); | ||
26 | } | ||
27 | |||
28 | struct mem_type { | ||
29 | unsigned int prot_pte; | ||
30 | unsigned int prot_l1; | ||
31 | unsigned int prot_sect; | ||
32 | }; | ||
33 | |||
34 | const struct mem_type *get_mem_type(unsigned int type); | ||
35 | |||
36 | extern void __flush_dcache_page(struct address_space *, struct page *); | ||
37 | |||
38 | void __init bootmem_init(void); | ||
39 | void uc32_mm_memblock_reserve(void); | ||
diff --git a/arch/unicore32/mm/mmu.c b/arch/unicore32/mm/mmu.c new file mode 100644 index 000000000000..7bf3d588631f --- /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 | |||
33 | DEFINE_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 | */ | ||
39 | struct page *empty_zero_page; | ||
40 | EXPORT_SYMBOL(empty_zero_page); | ||
41 | |||
42 | /* | ||
43 | * The pmd table for the upper-most set of pages. | ||
44 | */ | ||
45 | pmd_t *top_pmd; | ||
46 | |||
47 | pgprot_t pgprot_user; | ||
48 | EXPORT_SYMBOL(pgprot_user); | ||
49 | |||
50 | pgprot_t pgprot_kernel; | ||
51 | EXPORT_SYMBOL(pgprot_kernel); | ||
52 | |||
53 | static 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 | |||
62 | void 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 | |||
80 | struct 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 | |||
92 | static 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 | |||
127 | const struct mem_type *get_mem_type(unsigned int type) | ||
128 | { | ||
129 | return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL; | ||
130 | } | ||
131 | EXPORT_SYMBOL(get_mem_type); | ||
132 | |||
133 | /* | ||
134 | * Adjust the PMD section entries according to the CPU in use. | ||
135 | */ | ||
136 | static 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 | |||
146 | static 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 | |||
153 | static 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 | |||
164 | static 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 | |||
175 | static 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 | */ | ||
209 | static 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 | |||
254 | static 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 | */ | ||
261 | static 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 | } | ||
282 | early_param("vmalloc", early_vmalloc); | ||
283 | |||
284 | static phys_addr_t lowmem_limit __initdata = SZ_1G; | ||
285 | |||
286 | static 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 | |||
301 | static 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 | */ | ||
334 | void __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 | */ | ||
359 | static 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 | |||
415 | static 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 | */ | ||
443 | void __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 | */ | ||
469 | void 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 | */ | ||
509 | void 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 000000000000..08b8d4295e70 --- /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 | */ | ||
27 | pgd_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 | |||
70 | no_pte: | ||
71 | pmd_free(mm, new_pmd); | ||
72 | no_pmd: | ||
73 | free_pages((unsigned long)new_pgd, 0); | ||
74 | no_pgd: | ||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | void 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); | ||
100 | free: | ||
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 000000000000..51560d68c894 --- /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 | ||
101 | 900: @ ---- 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 | ||
110 | 930: @ ---- 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 | ||
118 | 910: @ 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 | |||
124 | 920: @ 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 | ||
129 | 980: | ||
130 | andn \tbl, \va, \msk | ||
131 | and \pa, \pa, \msk | ||
132 | or \pa, \pa, \tbl | ||
133 | 990: | ||
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 000000000000..f30071e3665d --- /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 | |||
19 | EXPORT_SYMBOL(cpu_dcache_clean_area); | ||
20 | EXPORT_SYMBOL(cpu_set_pte); | ||
21 | |||
22 | EXPORT_SYMBOL(__cpuc_dma_flush_range); | ||
23 | EXPORT_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 000000000000..9d296092e362 --- /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 | |||
21 | ENTRY(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 | ||
38 | ENTRY(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 | */ | ||
61 | ENTRY(cpu_do_idle) | ||
62 | mov r0, #0 @ PCI address | ||
63 | .rept 8 | ||
64 | ldw r1, [r0] | ||
65 | .endr | ||
66 | mov pc, lr | ||
67 | |||
68 | ENTRY(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 | ||
74 | 1: va2pa r0, r10, r11, r12, r13 @ r10 is PA | ||
75 | b 3f | ||
76 | 2: cand.a r0, r9 | ||
77 | beq 1b | ||
78 | 3: 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 | ||
86 | 101: 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 | ||
103 | ENTRY(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 | ||
121 | ENTRY(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 000000000000..061d455f9a15 --- /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 | */ | ||
28 | ENTRY(__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 | ||
33 | 1: | ||
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 | ||
42 | 2: | ||
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 | ||
55 | 2: | ||
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 | */ | ||
67 | ENTRY(__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 | ||
71 | 1: | ||
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 | |||