diff options
Diffstat (limited to 'arch/cris/arch-v32')
75 files changed, 8348 insertions, 3391 deletions
diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig index d8acaa920e1c..005ed2b3f7f4 100644 --- a/arch/cris/arch-v32/Kconfig +++ b/arch/cris/arch-v32/Kconfig | |||
@@ -1,27 +1,73 @@ | |||
1 | if ETRAX_ARCH_V32 | 1 | if ETRAX_ARCH_V32 |
2 | 2 | ||
3 | source arch/cris/arch-v32/mach-fs/Kconfig | ||
4 | source arch/cris/arch-v32/mach-a3/Kconfig | ||
5 | |||
6 | source drivers/cpufreq/Kconfig | ||
7 | |||
3 | config ETRAX_DRAM_VIRTUAL_BASE | 8 | config ETRAX_DRAM_VIRTUAL_BASE |
4 | hex | 9 | hex |
5 | depends on ETRAX_ARCH_V32 | 10 | depends on ETRAX_ARCH_V32 |
6 | default "c0000000" | 11 | default "c0000000" |
7 | 12 | ||
8 | config ETRAX_LED1G | 13 | choice |
9 | string "First green LED bit" | 14 | prompt "Nbr of Ethernet LED groups" |
10 | depends on ETRAX_ARCH_V32 | 15 | depends on ETRAX_ARCH_V32 |
16 | default ETRAX_NBR_LED_GRP_ONE | ||
17 | help | ||
18 | Select how many Ethernet LED groups that can be used. Usually one per Ethernet | ||
19 | interface is a good choice. | ||
20 | |||
21 | config ETRAX_NBR_LED_GRP_ZERO | ||
22 | bool "Use zero LED groups" | ||
23 | help | ||
24 | Select this if you do not want any Ethernet LEDs. | ||
25 | |||
26 | config ETRAX_NBR_LED_GRP_ONE | ||
27 | bool "Use one LED group" | ||
28 | help | ||
29 | Select this if you want one Ethernet LED group. This LED group | ||
30 | can be used for one or more Ethernet interfaces. However, it is | ||
31 | recomended that each Ethernet interface use a dedicated LED group. | ||
32 | |||
33 | config ETRAX_NBR_LED_GRP_TWO | ||
34 | bool "Use two LED groups" | ||
35 | help | ||
36 | Select this if you want two Ethernet LED groups. This is the | ||
37 | best choice if you have more than one Ethernet interface and | ||
38 | would like to have separate LEDs for the interfaces. | ||
39 | |||
40 | endchoice | ||
41 | |||
42 | config ETRAX_LED_G_NET0 | ||
43 | string "Ethernet LED group 0 green LED bit" | ||
44 | depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO) | ||
11 | default "PA3" | 45 | default "PA3" |
12 | help | 46 | help |
13 | Bit to use for the first green LED (network LED). | 47 | Bit to use for the green LED in Ethernet LED group 0. |
14 | Most Axis products use bit A3 here. | ||
15 | 48 | ||
16 | config ETRAX_LED1R | 49 | config ETRAX_LED_R_NET0 |
17 | string "First red LED bit" | 50 | string "Ethernet LED group 0 red LED bit" |
18 | depends on ETRAX_ARCH_V32 | 51 | depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO) |
19 | default "PA4" | 52 | default "PA4" |
20 | help | 53 | help |
21 | Bit to use for the first red LED (network LED). | 54 | Bit to use for the red LED in Ethernet LED group 0. |
22 | Most Axis products use bit A4 here. | ||
23 | 55 | ||
24 | config ETRAX_LED2G | 56 | config ETRAX_LED_G_NET1 |
57 | string "Ethernet group 1 green LED bit" | ||
58 | depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO | ||
59 | default "" | ||
60 | help | ||
61 | Bit to use for the green LED in Ethernet LED group 1. | ||
62 | |||
63 | config ETRAX_LED_R_NET1 | ||
64 | string "Ethernet group 1 red LED bit" | ||
65 | depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO | ||
66 | default "" | ||
67 | help | ||
68 | Bit to use for the red LED in Ethernet LED group 1. | ||
69 | |||
70 | config ETRAX_V32_LED2G | ||
25 | string "Second green LED bit" | 71 | string "Second green LED bit" |
26 | depends on ETRAX_ARCH_V32 | 72 | depends on ETRAX_ARCH_V32 |
27 | default "PA5" | 73 | default "PA5" |
@@ -29,7 +75,7 @@ config ETRAX_LED2G | |||
29 | Bit to use for the first green LED (status LED). | 75 | Bit to use for the first green LED (status LED). |
30 | Most Axis products use bit A5 here. | 76 | Most Axis products use bit A5 here. |
31 | 77 | ||
32 | config ETRAX_LED2R | 78 | config ETRAX_V32_LED2R |
33 | string "Second red LED bit" | 79 | string "Second red LED bit" |
34 | depends on ETRAX_ARCH_V32 | 80 | depends on ETRAX_ARCH_V32 |
35 | default "PA6" | 81 | default "PA6" |
@@ -37,7 +83,7 @@ config ETRAX_LED2R | |||
37 | Bit to use for the first red LED (network LED). | 83 | Bit to use for the first red LED (network LED). |
38 | Most Axis products use bit A6 here. | 84 | Most Axis products use bit A6 here. |
39 | 85 | ||
40 | config ETRAX_LED3G | 86 | config ETRAX_V32_LED3G |
41 | string "Third green LED bit" | 87 | string "Third green LED bit" |
42 | depends on ETRAX_ARCH_V32 | 88 | depends on ETRAX_ARCH_V32 |
43 | default "PA7" | 89 | default "PA7" |
@@ -45,7 +91,7 @@ config ETRAX_LED3G | |||
45 | Bit to use for the first green LED (drive/power LED). | 91 | Bit to use for the first green LED (drive/power LED). |
46 | Most Axis products use bit A7 here. | 92 | Most Axis products use bit A7 here. |
47 | 93 | ||
48 | config ETRAX_LED3R | 94 | config ETRAX_V32_LED3R |
49 | string "Third red LED bit" | 95 | string "Third red LED bit" |
50 | depends on ETRAX_ARCH_V32 | 96 | depends on ETRAX_ARCH_V32 |
51 | default "PA7" | 97 | default "PA7" |
@@ -54,39 +100,6 @@ config ETRAX_LED3R | |||
54 | Most Axis products use bit A7 here. | 100 | Most Axis products use bit A7 here. |
55 | 101 | ||
56 | choice | 102 | choice |
57 | prompt "Product debug-port" | ||
58 | depends on ETRAX_ARCH_V32 | ||
59 | default ETRAX_DEBUG_PORT0 | ||
60 | |||
61 | config ETRAX_DEBUG_PORT0 | ||
62 | bool "Serial-0" | ||
63 | help | ||
64 | Choose a serial port for the ETRAX debug console. Default to | ||
65 | port 0. | ||
66 | |||
67 | config ETRAX_DEBUG_PORT1 | ||
68 | bool "Serial-1" | ||
69 | help | ||
70 | Use serial port 1 for the console. | ||
71 | |||
72 | config ETRAX_DEBUG_PORT2 | ||
73 | bool "Serial-2" | ||
74 | help | ||
75 | Use serial port 2 for the console. | ||
76 | |||
77 | config ETRAX_DEBUG_PORT3 | ||
78 | bool "Serial-3" | ||
79 | help | ||
80 | Use serial port 3 for the console. | ||
81 | |||
82 | config ETRAX_DEBUG_PORT_NULL | ||
83 | bool "disabled" | ||
84 | help | ||
85 | Disable serial-port debugging. | ||
86 | |||
87 | endchoice | ||
88 | |||
89 | choice | ||
90 | prompt "Kernel GDB port" | 103 | prompt "Kernel GDB port" |
91 | depends on ETRAX_KGDB | 104 | depends on ETRAX_KGDB |
92 | default ETRAX_KGDB_PORT0 | 105 | default ETRAX_KGDB_PORT0 |
@@ -95,25 +108,11 @@ choice | |||
95 | not be enabled under Drivers for built-in interfaces (as it has its | 108 | not be enabled under Drivers for built-in interfaces (as it has its |
96 | own initialization code) and should not be the same as the debug port. | 109 | own initialization code) and should not be the same as the debug port. |
97 | 110 | ||
98 | config ETRAX_KGDB_PORT0 | 111 | config ETRAX_KGDB_PORT4 |
99 | bool "Serial-0" | 112 | bool "Serial-4" |
100 | help | 113 | depends on ETRAX_SERIAL_PORTS = 5 |
101 | Use serial port 0 for kernel debugging. | ||
102 | |||
103 | config ETRAX_KGDB_PORT1 | ||
104 | bool "Serial-1" | ||
105 | help | ||
106 | Use serial port 1 for kernel debugging. | ||
107 | |||
108 | config ETRAX_KGDB_PORT2 | ||
109 | bool "Serial-2" | ||
110 | help | ||
111 | Use serial port 2 for kernel debugging. | ||
112 | |||
113 | config ETRAX_KGDB_PORT3 | ||
114 | bool "Serial-3" | ||
115 | help | 114 | help |
116 | Use serial port 3 for kernel debugging. | 115 | Use serial port 4 for kernel debugging. |
117 | 116 | ||
118 | endchoice | 117 | endchoice |
119 | 118 | ||
diff --git a/arch/cris/arch-v32/boot/Makefile b/arch/cris/arch-v32/boot/Makefile index 26f293ab9617..3f91349c5f12 100644 --- a/arch/cris/arch-v32/boot/Makefile +++ b/arch/cris/arch-v32/boot/Makefile | |||
@@ -1,14 +1,21 @@ | |||
1 | # | 1 | # |
2 | # arch/cris/arch-v32/boot/Makefile | 2 | # arch/cris/arch-v32/boot/Makefile |
3 | # | 3 | # |
4 | target = $(target_boot_dir) | ||
5 | src = $(src_boot_dir) | ||
6 | 4 | ||
7 | zImage: compressed/vmlinuz | 5 | OBJCOPY = objcopy-cris |
6 | OBJCOPYFLAGS = -O binary -R .note -R .comment | ||
8 | 7 | ||
9 | compressed/vmlinuz: $(objtree)/vmlinux | 8 | subdir- := compressed rescue |
10 | @$(MAKE) -f $(src)/compressed/Makefile $(objtree)/vmlinuz | 9 | targets := Image |
11 | 10 | ||
12 | clean: | 11 | $(obj)/Image: vmlinux FORCE |
13 | rm -f zImage tools/build compressed/vmlinux.out | 12 | $(call if_changed,objcopy) |
14 | @$(MAKE) -f $(src)/compressed/Makefile clean | 13 | @echo ' Kernel: $@ is ready' |
14 | |||
15 | $(obj)/compressed/vmlinux: $(obj)/Image FORCE | ||
16 | $(Q)$(MAKE) $(build)=$(obj)/compressed $@ | ||
17 | $(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin | ||
18 | |||
19 | $(obj)/zImage: $(obj)/compressed/vmlinux | ||
20 | @cp $< $@ | ||
21 | @echo ' Kernel: $@ is ready' | ||
diff --git a/arch/cris/arch-v32/boot/compressed/Makefile b/arch/cris/arch-v32/boot/compressed/Makefile index 609692f9d5eb..2c8c2c3039c5 100644 --- a/arch/cris/arch-v32/boot/compressed/Makefile +++ b/arch/cris/arch-v32/boot/compressed/Makefile | |||
@@ -1,41 +1,30 @@ | |||
1 | # | 1 | # |
2 | # lx25/arch/cris/arch-v32/boot/compressed/Makefile | 2 | # arch/cris/arch-v32/boot/compressed/Makefile |
3 | # | 3 | # |
4 | # create a compressed vmlinux image from the original vmlinux files and romfs | ||
5 | # | ||
6 | |||
7 | target = $(target_compressed_dir) | ||
8 | src = $(src_compressed_dir) | ||
9 | 4 | ||
10 | CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE) | 5 | CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE) |
11 | CFLAGS = -O2 | 6 | asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch |
7 | ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch | ||
12 | LD = gcc-cris -mlinux -march=v32 -nostdlib | 8 | LD = gcc-cris -mlinux -march=v32 -nostdlib |
9 | ldflags-y += -T $(obj)/decompress.ld | ||
10 | obj-y = head.o misc.o | ||
11 | OBJECTS = $(obj)/head.o $(obj)/misc.o | ||
13 | OBJCOPY = objcopy-cris | 12 | OBJCOPY = objcopy-cris |
14 | OBJCOPYFLAGS = -O binary --remove-section=.bss | 13 | OBJCOPYFLAGS = -O binary --remove-section=.bss |
15 | OBJECTS = $(target)/head.o $(target)/misc.o | ||
16 | |||
17 | # files to compress | ||
18 | SYSTEM = $(objtree)/vmlinux.bin | ||
19 | |||
20 | all: vmlinuz | ||
21 | |||
22 | $(target)/decompress.bin: $(OBJECTS) | ||
23 | $(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS) | ||
24 | $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin | ||
25 | 14 | ||
26 | $(objtree)/vmlinuz: $(target) piggy.img $(target)/decompress.bin | 15 | quiet_cmd_image = BUILD $@ |
27 | cat $(target)/decompress.bin piggy.img > $(objtree)/vmlinuz | 16 | cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@ |
28 | rm -f piggy.img | ||
29 | cp $(objtree)/vmlinuz $(src) | ||
30 | 17 | ||
31 | $(target)/head.o: $(src)/head.S | 18 | targets := vmlinux piggy.gz decompress.o decompress.bin |
32 | $(CC) -D__ASSEMBLY__ -c $< -o $@ | ||
33 | 19 | ||
34 | # gzip the kernel image | 20 | $(obj)/decompress.o: $(OBJECTS) FORCE |
21 | $(call if_changed,ld) | ||
35 | 22 | ||
36 | piggy.img: $(SYSTEM) | 23 | $(obj)/decompress.bin: $(obj)/decompress.o FORCE |
37 | cat $(SYSTEM) | gzip -f -9 > piggy.img | 24 | $(call if_changed,objcopy) |
38 | 25 | ||
39 | clean: | 26 | $(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE |
40 | rm -f piggy.img $(objtree)/vmlinuz vmlinuz.o decompress.o decompress.bin $(OBJECTS) | 27 | $(call if_changed,image) |
41 | 28 | ||
29 | $(obj)/piggy.gz: $(obj)/../Image FORCE | ||
30 | $(call if_changed,gzip) | ||
diff --git a/arch/cris/arch-v32/boot/compressed/README b/arch/cris/arch-v32/boot/compressed/README index e33691d15c57..182c5d75784b 100644 --- a/arch/cris/arch-v32/boot/compressed/README +++ b/arch/cris/arch-v32/boot/compressed/README | |||
@@ -1,6 +1,5 @@ | |||
1 | Creation of the self-extracting compressed kernel image (vmlinuz) | 1 | Creation of the self-extracting compressed kernel image (vmlinuz) |
2 | ----------------------------------------------------------------- | 2 | ----------------------------------------------------------------- |
3 | $Id: README,v 1.1 2003/08/21 09:37:03 johana Exp $ | ||
4 | 3 | ||
5 | This can be slightly confusing because it's a process with many steps. | 4 | This can be slightly confusing because it's a process with many steps. |
6 | 5 | ||
diff --git a/arch/cris/arch-v32/boot/compressed/head.S b/arch/cris/arch-v32/boot/compressed/head.S index 34cea10a8998..f86208caf32d 100644 --- a/arch/cris/arch-v32/boot/compressed/head.S +++ b/arch/cris/arch-v32/boot/compressed/head.S | |||
@@ -2,13 +2,12 @@ | |||
2 | * Code that sets up the DRAM registers, calls the | 2 | * Code that sets up the DRAM registers, calls the |
3 | * decompressor to unpack the piggybacked kernel, and jumps. | 3 | * decompressor to unpack the piggybacked kernel, and jumps. |
4 | * | 4 | * |
5 | * Copyright (C) 1999 - 2003, Axis Communications AB | 5 | * Copyright (C) 1999 - 2006, Axis Communications AB |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define ASSEMBLER_MACROS_ONLY | 8 | #define ASSEMBLER_MACROS_ONLY |
9 | #include <asm/arch/hwregs/asm/reg_map_asm.h> | 9 | #include <hwregs/asm/reg_map_asm.h> |
10 | #include <asm/arch/hwregs/asm/gio_defs_asm.h> | 10 | #include <asm/arch/mach/startup.inc> |
11 | #include <asm/arch/hwregs/asm/config_defs_asm.h> | ||
12 | 11 | ||
13 | #define RAM_INIT_MAGIC 0x56902387 | 12 | #define RAM_INIT_MAGIC 0x56902387 |
14 | #define COMMAND_LINE_MAGIC 0x87109563 | 13 | #define COMMAND_LINE_MAGIC 0x87109563 |
@@ -22,114 +21,49 @@ start: | |||
22 | di | 21 | di |
23 | 22 | ||
24 | ;; Start clocks for used blocks. | 23 | ;; Start clocks for used blocks. |
25 | move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 | 24 | START_CLOCKS |
26 | move.d [$r1], $r0 | 25 | |
27 | or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ | 26 | ;; Initialize the DRAM registers. |
28 | REG_STATE(config, rw_clk_ctrl, bif, yes) | \ | ||
29 | REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 | ||
30 | move.d $r0, [$r1] | ||
31 | |||
32 | ;; If booting from NAND flash we first have to copy some | ||
33 | ;; data from NAND flash to internal RAM to get the code | ||
34 | ;; that initializes the SDRAM. Lets copy 20 KB. This | ||
35 | ;; code executes at 0x38010000 if booting from NAND and | ||
36 | ;; we are guaranted that at least 0x200 bytes are good so | ||
37 | ;; lets start from there. The first 8192 bytes in the nand | ||
38 | ;; flash is spliced with zeroes and is thus 16384 bytes. | ||
39 | move.d 0x38010200, $r10 | ||
40 | move.d 0x14200, $r11 ; Start offset in NAND flash 0x10200 + 16384 | ||
41 | move.d 0x5000, $r12 ; Length of copy | ||
42 | |||
43 | ;; Before this code the tools add a partitiontable so the PC | ||
44 | ;; has an offset from the linked address. | ||
45 | offset1: | ||
46 | lapcq ., $r13 ; get PC | ||
47 | add.d first_copy_complete-offset1, $r13 | ||
48 | |||
49 | #include "../../lib/nand_init.S" | ||
50 | |||
51 | first_copy_complete: | ||
52 | ;; Initialze the DRAM registers. | ||
53 | cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? | 27 | cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? |
54 | beq dram_init_finished | 28 | beq dram_init_finished |
55 | nop | 29 | nop |
56 | 30 | ||
57 | #include "../../lib/dram_init.S" | 31 | #include "../../mach/dram_init.S" |
58 | 32 | ||
59 | dram_init_finished: | 33 | dram_init_finished: |
60 | lapcq ., $r13 ; get PC | ||
61 | add.d second_copy_complete-dram_init_finished, $r13 | ||
62 | |||
63 | move.d REG_ADDR(config, regi_config, r_bootsel), $r0 | ||
64 | move.d [$r0], $r0 | ||
65 | and.d REG_MASK(config, r_bootsel, boot_mode), $r0 | ||
66 | cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 | ||
67 | bne second_copy_complete ; No NAND boot | ||
68 | nop | ||
69 | |||
70 | ;; Copy 2MB from NAND flash to SDRAM (at 2-4MB into the SDRAM) | ||
71 | move.d 0x40204000, $r10 | ||
72 | move.d 0x8000, $r11 | ||
73 | move.d 0x200000, $r12 | ||
74 | ba copy_nand_to_ram | ||
75 | nop | ||
76 | second_copy_complete: | ||
77 | |||
78 | ;; Initiate the PA port. | ||
79 | move.d CONFIG_ETRAX_DEF_GIO_PA_OUT, $r0 | ||
80 | move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r1 | ||
81 | move.d $r0, [$r1] | ||
82 | |||
83 | move.d CONFIG_ETRAX_DEF_GIO_PA_OE, $r0 | ||
84 | move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r1 | ||
85 | move.d $r0, [$r1] | ||
86 | 34 | ||
35 | GIO_INIT | ||
87 | ;; Setup the stack to a suitably high address. | 36 | ;; Setup the stack to a suitably high address. |
88 | ;; We assume 8 MB is the minimum DRAM and put | 37 | ;; We assume 8 MB is the minimum DRAM and put |
89 | ;; the SP at the top for now. | 38 | ;; the SP at the top for now. |
90 | 39 | ||
91 | move.d 0x40800000, $sp | 40 | move.d 0x40800000, $sp |
92 | 41 | ||
93 | ;; Figure out where the compressed piggyback image is | 42 | ;; Figure out where the compressed piggyback image is. |
94 | ;; in the flash (since we wont try to copy it to DRAM | 43 | ;; It is either in [NOR] flash (we don't want to copy it |
95 | ;; before unpacking). It is at _edata, but in flash. | 44 | ;; to DRAM before unpacking), or copied to DRAM |
45 | ;; by the [NAND] flash boot loader. | ||
46 | ;; The piggyback image is at _edata, but relative to where the | ||
47 | ;; image is actually located in memory, not where it is linked | ||
48 | ;; (the decompressor is linked at 0x40700000+ and runs there). | ||
96 | ;; Use (_edata - herami) as offset to the current PC. | 49 | ;; Use (_edata - herami) as offset to the current PC. |
97 | 50 | ||
98 | move.d REG_ADDR(config, regi_config, r_bootsel), $r0 | ||
99 | move.d [$r0], $r0 | ||
100 | and.d REG_MASK(config, r_bootsel, boot_mode), $r0 | ||
101 | cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 | ||
102 | beq hereami2 | ||
103 | nop | ||
104 | hereami: | 51 | hereami: |
105 | lapcq ., $r5 ; get PC | 52 | lapcq ., $r5 ; get PC |
106 | and.d 0x7fffffff, $r5 ; strip any non-cache bit | 53 | and.d 0x7fffffff, $r5 ; strip any non-cache bit |
107 | move.d $r5, $r0 ; save for later - flash address of 'herami' | 54 | move.d $r5, $r0 ; source address of 'herami' |
108 | add.d _edata, $r5 | 55 | add.d _edata, $r5 |
109 | sub.d hereami, $r5 ; r5 = flash address of '_edata' | 56 | sub.d hereami, $r5 ; r5 = flash address of '_edata' |
110 | move.d hereami, $r1 ; destination | 57 | move.d hereami, $r1 ; destination |
111 | ba 2f | 58 | |
112 | nop | ||
113 | hereami2: | ||
114 | lapcq ., $r5 ; get PC | ||
115 | and.d 0x00ffffff, $r5 ; strip any non-cache bit | ||
116 | move.d $r5, $r6 | ||
117 | or.d 0x40200000, $r6 | ||
118 | move.d $r6, $r0 ; save for later - flash address of 'herami' | ||
119 | add.d _edata, $r5 | ||
120 | sub.d hereami2, $r5 ; r5 = flash address of '_edata' | ||
121 | add.d 0x40200000, $r5 | ||
122 | move.d hereami2, $r1 ; destination | ||
123 | 2: | ||
124 | ;; Copy text+data to DRAM | 59 | ;; Copy text+data to DRAM |
125 | 60 | ||
126 | move.d _edata, $r2 ; end destination | 61 | move.d _edata, $r2 ; end destination |
127 | 1: move.w [$r0+], $r3 | 62 | 1: move.w [$r0+], $r3 ; from herami+ source |
128 | move.w $r3, [$r1+] | 63 | move.w $r3, [$r1+] ; to hereami+ destination (linked address) |
129 | cmp.d $r2, $r1 | 64 | cmp.d $r2, $r1 ; finish when destination == _edata |
130 | bcs 1b | 65 | bcs 1b |
131 | nop | 66 | nop |
132 | |||
133 | move.d input_data, $r0 ; for the decompressor | 67 | move.d input_data, $r0 ; for the decompressor |
134 | move.d $r5, [$r0] ; for the decompressor | 68 | move.d $r5, [$r0] ; for the decompressor |
135 | 69 | ||
@@ -144,16 +78,24 @@ hereami2: | |||
144 | nop | 78 | nop |
145 | 79 | ||
146 | ;; Save command line magic and address. | 80 | ;; Save command line magic and address. |
147 | move.d _cmd_line_magic, $r12 | 81 | move.d _cmd_line_magic, $r0 |
148 | move.d $r10, [$r12] | 82 | move.d $r10, [$r0] |
149 | move.d _cmd_line_addr, $r12 | 83 | move.d _cmd_line_addr, $r0 |
150 | move.d $r11, [$r12] | 84 | move.d $r11, [$r0] |
85 | |||
86 | ;; Save boot source indicator | ||
87 | move.d _boot_source, $r0 | ||
88 | move.d $r12, [$r0] | ||
151 | 89 | ||
152 | ;; Do the decompression and save compressed size in _inptr | 90 | ;; Do the decompression and save compressed size in _inptr |
153 | 91 | ||
154 | jsr decompress_kernel | 92 | jsr decompress_kernel |
155 | nop | 93 | nop |
156 | 94 | ||
95 | ;; Restore boot source indicator | ||
96 | move.d _boot_source, $r12 | ||
97 | move.d [$r12], $r12 | ||
98 | |||
157 | ;; Restore command line magic and address. | 99 | ;; Restore command line magic and address. |
158 | move.d _cmd_line_magic, $r10 | 100 | move.d _cmd_line_magic, $r10 |
159 | move.d [$r10], $r10 | 101 | move.d [$r10], $r10 |
@@ -166,11 +108,10 @@ hereami2: | |||
166 | move.d [$r0], $r9 ; flash address of compressed kernel | 108 | move.d [$r0], $r9 ; flash address of compressed kernel |
167 | move.d inptr, $r0 | 109 | move.d inptr, $r0 |
168 | add.d [$r0], $r9 ; size of compressed kernel | 110 | add.d [$r0], $r9 ; size of compressed kernel |
169 | cmp.d 0x40200000, $r9 | 111 | cmp.d 0x40000000, $r9 ; image in DRAM ? |
170 | blo enter_kernel | 112 | blo enter_kernel ; no, must be [NOR] flash, jump |
171 | nop | 113 | nop ; delay slot |
172 | sub.d 0x40200000, $r9 | 114 | and.d 0x001fffff, $r9 ; assume compressed kernel was < 2M |
173 | add.d 0x4000, $r9 | ||
174 | 115 | ||
175 | enter_kernel: | 116 | enter_kernel: |
176 | ;; Enter the decompressed kernel | 117 | ;; Enter the decompressed kernel |
@@ -186,7 +127,7 @@ _cmd_line_magic: | |||
186 | .dword 0 | 127 | .dword 0 |
187 | _cmd_line_addr: | 128 | _cmd_line_addr: |
188 | .dword 0 | 129 | .dword 0 |
189 | is_nand_boot: | 130 | _boot_source: |
190 | .dword 0 | 131 | .dword 0 |
191 | 132 | ||
192 | #include "../../lib/hw_settings.S" | 133 | #include "../../mach/hw_settings.S" |
diff --git a/arch/cris/arch-v32/boot/compressed/misc.c b/arch/cris/arch-v32/boot/compressed/misc.c index 0169ba1ca9c9..55b2695c5d70 100644 --- a/arch/cris/arch-v32/boot/compressed/misc.c +++ b/arch/cris/arch-v32/boot/compressed/misc.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * misc.c | 2 | * misc.c |
3 | * | 3 | * |
4 | * $Id: misc.c,v 1.8 2005/04/24 18:34:29 starvik Exp $ | ||
5 | * | ||
6 | * This is a collection of several routines from gzip-1.0.3 | 4 | * This is a collection of several routines from gzip-1.0.3 |
7 | * adapted for Linux. | 5 | * adapted for Linux. |
8 | * | 6 | * |
@@ -22,9 +20,13 @@ | |||
22 | 20 | ||
23 | 21 | ||
24 | #include <linux/types.h> | 22 | #include <linux/types.h> |
25 | #include <asm/arch/hwregs/reg_rdwr.h> | 23 | #include <hwregs/reg_rdwr.h> |
26 | #include <asm/arch/hwregs/reg_map.h> | 24 | #include <hwregs/reg_map.h> |
27 | #include <asm/arch/hwregs/ser_defs.h> | 25 | #include <hwregs/ser_defs.h> |
26 | #include <hwregs/pinmux_defs.h> | ||
27 | #ifdef CONFIG_CRIS_MACH_ARTPEC3 | ||
28 | #include <hwregs/clkgen_defs.h> | ||
29 | #endif | ||
28 | 30 | ||
29 | /* | 31 | /* |
30 | * gzip declarations | 32 | * gzip declarations |
@@ -85,7 +87,6 @@ static unsigned outcnt = 0; /* bytes in output buffer */ | |||
85 | # define Tracecv(c,x) | 87 | # define Tracecv(c,x) |
86 | #endif | 88 | #endif |
87 | 89 | ||
88 | static int fill_inbuf(void); | ||
89 | static void flush_window(void); | 90 | static void flush_window(void); |
90 | static void error(char *m); | 91 | static void error(char *m); |
91 | static void gzip_mark(void **); | 92 | static void gzip_mark(void **); |
@@ -186,6 +187,8 @@ memset(void* s, int c, size_t n) | |||
186 | char *ss = (char*)s; | 187 | char *ss = (char*)s; |
187 | 188 | ||
188 | for (i=0;i<n;i++) ss[i] = c; | 189 | for (i=0;i<n;i++) ss[i] = c; |
190 | |||
191 | return s; | ||
189 | } | 192 | } |
190 | 193 | ||
191 | void* | 194 | void* |
@@ -196,6 +199,8 @@ memcpy(void* __dest, __const void* __src, | |||
196 | char *d = (char *)__dest, *s = (char *)__src; | 199 | char *d = (char *)__dest, *s = (char *)__src; |
197 | 200 | ||
198 | for (i=0;i<__n;i++) d[i] = s[i]; | 201 | for (i=0;i<__n;i++) d[i] = s[i]; |
202 | |||
203 | return __dest; | ||
199 | } | 204 | } |
200 | 205 | ||
201 | /* =========================================================================== | 206 | /* =========================================================================== |
@@ -225,15 +230,15 @@ flush_window() | |||
225 | static void | 230 | static void |
226 | error(char *x) | 231 | error(char *x) |
227 | { | 232 | { |
228 | puts("\n\n"); | 233 | puts("\r\n\n"); |
229 | puts(x); | 234 | puts(x); |
230 | puts("\n\n -- System halted\n"); | 235 | puts("\r\n\n -- System halted\n"); |
231 | 236 | ||
232 | while(1); /* Halt */ | 237 | while(1); /* Halt */ |
233 | } | 238 | } |
234 | 239 | ||
235 | void | 240 | void |
236 | setup_normal_output_buffer() | 241 | setup_normal_output_buffer(void) |
237 | { | 242 | { |
238 | output_data = (char *)KERNEL_LOAD_ADR; | 243 | output_data = (char *)KERNEL_LOAD_ADR; |
239 | } | 244 | } |
@@ -262,15 +267,17 @@ serial_setup(reg_scope_instances regi_ser) | |||
262 | rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div); | 267 | rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div); |
263 | 268 | ||
264 | tr_ctrl.stop_bits = 1; /* 2 stop bits. */ | 269 | tr_ctrl.stop_bits = 1; /* 2 stop bits. */ |
270 | tr_ctrl.en = 1; /* enable transmitter */ | ||
271 | rec_ctrl.en = 1; /* enabler receiver */ | ||
265 | 272 | ||
266 | /* | 273 | /* |
267 | * The baudrate setup is a bit fishy, but in the end the transceiver is | 274 | * The baudrate setup used to be a bit fishy, but now transmitter and |
268 | * set to 4800 and the receiver to 115200. The magic value is | 275 | * receiver are both set to the intended baud rate, 115200. |
269 | * 29.493 MHz. | 276 | * The magic value is 29.493 MHz. |
270 | */ | 277 | */ |
271 | tr_ctrl.base_freq = regk_ser_f29_493; | 278 | tr_ctrl.base_freq = regk_ser_f29_493; |
272 | rec_ctrl.base_freq = regk_ser_f29_493; | 279 | rec_ctrl.base_freq = regk_ser_f29_493; |
273 | tr_baud.div = (29493000 / 8) / 4800; | 280 | tr_baud.div = (29493000 / 8) / 115200; |
274 | rec_baud.div = (29493000 / 8) / 115200; | 281 | rec_baud.div = (29493000 / 8) / 115200; |
275 | 282 | ||
276 | REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl); | 283 | REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl); |
@@ -280,25 +287,52 @@ serial_setup(reg_scope_instances regi_ser) | |||
280 | } | 287 | } |
281 | 288 | ||
282 | void | 289 | void |
283 | decompress_kernel() | 290 | decompress_kernel(void) |
284 | { | 291 | { |
285 | char revision; | 292 | char revision; |
286 | 293 | ||
287 | /* input_data is set in head.S */ | 294 | #if defined(CONFIG_ETRAX_DEBUG_PORT1) || \ |
288 | inbuf = input_data; | 295 | defined(CONFIG_ETRAX_DEBUG_PORT2) || \ |
296 | defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
297 | reg_pinmux_rw_hwprot hwprot; | ||
298 | |||
299 | #ifdef CONFIG_CRIS_MACH_ARTPEC3 | ||
300 | reg_clkgen_rw_clk_ctrl clk_ctrl; | ||
301 | |||
302 | /* Enable corresponding clock region when serial 1..3 selected */ | ||
303 | |||
304 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | ||
305 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
306 | REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); | ||
307 | #endif | ||
308 | |||
309 | /* pinmux setup for ports 1..3 */ | ||
310 | hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
311 | #endif | ||
289 | 312 | ||
290 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | 313 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 |
291 | serial_setup(regi_ser0); | 314 | serial_setup(regi_ser0); |
292 | #endif | 315 | #endif |
293 | #ifdef CONFIG_ETRAX_DEBUG_PORT1 | 316 | #ifdef CONFIG_ETRAX_DEBUG_PORT1 |
317 | hwprot.ser1 = regk_pinmux_yes; | ||
294 | serial_setup(regi_ser1); | 318 | serial_setup(regi_ser1); |
295 | #endif | 319 | #endif |
296 | #ifdef CONFIG_ETRAX_DEBUG_PORT2 | 320 | #ifdef CONFIG_ETRAX_DEBUG_PORT2 |
321 | hwprot.ser2 = regk_pinmux_yes; | ||
297 | serial_setup(regi_ser2); | 322 | serial_setup(regi_ser2); |
298 | #endif | 323 | #endif |
299 | #ifdef CONFIG_ETRAX_DEBUG_PORT3 | 324 | #ifdef CONFIG_ETRAX_DEBUG_PORT3 |
325 | hwprot.ser3 = regk_pinmux_yes; | ||
300 | serial_setup(regi_ser3); | 326 | serial_setup(regi_ser3); |
301 | #endif | 327 | #endif |
328 | #if defined(CONFIG_ETRAX_DEBUG_PORT1) || \ | ||
329 | defined(CONFIG_ETRAX_DEBUG_PORT2) || \ | ||
330 | defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
331 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
332 | #endif | ||
333 | |||
334 | /* input_data is set in head.S */ | ||
335 | inbuf = input_data; | ||
302 | 336 | ||
303 | setup_normal_output_buffer(); | 337 | setup_normal_output_buffer(); |
304 | 338 | ||
@@ -307,11 +341,11 @@ decompress_kernel() | |||
307 | __asm__ volatile ("move $vr,%0" : "=rm" (revision)); | 341 | __asm__ volatile ("move $vr,%0" : "=rm" (revision)); |
308 | if (revision < 32) | 342 | if (revision < 32) |
309 | { | 343 | { |
310 | puts("You need an ETRAX FS to run Linux 2.6/crisv32.\n"); | 344 | puts("You need an ETRAX FS to run Linux 2.6/crisv32.\r\n"); |
311 | while(1); | 345 | while(1); |
312 | } | 346 | } |
313 | 347 | ||
314 | puts("Uncompressing Linux...\n"); | 348 | puts("Uncompressing Linux...\r\n"); |
315 | gunzip(); | 349 | gunzip(); |
316 | puts("Done. Now booting the kernel.\n"); | 350 | puts("Done. Now booting the kernel.\r\n"); |
317 | } | 351 | } |
diff --git a/arch/cris/arch-v32/boot/rescue/Makefile b/arch/cris/arch-v32/boot/rescue/Makefile index f668a8198724..c0987795dcb7 100644 --- a/arch/cris/arch-v32/boot/rescue/Makefile +++ b/arch/cris/arch-v32/boot/rescue/Makefile | |||
@@ -1,36 +1,27 @@ | |||
1 | # | 1 | # |
2 | # Makefile for rescue code | 2 | # Makefile for rescue (bootstrap) code |
3 | # | 3 | # |
4 | target = $(target_rescue_dir) | ||
5 | src = $(src_rescue_dir) | ||
6 | 4 | ||
7 | CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE) | 5 | CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE) |
8 | CFLAGS = -O2 | 6 | ccflags-y += -O2 -I $(srctree)/include/asm/arch/mach/ \ |
7 | -I $(srctree)/include/asm/arch | ||
8 | asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch | ||
9 | LD = gcc-cris -mlinux -march=v32 -nostdlib | 9 | LD = gcc-cris -mlinux -march=v32 -nostdlib |
10 | ldflags-y += -T $(obj)/rescue.ld | ||
11 | LDPOSTFLAGS = -lgcc | ||
10 | OBJCOPY = objcopy-cris | 12 | OBJCOPY = objcopy-cris |
11 | OBJCOPYFLAGS = -O binary --remove-section=.bss | 13 | OBJCOPYFLAGS = -O binary --remove-section=.bss |
14 | obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o | ||
15 | OBJECT := $(obj)/head.o | ||
12 | 16 | ||
13 | all: $(target)/rescue.bin | 17 | targets := rescue.o rescue.bin |
14 | 18 | ||
15 | rescue: rescue.bin | 19 | quiet_cmd_ldlibgcc = LD $@ |
16 | # do nothing | 20 | cmd_ldlibgcc = $(LD) $(LDFLAGS) $(filter-out FORCE,$^) $(LDPOSTFLAGS) -o $@ |
17 | 21 | ||
18 | $(target)/rescue.bin: $(target) $(target)/head.o | 22 | $(obj)/rescue.o: $(OBJECTS) FORCE |
19 | $(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o | 23 | $(call if_changed,ldlibgcc) |
20 | $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin | ||
21 | cp -p $(target)/rescue.bin $(objtree) | ||
22 | 24 | ||
23 | $(target): | 25 | $(obj)/rescue.bin: $(obj)/rescue.o FORCE |
24 | mkdir -p $(target) | 26 | $(call if_changed,objcopy) |
25 | 27 | cp -p $(obj)/rescue.bin $(objtree) | |
26 | $(target)/head.o: $(src)/head.S | ||
27 | $(CC) -D__ASSEMBLY__ -c $< -o $*.o | ||
28 | |||
29 | clean: | ||
30 | rm -f $(target)/*.o $(target)/*.bin | ||
31 | |||
32 | fastdep: | ||
33 | |||
34 | modules: | ||
35 | |||
36 | modules-install: | ||
diff --git a/arch/cris/arch-v32/boot/rescue/head.S b/arch/cris/arch-v32/boot/rescue/head.S index 8cdb4011bc16..5f846b7700a3 100644 --- a/arch/cris/arch-v32/boot/rescue/head.S +++ b/arch/cris/arch-v32/boot/rescue/head.S | |||
@@ -1,38 +1,26 @@ | |||
1 | /* $Id: head.S,v 1.4 2004/11/01 16:10:28 starvik Exp $ | 1 | /* |
2 | * Just get started by jumping to CONFIG_ETRAX_PTABLE_SECTOR to start | ||
3 | * kernel decompressor. | ||
4 | * | ||
5 | * In practice, this only works for NOR flash (or some convoluted RAM boot) | ||
6 | * and hence is not really useful for Artpec-3, so it's Etrax FS / NOR only. | ||
2 | * | 7 | * |
3 | * This used to be the rescue code but now that is handled by the | ||
4 | * RedBoot based RFL instead. Nothing to see here, move along. | ||
5 | */ | 8 | */ |
6 | 9 | ||
7 | #include <asm/arch/hwregs/reg_map_asm.h> | 10 | #include <mach/startup.inc> |
8 | #include <asm/arch/hwregs/config_defs_asm.h> | ||
9 | 11 | ||
10 | .text | 12 | #ifdef CONFIG_ETRAX_AXISFLASHMAP |
11 | 13 | ||
12 | ;; Start clocks for used blocks. | 14 | ;; Code |
13 | move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 | ||
14 | move.d [$r1], $r0 | ||
15 | or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ | ||
16 | REG_STATE(config, rw_clk_ctrl, bif, yes) | \ | ||
17 | REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 | ||
18 | move.d $r0, [$r1] | ||
19 | 15 | ||
20 | ;; Copy 68KB NAND flash to Internal RAM (if NAND boot) | 16 | .text |
21 | move.d 0x38004000, $r10 | 17 | start: |
22 | move.d 0x8000, $r11 | ||
23 | move.d 0x11000, $r12 | ||
24 | move.d copy_complete, $r13 | ||
25 | and.d 0x000fffff, $r13 | ||
26 | or.d 0x38000000, $r13 | ||
27 | 18 | ||
28 | #include "../../lib/nand_init.S" | 19 | ;; Start clocks for used blocks. |
20 | START_CLOCKS | ||
29 | 21 | ||
30 | ;; No NAND found | ||
31 | move.d CONFIG_ETRAX_PTABLE_SECTOR, $r10 | 22 | move.d CONFIG_ETRAX_PTABLE_SECTOR, $r10 |
32 | jump $r10 ; Jump to decompresser | 23 | jump $r10 ; Jump to decompressor |
33 | nop | 24 | nop |
34 | 25 | ||
35 | copy_complete: | 26 | #endif |
36 | move.d 0x38000000 + CONFIG_ETRAX_PTABLE_SECTOR, $r10 | ||
37 | jump $r10 ; Jump to decompresser | ||
38 | nop | ||
diff --git a/arch/cris/arch-v32/boot/rescue/rescue.ld b/arch/cris/arch-v32/boot/rescue/rescue.ld index 42b11aa122b2..8ac646bc1a2b 100644 --- a/arch/cris/arch-v32/boot/rescue/rescue.ld +++ b/arch/cris/arch-v32/boot/rescue/rescue.ld | |||
@@ -1,20 +1,43 @@ | |||
1 | /*#OUTPUT_FORMAT(elf32-us-cris) */ | ||
2 | OUTPUT_ARCH (crisv32) | ||
3 | /* Now that NAND support has been stripped, this file could be simplified, | ||
4 | * but it doesn't do any harm on the other hand so why bother. */ | ||
5 | |||
1 | MEMORY | 6 | MEMORY |
2 | { | 7 | { |
3 | flash : ORIGIN = 0x00000000, | 8 | bootblk : ORIGIN = 0x38000000, |
4 | LENGTH = 0x00100000 | 9 | LENGTH = 0x00004000 |
10 | intmem : ORIGIN = 0x38004000, | ||
11 | LENGTH = 0x00005000 | ||
5 | } | 12 | } |
6 | 13 | ||
7 | SECTIONS | 14 | SECTIONS |
8 | { | 15 | { |
9 | .text : | 16 | .text : |
10 | { | 17 | { |
11 | stext = . ; | 18 | _stext = . ; |
12 | *(.text) | 19 | *(.text) |
13 | etext = . ; | 20 | *(.init.text) |
14 | } > flash | 21 | *(.rodata) |
22 | *(.rodata.*) | ||
23 | _etext = . ; | ||
24 | } > bootblk | ||
15 | .data : | 25 | .data : |
16 | { | 26 | { |
17 | *(.data) | 27 | *(.data) |
18 | edata = . ; | 28 | _edata = . ; |
19 | } > flash | 29 | } > bootblk |
30 | .bss : | ||
31 | { | ||
32 | _bss = . ; | ||
33 | *(.bss) | ||
34 | _end = ALIGN( 0x10 ) ; | ||
35 | } > intmem | ||
36 | |||
37 | /* Get rid of stuff from EXPORT_SYMBOL(foo). */ | ||
38 | /DISCARD/ : | ||
39 | { | ||
40 | *(__ksymtab_strings) | ||
41 | *(__ksymtab) | ||
42 | } | ||
20 | } | 43 | } |
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index c329cce2a0c3..2a92cb1886ca 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig | |||
@@ -4,64 +4,102 @@ config ETRAX_ETHERNET | |||
4 | bool "Ethernet support" | 4 | bool "Ethernet support" |
5 | depends on ETRAX_ARCH_V32 | 5 | depends on ETRAX_ARCH_V32 |
6 | select NET_ETHERNET | 6 | select NET_ETHERNET |
7 | select MII | ||
7 | help | 8 | help |
8 | This option enables the ETRAX FS built-in 10/100Mbit Ethernet | 9 | This option enables the ETRAX FS built-in 10/100Mbit Ethernet |
9 | controller. | 10 | controller. |
10 | 11 | ||
11 | config ETRAX_ETHERNET_HW_CSUM | 12 | config ETRAX_NO_PHY |
12 | bool "Hardware accelerated ethernet checksum and scatter/gather" | 13 | bool "PHY not present" |
13 | depends on ETRAX_ETHERNET | 14 | depends on ETRAX_ETHERNET |
14 | depends on ETRAX_STREAMCOPROC | 15 | default N |
15 | default y | ||
16 | help | 16 | help |
17 | Hardware acceleration of checksumming and scatter/gather | 17 | This option disables all MDIO communication with an ethernet |
18 | transceiver connected to the MII interface. This option shall | ||
19 | typically be enabled if the MII interface is connected to a | ||
20 | switch. This option should normally be disabled. If enabled, | ||
21 | speed and duplex will be locked to 100 Mbit and full duplex. | ||
18 | 22 | ||
19 | config ETRAX_ETHERNET_IFACE0 | 23 | config ETRAX_ETHERNET_IFACE0 |
20 | depends on ETRAX_ETHERNET | 24 | depends on ETRAX_ETHERNET |
21 | bool "Enable network interface 0" | 25 | bool "Enable network interface 0" |
22 | 26 | ||
23 | config ETRAX_ETHERNET_IFACE1 | 27 | config ETRAX_ETHERNET_IFACE1 |
24 | depends on ETRAX_ETHERNET | 28 | depends on (ETRAX_ETHERNET && ETRAXFS) |
25 | bool "Enable network interface 1 (uses DMA6 and DMA7)" | 29 | bool "Enable network interface 1 (uses DMA6 and DMA7)" |
26 | 30 | ||
31 | config ETRAX_ETHERNET_GBIT | ||
32 | depends on (ETRAX_ETHERNET && CRIS_MACH_ARTPEC3) | ||
33 | bool "Enable gigabit Ethernet support" | ||
34 | |||
27 | choice | 35 | choice |
28 | prompt "Network LED behavior" | 36 | prompt "Eth0 led group" |
29 | depends on ETRAX_ETHERNET | 37 | depends on ETRAX_ETHERNET_IFACE0 |
30 | default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY | 38 | default ETRAX_ETH0_USE_LEDGRP0 |
31 | 39 | ||
32 | config ETRAX_NETWORK_LED_ON_WHEN_LINK | 40 | config ETRAX_ETH0_USE_LEDGRP0 |
33 | bool "LED_on_when_link" | 41 | bool "Use LED grp 0" |
42 | depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO | ||
34 | help | 43 | help |
35 | Selecting LED_on_when_link will light the LED when there is a | 44 | Use LED grp 0 for eth0 |
36 | connection and will flash off when there is activity. | ||
37 | 45 | ||
38 | Selecting LED_on_when_activity will light the LED only when | 46 | config ETRAX_ETH0_USE_LEDGRP1 |
39 | there is activity. | 47 | bool "Use LED grp 1" |
40 | 48 | depends on ETRAX_NBR_LED_GRP_TWO | |
41 | This setting will also affect the behaviour of other activity LEDs | 49 | help |
42 | e.g. Bluetooth. | 50 | Use LED grp 1 for eth0 |
43 | 51 | ||
44 | config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY | 52 | config ETRAX_ETH0_USE_LEDGRPNULL |
45 | bool "LED_on_when_activity" | 53 | bool "Use no LEDs for eth0" |
46 | help | 54 | help |
47 | Selecting LED_on_when_link will light the LED when there is a | 55 | Use no LEDs for eth0 |
48 | connection and will flash off when there is activity. | 56 | endchoice |
49 | 57 | ||
50 | Selecting LED_on_when_activity will light the LED only when | 58 | choice |
51 | there is activity. | 59 | prompt "Eth1 led group" |
60 | depends on ETRAX_ETHERNET_IFACE1 | ||
61 | default ETRAX_ETH1_USE_LEDGRP1 | ||
62 | |||
63 | config ETRAX_ETH1_USE_LEDGRP0 | ||
64 | bool "Use LED grp 0" | ||
65 | depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO | ||
66 | help | ||
67 | Use LED grp 0 for eth1 | ||
52 | 68 | ||
53 | This setting will also affect the behaviour of other activity LEDs | 69 | config ETRAX_ETH1_USE_LEDGRP1 |
54 | e.g. Bluetooth. | 70 | bool "Use LED grp 1" |
71 | depends on ETRAX_NBR_LED_GRP_TWO | ||
72 | help | ||
73 | Use LED grp 1 for eth1 | ||
55 | 74 | ||
75 | config ETRAX_ETH1_USE_LEDGRPNULL | ||
76 | bool "Use no LEDs for eth1" | ||
77 | help | ||
78 | Use no LEDs for eth1 | ||
56 | endchoice | 79 | endchoice |
57 | 80 | ||
58 | config ETRAXFS_SERIAL | 81 | config ETRAXFS_SERIAL |
59 | bool "Serial-port support" | 82 | bool "Serial-port support" |
60 | depends on ETRAX_ARCH_V32 | 83 | depends on ETRAX_ARCH_V32 |
84 | select SERIAL_CORE | ||
85 | select SERIAL_CORE_CONSOLE | ||
61 | help | 86 | help |
62 | Enables the ETRAX FS serial driver for ser0 (ttyS0) | 87 | Enables the ETRAX FS serial driver for ser0 (ttyS0) |
63 | You probably want this enabled. | 88 | You probably want this enabled. |
64 | 89 | ||
90 | config ETRAX_RS485 | ||
91 | bool "RS-485 support" | ||
92 | depends on ETRAXFS_SERIAL | ||
93 | help | ||
94 | Enables support for RS-485 serial communication. | ||
95 | |||
96 | config ETRAX_RS485_DISABLE_RECEIVER | ||
97 | bool "Disable serial receiver" | ||
98 | depends on ETRAX_RS485 | ||
99 | help | ||
100 | It is necessary to disable the serial receiver to avoid serial | ||
101 | loopback. Not all products are able to do this in software only. | ||
102 | |||
65 | config ETRAX_SERIAL_PORT0 | 103 | config ETRAX_SERIAL_PORT0 |
66 | bool "Serial port 0 enabled" | 104 | bool "Serial port 0 enabled" |
67 | depends on ETRAXFS_SERIAL | 105 | depends on ETRAXFS_SERIAL |
@@ -72,50 +110,28 @@ config ETRAX_SERIAL_PORT0 | |||
72 | ser0 can use dma4 or dma6 for output and dma5 or dma7 for input. | 110 | ser0 can use dma4 or dma6 for output and dma5 or dma7 for input. |
73 | 111 | ||
74 | choice | 112 | choice |
75 | prompt "Ser0 DMA in channel " | 113 | prompt "Ser0 default port type " |
76 | depends on ETRAX_SERIAL_PORT0 | 114 | depends on ETRAX_SERIAL_PORT0 |
77 | default ETRAX_SERIAL_PORT0_NO_DMA_IN | 115 | default ETRAX_SERIAL_PORT0_TYPE_232 |
78 | help | 116 | help |
79 | What DMA channel to use for ser0. | 117 | Type of serial port. |
80 | |||
81 | 118 | ||
82 | config ETRAX_SERIAL_PORT0_NO_DMA_IN | 119 | config ETRAX_SERIAL_PORT0_TYPE_232 |
83 | bool "Ser0 uses no DMA for input" | 120 | bool "Ser0 is a RS-232 port" |
84 | help | 121 | help |
85 | Do not use DMA for ser0 input. | 122 | Configure serial port 0 to be a RS-232 port. |
86 | 123 | ||
87 | config ETRAX_SERIAL_PORT0_DMA7_IN | 124 | config ETRAX_SERIAL_PORT0_TYPE_485HD |
88 | bool "Ser0 uses DMA7 for input" | 125 | bool "Ser0 is a half duplex RS-485 port" |
89 | depends on ETRAX_SERIAL_PORT0 | 126 | depends on ETRAX_RS485 |
90 | help | ||
91 | Enables the DMA7 input channel for ser0 (ttyS0). | ||
92 | If you do not enable DMA, an interrupt for each character will be | ||
93 | used when receiving data. | ||
94 | Normally you want to use DMA, unless you use the DMA channel for | ||
95 | something else. | ||
96 | |||
97 | endchoice | ||
98 | |||
99 | choice | ||
100 | prompt "Ser0 DMA out channel" | ||
101 | depends on ETRAX_SERIAL_PORT0 | ||
102 | default ETRAX_SERIAL_PORT0_NO_DMA_OUT | ||
103 | |||
104 | config ETRAX_SERIAL_PORT0_NO_DMA_OUT | ||
105 | bool "Ser0 uses no DMA for output" | ||
106 | help | 127 | help |
107 | Do not use DMA for ser0 output. | 128 | Configure serial port 0 to be a half duplex (two wires) RS-485 port. |
108 | 129 | ||
109 | config ETRAX_SERIAL_PORT0_DMA6_OUT | 130 | config ETRAX_SERIAL_PORT0_TYPE_485FD |
110 | bool "Ser0 uses DMA6 for output" | 131 | bool "Ser0 is a full duplex RS-485 port" |
111 | depends on ETRAX_SERIAL_PORT0 | 132 | depends on ETRAX_RS485 |
112 | help | 133 | help |
113 | Enables the DMA6 output channel for ser0 (ttyS0). | 134 | Configure serial port 0 to be a full duplex (four wires) RS-485 port. |
114 | If you do not enable DMA, an interrupt for each character will be | ||
115 | used when transmitting data. | ||
116 | Normally you want to use DMA, unless you use the DMA channel for | ||
117 | something else. | ||
118 | |||
119 | endchoice | 135 | endchoice |
120 | 136 | ||
121 | config ETRAX_SER0_DTR_BIT | 137 | config ETRAX_SER0_DTR_BIT |
@@ -141,52 +157,28 @@ config ETRAX_SERIAL_PORT1 | |||
141 | Enables the ETRAX FS serial driver for ser1 (ttyS1). | 157 | Enables the ETRAX FS serial driver for ser1 (ttyS1). |
142 | 158 | ||
143 | choice | 159 | choice |
144 | prompt "Ser1 DMA in channel " | 160 | prompt "Ser1 default port type" |
145 | depends on ETRAX_SERIAL_PORT1 | 161 | depends on ETRAX_SERIAL_PORT1 |
146 | default ETRAX_SERIAL_PORT1_NO_DMA_IN | 162 | default ETRAX_SERIAL_PORT1_TYPE_232 |
147 | help | ||
148 | What DMA channel to use for ser1. | ||
149 | |||
150 | |||
151 | config ETRAX_SERIAL_PORT1_NO_DMA_IN | ||
152 | bool "Ser1 uses no DMA for input" | ||
153 | help | 163 | help |
154 | Do not use DMA for ser1 input. | 164 | Type of serial port. |
155 | 165 | ||
156 | config ETRAX_SERIAL_PORT1_DMA5_IN | 166 | config ETRAX_SERIAL_PORT1_TYPE_232 |
157 | bool "Ser1 uses DMA5 for input" | 167 | bool "Ser1 is a RS-232 port" |
158 | depends on ETRAX_SERIAL_PORT1 | ||
159 | help | 168 | help |
160 | Enables the DMA5 input channel for ser1 (ttyS1). | 169 | Configure serial port 1 to be a RS-232 port. |
161 | If you do not enable DMA, an interrupt for each character will be | ||
162 | used when receiving data. | ||
163 | Normally you want this on, unless you use the DMA channel for | ||
164 | something else. | ||
165 | |||
166 | endchoice | ||
167 | 170 | ||
168 | choice | 171 | config ETRAX_SERIAL_PORT1_TYPE_485HD |
169 | prompt "Ser1 DMA out channel " | 172 | bool "Ser1 is a half duplex RS-485 port" |
170 | depends on ETRAX_SERIAL_PORT1 | 173 | depends on ETRAX_RS485 |
171 | default ETRAX_SERIAL_PORT1_NO_DMA_OUT | ||
172 | help | ||
173 | What DMA channel to use for ser1. | ||
174 | |||
175 | config ETRAX_SERIAL_PORT1_NO_DMA_OUT | ||
176 | bool "Ser1 uses no DMA for output" | ||
177 | help | 174 | help |
178 | Do not use DMA for ser1 output. | 175 | Configure serial port 1 to be a half duplex (two wires) RS-485 port. |
179 | 176 | ||
180 | config ETRAX_SERIAL_PORT1_DMA4_OUT | 177 | config ETRAX_SERIAL_PORT1_TYPE_485FD |
181 | bool "Ser1 uses DMA4 for output" | 178 | bool "Ser1 is a full duplex RS-485 port" |
182 | depends on ETRAX_SERIAL_PORT1 | 179 | depends on ETRAX_RS485 |
183 | help | 180 | help |
184 | Enables the DMA4 output channel for ser1 (ttyS1). | 181 | Configure serial port 1 to be a full duplex (four wires) RS-485 port. |
185 | If you do not enable DMA, an interrupt for each character will be | ||
186 | used when transmitting data. | ||
187 | Normally you want this on, unless you use the DMA channel for | ||
188 | something else. | ||
189 | |||
190 | endchoice | 182 | endchoice |
191 | 183 | ||
192 | config ETRAX_SER1_DTR_BIT | 184 | config ETRAX_SER1_DTR_BIT |
@@ -212,52 +204,31 @@ config ETRAX_SERIAL_PORT2 | |||
212 | Enables the ETRAX FS serial driver for ser2 (ttyS2). | 204 | Enables the ETRAX FS serial driver for ser2 (ttyS2). |
213 | 205 | ||
214 | choice | 206 | choice |
215 | prompt "Ser2 DMA in channel " | 207 | prompt "Ser2 default port type" |
216 | depends on ETRAX_SERIAL_PORT2 | 208 | depends on ETRAX_SERIAL_PORT2 |
217 | default ETRAX_SERIAL_PORT2_NO_DMA_IN | 209 | default ETRAX_SERIAL_PORT2_TYPE_232 |
218 | help | 210 | help |
219 | What DMA channel to use for ser2. | 211 | What DMA channel to use for ser2 |
220 | 212 | ||
221 | 213 | config ETRAX_SERIAL_PORT2_TYPE_232 | |
222 | config ETRAX_SERIAL_PORT2_NO_DMA_IN | 214 | bool "Ser2 is a RS-232 port" |
223 | bool "Ser2 uses no DMA for input" | ||
224 | help | 215 | help |
225 | Do not use DMA for ser2 input. | 216 | Configure serial port 2 to be a RS-232 port. |
226 | 217 | ||
227 | config ETRAX_SERIAL_PORT2_DMA3_IN | 218 | config ETRAX_SERIAL_PORT2_TYPE_485HD |
228 | bool "Ser2 uses DMA3 for input" | 219 | bool "Ser2 is a half duplex RS-485 port" |
229 | depends on ETRAX_SERIAL_PORT2 | 220 | depends on ETRAX_RS485 |
230 | help | ||
231 | Enables the DMA3 input channel for ser2 (ttyS2). | ||
232 | If you do not enable DMA, an interrupt for each character will be | ||
233 | used when receiving data. | ||
234 | Normally you want to use DMA, unless you use the DMA channel for | ||
235 | something else. | ||
236 | |||
237 | endchoice | ||
238 | |||
239 | choice | ||
240 | prompt "Ser2 DMA out channel" | ||
241 | depends on ETRAX_SERIAL_PORT2 | ||
242 | default ETRAX_SERIAL_PORT2_NO_DMA_OUT | ||
243 | |||
244 | config ETRAX_SERIAL_PORT2_NO_DMA_OUT | ||
245 | bool "Ser2 uses no DMA for output" | ||
246 | help | 221 | help |
247 | Do not use DMA for ser2 output. | 222 | Configure serial port 2 to be a half duplex (two wires) RS-485 port. |
248 | 223 | ||
249 | config ETRAX_SERIAL_PORT2_DMA2_OUT | 224 | config ETRAX_SERIAL_PORT2_TYPE_485FD |
250 | bool "Ser2 uses DMA2 for output" | 225 | bool "Ser2 is a full duplex RS-485 port" |
251 | depends on ETRAX_SERIAL_PORT2 | 226 | depends on ETRAX_RS485 |
252 | help | 227 | help |
253 | Enables the DMA2 output channel for ser2 (ttyS2). | 228 | Configure serial port 2 to be a full duplex (four wires) RS-485 port. |
254 | If you do not enable DMA, an interrupt for each character will be | ||
255 | used when transmitting data. | ||
256 | Normally you want to use DMA, unless you use the DMA channel for | ||
257 | something else. | ||
258 | |||
259 | endchoice | 229 | endchoice |
260 | 230 | ||
231 | |||
261 | config ETRAX_SER2_DTR_BIT | 232 | config ETRAX_SER2_DTR_BIT |
262 | string "Ser 2 DTR bit (empty = not used)" | 233 | string "Ser 2 DTR bit (empty = not used)" |
263 | depends on ETRAX_SERIAL_PORT2 | 234 | depends on ETRAX_SERIAL_PORT2 |
@@ -281,71 +252,121 @@ config ETRAX_SERIAL_PORT3 | |||
281 | Enables the ETRAX FS serial driver for ser3 (ttyS3). | 252 | Enables the ETRAX FS serial driver for ser3 (ttyS3). |
282 | 253 | ||
283 | choice | 254 | choice |
284 | prompt "Ser3 DMA in channel " | 255 | prompt "Ser3 default port type" |
285 | depends on ETRAX_SERIAL_PORT3 | 256 | depends on ETRAX_SERIAL_PORT3 |
286 | default ETRAX_SERIAL_PORT3_NO_DMA_IN | 257 | default ETRAX_SERIAL_PORT3_TYPE_232 |
287 | help | 258 | help |
288 | What DMA channel to use for ser3. | 259 | What DMA channel to use for ser3. |
289 | 260 | ||
261 | config ETRAX_SERIAL_PORT3_TYPE_232 | ||
262 | bool "Ser3 is a RS-232 port" | ||
263 | help | ||
264 | Configure serial port 3 to be a RS-232 port. | ||
290 | 265 | ||
291 | config ETRAX_SERIAL_PORT3_NO_DMA_IN | 266 | config ETRAX_SERIAL_PORT3_TYPE_485HD |
292 | bool "Ser3 uses no DMA for input" | 267 | bool "Ser3 is a half duplex RS-485 port" |
268 | depends on ETRAX_RS485 | ||
293 | help | 269 | help |
294 | Do not use DMA for ser3 input. | 270 | Configure serial port 3 to be a half duplex (two wires) RS-485 port. |
295 | 271 | ||
296 | config ETRAX_SERIAL_PORT3_DMA9_IN | 272 | config ETRAX_SERIAL_PORT3_TYPE_485FD |
297 | bool "Ser3 uses DMA9 for input" | 273 | bool "Ser3 is a full duplex RS-485 port" |
274 | depends on ETRAX_RS485 | ||
275 | help | ||
276 | Configure serial port 3 to be a full duplex (four wires) RS-485 port. | ||
277 | endchoice | ||
278 | |||
279 | config ETRAX_SER3_DTR_BIT | ||
280 | string "Ser 3 DTR bit (empty = not used)" | ||
281 | depends on ETRAX_SERIAL_PORT3 | ||
282 | |||
283 | config ETRAX_SER3_RI_BIT | ||
284 | string "Ser 3 RI bit (empty = not used)" | ||
285 | depends on ETRAX_SERIAL_PORT3 | ||
286 | |||
287 | config ETRAX_SER3_DSR_BIT | ||
288 | string "Ser 3 DSR bit (empty = not used)" | ||
289 | depends on ETRAX_SERIAL_PORT3 | ||
290 | |||
291 | config ETRAX_SER3_CD_BIT | ||
292 | string "Ser 3 CD bit (empty = not used)" | ||
298 | depends on ETRAX_SERIAL_PORT3 | 293 | depends on ETRAX_SERIAL_PORT3 |
294 | |||
295 | config ETRAX_SERIAL_PORT4 | ||
296 | bool "Serial port 4 enabled" | ||
297 | depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3 | ||
299 | help | 298 | help |
300 | Enables the DMA9 input channel for ser3 (ttyS3). | 299 | Enables the ETRAX FS serial driver for ser4 (ttyS4). |
301 | If you do not enable DMA, an interrupt for each character will be | 300 | |
302 | used when receiving data. | 301 | choice |
303 | Normally you want to use DMA, unless you use the DMA channel for | 302 | prompt "Ser4 default port type" |
304 | something else. | 303 | depends on ETRAX_SERIAL_PORT4 |
304 | default ETRAX_SERIAL_PORT4_TYPE_232 | ||
305 | help | ||
306 | What DMA channel to use for ser4. | ||
305 | 307 | ||
308 | config ETRAX_SERIAL_PORT4_TYPE_232 | ||
309 | bool "Ser4 is a RS-232 port" | ||
310 | help | ||
311 | Configure serial port 4 to be a RS-232 port. | ||
312 | |||
313 | config ETRAX_SERIAL_PORT4_TYPE_485HD | ||
314 | bool "Ser4 is a half duplex RS-485 port" | ||
315 | depends on ETRAX_RS485 | ||
316 | help | ||
317 | Configure serial port 4 to be a half duplex (two wires) RS-485 port. | ||
318 | |||
319 | config ETRAX_SERIAL_PORT4_TYPE_485FD | ||
320 | bool "Ser4 is a full duplex RS-485 port" | ||
321 | depends on ETRAX_RS485 | ||
322 | help | ||
323 | Configure serial port 4 to be a full duplex (four wires) RS-485 port. | ||
306 | endchoice | 324 | endchoice |
307 | 325 | ||
308 | choice | 326 | choice |
309 | prompt "Ser3 DMA out channel" | 327 | prompt "Ser4 DMA in channel " |
310 | depends on ETRAX_SERIAL_PORT3 | 328 | depends on ETRAX_SERIAL_PORT4 |
311 | default ETRAX_SERIAL_PORT3_NO_DMA_OUT | 329 | default ETRAX_SERIAL_PORT4_NO_DMA_IN |
330 | help | ||
331 | What DMA channel to use for ser4. | ||
332 | |||
312 | 333 | ||
313 | config ETRAX_SERIAL_PORT3_NO_DMA_OUT | 334 | config ETRAX_SERIAL_PORT4_NO_DMA_IN |
314 | bool "Ser3 uses no DMA for output" | 335 | bool "Ser4 uses no DMA for input" |
315 | help | 336 | help |
316 | Do not use DMA for ser3 output. | 337 | Do not use DMA for ser4 input. |
317 | 338 | ||
318 | config ETRAX_SERIAL_PORT3_DMA8_OUT | 339 | config ETRAX_SERIAL_PORT4_DMA9_IN |
319 | bool "Ser3 uses DMA8 for output" | 340 | bool "Ser4 uses DMA9 for input" |
320 | depends on ETRAX_SERIAL_PORT3 | 341 | depends on ETRAX_SERIAL_PORT4 |
321 | help | 342 | help |
322 | Enables the DMA8 output channel for ser3 (ttyS3). | 343 | Enables the DMA9 input channel for ser4 (ttyS4). |
323 | If you do not enable DMA, an interrupt for each character will be | 344 | If you do not enable DMA, an interrupt for each character will be |
324 | used when transmitting data. | 345 | used when receiveing data. |
325 | Normally you want to use DMA, unless you use the DMA channel for | 346 | Normally you want to use DMA, unless you use the DMA channel for |
326 | something else. | 347 | something else. |
327 | 348 | ||
328 | endchoice | 349 | endchoice |
329 | 350 | ||
330 | config ETRAX_SER3_DTR_BIT | 351 | config ETRAX_SER4_DTR_BIT |
331 | string "Ser 3 DTR bit (empty = not used)" | 352 | string "Ser 4 DTR bit (empty = not used)" |
332 | depends on ETRAX_SERIAL_PORT3 | 353 | depends on ETRAX_SERIAL_PORT4 |
333 | 354 | ||
334 | config ETRAX_SER3_RI_BIT | 355 | config ETRAX_SER4_RI_BIT |
335 | string "Ser 3 RI bit (empty = not used)" | 356 | string "Ser 4 RI bit (empty = not used)" |
336 | depends on ETRAX_SERIAL_PORT3 | 357 | depends on ETRAX_SERIAL_PORT4 |
337 | 358 | ||
338 | config ETRAX_SER3_DSR_BIT | 359 | config ETRAX_SER4_DSR_BIT |
339 | string "Ser 3 DSR bit (empty = not used)" | 360 | string "Ser 4 DSR bit (empty = not used)" |
340 | depends on ETRAX_SERIAL_PORT3 | 361 | depends on ETRAX_SERIAL_PORT4 |
341 | 362 | ||
342 | config ETRAX_SER3_CD_BIT | 363 | config ETRAX_SER3_CD_BIT |
343 | string "Ser 3 CD bit (empty = not used)" | 364 | string "Ser 4 CD bit (empty = not used)" |
344 | depends on ETRAX_SERIAL_PORT3 | 365 | depends on ETRAX_SERIAL_PORT4 |
345 | 366 | ||
346 | config ETRAX_RS485 | 367 | config ETRAX_RS485 |
347 | bool "RS-485 support" | 368 | bool "RS-485 support" |
348 | depends on ETRAX_SERIAL | 369 | depends on ETRAXFS_SERIAL |
349 | help | 370 | help |
350 | Enables support for RS-485 serial communication. For a primer on | 371 | Enables support for RS-485 serial communication. For a primer on |
351 | RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>. | 372 | RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>. |
@@ -356,22 +377,6 @@ config ETRAX_RS485_DISABLE_RECEIVER | |||
356 | help | 377 | help |
357 | It is necessary to disable the serial receiver to avoid serial | 378 | It is necessary to disable the serial receiver to avoid serial |
358 | loopback. Not all products are able to do this in software only. | 379 | loopback. Not all products are able to do this in software only. |
359 | Axis 2400/2401 must disable receiver. | ||
360 | |||
361 | config ETRAX_AXISFLASHMAP | ||
362 | bool "Axis flash-map support" | ||
363 | depends on ETRAX_ARCH_V32 | ||
364 | select MTD | ||
365 | select MTD_CFI | ||
366 | select MTD_CFI_AMDSTD | ||
367 | select MTD_CHAR | ||
368 | select MTD_BLOCK | ||
369 | select MTD_PARTITIONS | ||
370 | select MTD_CONCAT | ||
371 | select MTD_COMPLEX_MAPPINGS | ||
372 | help | ||
373 | This option enables MTD mapping of flash devices. Needed to use | ||
374 | flash memories. If unsure, say Y. | ||
375 | 380 | ||
376 | config ETRAX_SYNCHRONOUS_SERIAL | 381 | config ETRAX_SYNCHRONOUS_SERIAL |
377 | bool "Synchronous serial-port support" | 382 | bool "Synchronous serial-port support" |
@@ -394,7 +399,7 @@ config ETRAX_SYNCHRONOUS_SERIAL0_DMA | |||
394 | 399 | ||
395 | config ETRAX_SYNCHRONOUS_SERIAL_PORT1 | 400 | config ETRAX_SYNCHRONOUS_SERIAL_PORT1 |
396 | bool "Synchronous serial port 1 enabled" | 401 | bool "Synchronous serial port 1 enabled" |
397 | depends on ETRAX_SYNCHRONOUS_SERIAL | 402 | depends on ETRAX_SYNCHRONOUS_SERIAL && ETRAXFS |
398 | help | 403 | help |
399 | Enabled synchronous serial port 1. | 404 | Enabled synchronous serial port 1. |
400 | 405 | ||
@@ -405,6 +410,31 @@ config ETRAX_SYNCHRONOUS_SERIAL1_DMA | |||
405 | A synchronous serial port can run in manual or DMA mode. | 410 | A synchronous serial port can run in manual or DMA mode. |
406 | Selecting this option will make it run in DMA mode. | 411 | Selecting this option will make it run in DMA mode. |
407 | 412 | ||
413 | config ETRAX_AXISFLASHMAP | ||
414 | bool "Axis flash-map support" | ||
415 | depends on ETRAX_ARCH_V32 | ||
416 | select MTD | ||
417 | select MTD_CFI | ||
418 | select MTD_CFI_AMDSTD | ||
419 | select MTD_JEDECPROBE | ||
420 | select MTD_CHAR | ||
421 | select MTD_BLOCK | ||
422 | select MTD_PARTITIONS | ||
423 | select MTD_CONCAT | ||
424 | select MTD_COMPLEX_MAPPINGS | ||
425 | help | ||
426 | This option enables MTD mapping of flash devices. Needed to use | ||
427 | flash memories. If unsure, say Y. | ||
428 | |||
429 | config ETRAX_AXISFLASHMAP_MTD0WHOLE | ||
430 | bool "MTD0 is whole boot flash device" | ||
431 | depends on ETRAX_AXISFLASHMAP | ||
432 | default N | ||
433 | help | ||
434 | When this option is not set, mtd0 refers to the first partition | ||
435 | on the boot flash device. When set, mtd0 refers to the whole | ||
436 | device, with mtd1 referring to the first partition etc. | ||
437 | |||
408 | config ETRAX_PTABLE_SECTOR | 438 | config ETRAX_PTABLE_SECTOR |
409 | int "Byte-offset of partition table sector" | 439 | int "Byte-offset of partition table sector" |
410 | depends on ETRAX_AXISFLASHMAP | 440 | depends on ETRAX_AXISFLASHMAP |
@@ -425,42 +455,32 @@ config ETRAX_NANDFLASH | |||
425 | This option enables MTD mapping of NAND flash devices. Needed to use | 455 | This option enables MTD mapping of NAND flash devices. Needed to use |
426 | NAND flash memories. If unsure, say Y. | 456 | NAND flash memories. If unsure, say Y. |
427 | 457 | ||
458 | config ETRAX_NANDBOOT | ||
459 | bool "Boot from NAND flash" | ||
460 | depends on ETRAX_NANDFLASH | ||
461 | help | ||
462 | This options enables booting from NAND flash devices. | ||
463 | Say Y if your boot code, kernel and root file system is in | ||
464 | NAND flash. Say N if they are in NOR flash. | ||
465 | |||
428 | config ETRAX_I2C | 466 | config ETRAX_I2C |
429 | bool "I2C driver" | 467 | bool "I2C driver" |
430 | depends on ETRAX_ARCH_V32 | 468 | depends on ETRAX_ARCH_V32 |
431 | help | 469 | help |
432 | This option enabled the I2C driver used by e.g. the RTC driver. | 470 | This option enables the I2C driver used by e.g. the RTC driver. |
433 | 471 | ||
434 | config ETRAX_I2C_DATA_PORT | 472 | config ETRAX_V32_I2C_DATA_PORT |
435 | string "I2C data pin" | 473 | string "I2C data pin" |
436 | depends on ETRAX_I2C | 474 | depends on ETRAX_I2C |
437 | help | 475 | help |
438 | The pin to use for I2C data. | 476 | The pin to use for I2C data. |
439 | 477 | ||
440 | config ETRAX_I2C_CLK_PORT | 478 | config ETRAX_V32_I2C_CLK_PORT |
441 | string "I2C clock pin" | 479 | string "I2C clock pin" |
442 | depends on ETRAX_I2C | 480 | depends on ETRAX_I2C |
443 | help | 481 | help |
444 | The pin to use for I2C clock. | 482 | The pin to use for I2C clock. |
445 | 483 | ||
446 | config ETRAX_RTC | ||
447 | bool "Real Time Clock support" | ||
448 | depends on ETRAX_ARCH_V32 | ||
449 | help | ||
450 | Enabled RTC support. | ||
451 | |||
452 | choice | ||
453 | prompt "RTC chip" | ||
454 | depends on ETRAX_RTC | ||
455 | default ETRAX_PCF8563 | ||
456 | |||
457 | config ETRAX_PCF8563 | ||
458 | bool "PCF8563" | ||
459 | help | ||
460 | Philips PCF8563 RTC | ||
461 | |||
462 | endchoice | ||
463 | |||
464 | config ETRAX_GPIO | 484 | config ETRAX_GPIO |
465 | bool "GPIO support" | 485 | bool "GPIO support" |
466 | depends on ETRAX_ARCH_V32 | 486 | depends on ETRAX_ARCH_V32 |
@@ -476,33 +496,36 @@ config ETRAX_GPIO | |||
476 | Remember that you need to setup the port directions appropriately in | 496 | Remember that you need to setup the port directions appropriately in |
477 | the General configuration. | 497 | the General configuration. |
478 | 498 | ||
479 | config ETRAX_PA_BUTTON_BITMASK | 499 | config ETRAX_VIRTUAL_GPIO |
480 | hex "PA-buttons bitmask" | 500 | bool "Virtual GPIO support" |
481 | depends on ETRAX_GPIO | 501 | depends on ETRAX_GPIO |
482 | default "0x02" | ||
483 | help | 502 | help |
484 | This is a bitmask (8 bits) with information about what bits on PA | 503 | Enables the virtual Etrax general port device (major 120, minor 6). |
485 | that are used for buttons. | 504 | It uses an I/O expander for the I2C-bus. |
486 | Most products has a so called TEST button on PA1, if that is true | 505 | |
487 | use 0x02 here. | 506 | config ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN |
488 | Use 00 if there are no buttons on PA. | 507 | int "Virtual GPIO interrupt pin on PA pin" |
489 | If the bitmask is <> 00 a button driver will be included in the gpio | 508 | range 0 7 |
490 | driver. ETRAX general I/O support must be enabled. | 509 | depends on ETRAX_VIRTUAL_GPIO |
510 | help | ||
511 | The pin to use on PA for virtual gpio interrupt. | ||
491 | 512 | ||
492 | config ETRAX_PA_CHANGEABLE_DIR | 513 | config ETRAX_PA_CHANGEABLE_DIR |
493 | hex "PA user changeable dir mask" | 514 | hex "PA user changeable dir mask" |
494 | depends on ETRAX_GPIO | 515 | depends on ETRAX_GPIO |
495 | default "0x00" | 516 | default "0x00" if ETRAXFS |
517 | default "0x00000000" if !ETRAXFS | ||
496 | help | 518 | help |
497 | This is a bitmask (8 bits) with information of what bits in PA that a | 519 | This is a bitmask (8 bits) with information of what bits in PA that a |
498 | user can change direction on using ioctl's. | 520 | user can change direction on using ioctl's. |
499 | Bit set = changeable. | 521 | Bit set = changeable. |
500 | You probably want 0x00 here, but it depends on your hardware. | 522 | You probably want 0 here, but it depends on your hardware. |
501 | 523 | ||
502 | config ETRAX_PA_CHANGEABLE_BITS | 524 | config ETRAX_PA_CHANGEABLE_BITS |
503 | hex "PA user changeable bits mask" | 525 | hex "PA user changeable bits mask" |
504 | depends on ETRAX_GPIO | 526 | depends on ETRAX_GPIO |
505 | default "0x00" | 527 | default "0x00" if ETRAXFS |
528 | default "0x00000000" if !ETRAXFS | ||
506 | help | 529 | help |
507 | This is a bitmask (8 bits) with information of what bits in PA | 530 | This is a bitmask (8 bits) with information of what bits in PA |
508 | that a user can change the value on using ioctl's. | 531 | that a user can change the value on using ioctl's. |
@@ -511,17 +534,19 @@ config ETRAX_PA_CHANGEABLE_BITS | |||
511 | config ETRAX_PB_CHANGEABLE_DIR | 534 | config ETRAX_PB_CHANGEABLE_DIR |
512 | hex "PB user changeable dir mask" | 535 | hex "PB user changeable dir mask" |
513 | depends on ETRAX_GPIO | 536 | depends on ETRAX_GPIO |
514 | default "0x00000" | 537 | default "0x00000" if ETRAXFS |
538 | default "0x00000000" if !ETRAXFS | ||
515 | help | 539 | help |
516 | This is a bitmask (18 bits) with information of what bits in PB | 540 | This is a bitmask (18 bits) with information of what bits in PB |
517 | that a user can change direction on using ioctl's. | 541 | that a user can change direction on using ioctl's. |
518 | Bit set = changeable. | 542 | Bit set = changeable. |
519 | You probably want 0x00000 here, but it depends on your hardware. | 543 | You probably want 0 here, but it depends on your hardware. |
520 | 544 | ||
521 | config ETRAX_PB_CHANGEABLE_BITS | 545 | config ETRAX_PB_CHANGEABLE_BITS |
522 | hex "PB user changeable bits mask" | 546 | hex "PB user changeable bits mask" |
523 | depends on ETRAX_GPIO | 547 | depends on ETRAX_GPIO |
524 | default "0x00000" | 548 | default "0x00000" if ETRAXFS |
549 | default "0x00000000" if !ETRAXFS | ||
525 | help | 550 | help |
526 | This is a bitmask (18 bits) with information of what bits in PB | 551 | This is a bitmask (18 bits) with information of what bits in PB |
527 | that a user can change the value on using ioctl's. | 552 | that a user can change the value on using ioctl's. |
@@ -530,17 +555,19 @@ config ETRAX_PB_CHANGEABLE_BITS | |||
530 | config ETRAX_PC_CHANGEABLE_DIR | 555 | config ETRAX_PC_CHANGEABLE_DIR |
531 | hex "PC user changeable dir mask" | 556 | hex "PC user changeable dir mask" |
532 | depends on ETRAX_GPIO | 557 | depends on ETRAX_GPIO |
533 | default "0x00000" | 558 | default "0x00000" if ETRAXFS |
559 | default "0x00000000" if !ETRAXFS | ||
534 | help | 560 | help |
535 | This is a bitmask (18 bits) with information of what bits in PC | 561 | This is a bitmask (18 bits) with information of what bits in PC |
536 | that a user can change direction on using ioctl's. | 562 | that a user can change direction on using ioctl's. |
537 | Bit set = changeable. | 563 | Bit set = changeable. |
538 | You probably want 0x00000 here, but it depends on your hardware. | 564 | You probably want 0 here, but it depends on your hardware. |
539 | 565 | ||
540 | config ETRAX_PC_CHANGEABLE_BITS | 566 | config ETRAX_PC_CHANGEABLE_BITS |
541 | hex "PC user changeable bits mask" | 567 | hex "PC user changeable bits mask" |
542 | depends on ETRAX_GPIO | 568 | depends on ETRAX_GPIO |
543 | default "0x00000" | 569 | default "0x00000" if ETRAXFS |
570 | default "0x00000000" if ETRAXFS | ||
544 | help | 571 | help |
545 | This is a bitmask (18 bits) with information of what bits in PC | 572 | This is a bitmask (18 bits) with information of what bits in PC |
546 | that a user can change the value on using ioctl's. | 573 | that a user can change the value on using ioctl's. |
@@ -548,7 +575,7 @@ config ETRAX_PC_CHANGEABLE_BITS | |||
548 | 575 | ||
549 | config ETRAX_PD_CHANGEABLE_DIR | 576 | config ETRAX_PD_CHANGEABLE_DIR |
550 | hex "PD user changeable dir mask" | 577 | hex "PD user changeable dir mask" |
551 | depends on ETRAX_GPIO | 578 | depends on ETRAX_GPIO && ETRAXFS |
552 | default "0x00000" | 579 | default "0x00000" |
553 | help | 580 | help |
554 | This is a bitmask (18 bits) with information of what bits in PD | 581 | This is a bitmask (18 bits) with information of what bits in PD |
@@ -558,7 +585,7 @@ config ETRAX_PD_CHANGEABLE_DIR | |||
558 | 585 | ||
559 | config ETRAX_PD_CHANGEABLE_BITS | 586 | config ETRAX_PD_CHANGEABLE_BITS |
560 | hex "PD user changeable bits mask" | 587 | hex "PD user changeable bits mask" |
561 | depends on ETRAX_GPIO | 588 | depends on ETRAX_GPIO && ETRAXFS |
562 | default "0x00000" | 589 | default "0x00000" |
563 | help | 590 | help |
564 | This is a bitmask (18 bits) with information of what bits in PD | 591 | This is a bitmask (18 bits) with information of what bits in PD |
@@ -567,7 +594,7 @@ config ETRAX_PD_CHANGEABLE_BITS | |||
567 | 594 | ||
568 | config ETRAX_PE_CHANGEABLE_DIR | 595 | config ETRAX_PE_CHANGEABLE_DIR |
569 | hex "PE user changeable dir mask" | 596 | hex "PE user changeable dir mask" |
570 | depends on ETRAX_GPIO | 597 | depends on ETRAX_GPIO && ETRAXFS |
571 | default "0x00000" | 598 | default "0x00000" |
572 | help | 599 | help |
573 | This is a bitmask (18 bits) with information of what bits in PE | 600 | This is a bitmask (18 bits) with information of what bits in PE |
@@ -577,20 +604,36 @@ config ETRAX_PE_CHANGEABLE_DIR | |||
577 | 604 | ||
578 | config ETRAX_PE_CHANGEABLE_BITS | 605 | config ETRAX_PE_CHANGEABLE_BITS |
579 | hex "PE user changeable bits mask" | 606 | hex "PE user changeable bits mask" |
580 | depends on ETRAX_GPIO | 607 | depends on ETRAX_GPIO && ETRAXFS |
581 | default "0x00000" | 608 | default "0x00000" |
582 | help | 609 | help |
583 | This is a bitmask (18 bits) with information of what bits in PE | 610 | This is a bitmask (18 bits) with information of what bits in PE |
584 | that a user can change the value on using ioctl's. | 611 | that a user can change the value on using ioctl's. |
585 | Bit set = changeable. | 612 | Bit set = changeable. |
586 | 613 | ||
614 | config ETRAX_PV_CHANGEABLE_DIR | ||
615 | hex "PV user changeable dir mask" | ||
616 | depends on ETRAX_VIRTUAL_GPIO | ||
617 | default "0x0000" | ||
618 | help | ||
619 | This is a bitmask (16 bits) with information of what bits in PV | ||
620 | that a user can change direction on using ioctl's. | ||
621 | Bit set = changeable. | ||
622 | You probably want 0x0000 here, but it depends on your hardware. | ||
623 | |||
624 | config ETRAX_PV_CHANGEABLE_BITS | ||
625 | hex "PV user changeable bits mask" | ||
626 | depends on ETRAX_VIRTUAL_GPIO | ||
627 | default "0x0000" | ||
628 | help | ||
629 | This is a bitmask (16 bits) with information of what bits in PV | ||
630 | that a user can change the value on using ioctl's. | ||
631 | Bit set = changeable. | ||
632 | |||
587 | config ETRAX_CARDBUS | 633 | config ETRAX_CARDBUS |
588 | bool "Cardbus support" | 634 | bool "Cardbus support" |
589 | depends on ETRAX_ARCH_V32 | 635 | depends on ETRAX_ARCH_V32 |
590 | select PCCARD | ||
591 | select CARDBUS | ||
592 | select HOTPLUG | 636 | select HOTPLUG |
593 | select PCCARD_NONSTATIC | ||
594 | help | 637 | help |
595 | Enabled the ETRAX Cardbus driver. | 638 | Enabled the ETRAX Cardbus driver. |
596 | 639 | ||
@@ -613,4 +656,202 @@ config ETRAX_STREAMCOPROC | |||
613 | This option enables a driver for the stream co-processor | 656 | This option enables a driver for the stream co-processor |
614 | for cryptographic operations. | 657 | for cryptographic operations. |
615 | 658 | ||
659 | source drivers/mmc/Kconfig | ||
660 | |||
661 | config ETRAX_MMC_IOP | ||
662 | tristate "MMC/SD host driver using IO-processor" | ||
663 | depends on ETRAX_ARCH_V32 && MMC | ||
664 | help | ||
665 | This option enables the SD/MMC host controller interface. | ||
666 | The host controller is implemented using the built in | ||
667 | IO-Processor. Only the SPU is used in this implementation. | ||
668 | |||
669 | config ETRAX_SPI_MMC | ||
670 | # Make this one of several "choices" (possible simultaneously but | ||
671 | # suggested uniquely) when an IOP driver emerges for "real" MMC/SD | ||
672 | # protocol support. | ||
673 | tristate | ||
674 | depends on !ETRAX_MMC_IOP | ||
675 | default MMC | ||
676 | select SPI | ||
677 | select MMC_SPI | ||
678 | select ETRAX_SPI_MMC_BOARD | ||
679 | |||
680 | # For the parts that can't be a module (due to restrictions in | ||
681 | # framework elsewhere). | ||
682 | config ETRAX_SPI_MMC_BOARD | ||
683 | boolean | ||
684 | default n | ||
685 | |||
686 | # While the board info is MMC_SPI only, the drivers are written to be | ||
687 | # independent of MMC_SPI, so we'll keep SPI non-dependent on the | ||
688 | # MMC_SPI config choices (well, except for a single depends-on-line | ||
689 | # for the board-info file until a separate non-MMC SPI board file | ||
690 | # emerges). | ||
691 | # FIXME: When that happens, we'll need to be able to ask for and | ||
692 | # configure non-MMC SPI ports together with MMC_SPI ports (if multiple | ||
693 | # SPI ports are enabled). | ||
694 | |||
695 | config SPI_ETRAX_SSER | ||
696 | tristate | ||
697 | depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL | ||
698 | select SPI_BITBANG | ||
699 | help | ||
700 | This enables using an synchronous serial (sser) port as a | ||
701 | SPI master controller on Axis ETRAX FS and later. The | ||
702 | driver can be configured to use any sser port. | ||
703 | |||
704 | config SPI_ETRAX_GPIO | ||
705 | tristate | ||
706 | depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL | ||
707 | select SPI_BITBANG | ||
708 | help | ||
709 | This enables using GPIO pins port as a SPI master controller | ||
710 | on Axis ETRAX FS and later. The driver can be configured to | ||
711 | use any GPIO pins. | ||
712 | |||
713 | config ETRAX_SPI_SSER0 | ||
714 | tristate "SPI using synchronous serial port 0 (sser0)" | ||
715 | depends on ETRAX_SPI_MMC | ||
716 | default m if MMC_SPI=m | ||
717 | default y if MMC_SPI=y | ||
718 | default y if MMC_SPI=n | ||
719 | select SPI_ETRAX_SSER | ||
720 | help | ||
721 | Say Y for an MMC/SD socket connected to synchronous serial port 0, | ||
722 | or for devices using the SPI protocol on that port. Say m if you | ||
723 | want to build it as a module, which will be named spi_crisv32_sser. | ||
724 | (You need to select MMC separately.) | ||
725 | |||
726 | config ETRAX_SPI_SSER0_DMA | ||
727 | bool "DMA for SPI on sser0 enabled" | ||
728 | depends on ETRAX_SPI_SSER0 | ||
729 | depends on !ETRAX_SERIAL_PORT1_DMA4_OUT && !ETRAX_SERIAL_PORT1_DMA5_IN | ||
730 | default y | ||
731 | help | ||
732 | Say Y if using DMA (dma4/dma5) for SPI on synchronous serial port 0. | ||
733 | |||
734 | config ETRAX_SPI_MMC_CD_SSER0_PIN | ||
735 | string "MMC/SD card detect pin for SPI on sser0" | ||
736 | depends on ETRAX_SPI_SSER0 && MMC_SPI | ||
737 | default "pd11" | ||
738 | help | ||
739 | The pin to use for SD/MMC card detect. This pin should be pulled up | ||
740 | and grounded when a card is present. If defined as " " (space), no | ||
741 | pin is selected. A card must then always be inserted for proper | ||
742 | action. | ||
743 | |||
744 | config ETRAX_SPI_MMC_WP_SSER0_PIN | ||
745 | string "MMC/SD card write-protect pin for SPI on sser0" | ||
746 | depends on ETRAX_SPI_SSER0 && MMC_SPI | ||
747 | default "pd10" | ||
748 | help | ||
749 | The pin to use for the SD/MMC write-protect signal for a memory | ||
750 | card. If defined as " " (space), the card is considered writable. | ||
751 | |||
752 | config ETRAX_SPI_SSER1 | ||
753 | tristate "SPI using synchronous serial port 1 (sser1)" | ||
754 | depends on ETRAX_SPI_MMC | ||
755 | default m if MMC_SPI=m && ETRAX_SPI_SSER0=n | ||
756 | default y if MMC_SPI=y && ETRAX_SPI_SSER0=n | ||
757 | default y if MMC_SPI=n && ETRAX_SPI_SSER0=n | ||
758 | select SPI_ETRAX_SSER | ||
759 | help | ||
760 | Say Y for an MMC/SD socket connected to synchronous serial port 1, | ||
761 | or for devices using the SPI protocol on that port. Say m if you | ||
762 | want to build it as a module, which will be named spi_crisv32_sser. | ||
763 | (You need to select MMC separately.) | ||
764 | |||
765 | config ETRAX_SPI_SSER1_DMA | ||
766 | bool "DMA for SPI on sser1 enabled" | ||
767 | depends on ETRAX_SPI_SSER1 && !ETRAX_ETHERNET_IFACE1 | ||
768 | depends on !ETRAX_SERIAL_PORT0_DMA6_OUT && !ETRAX_SERIAL_PORT0_DMA7_IN | ||
769 | default y | ||
770 | help | ||
771 | Say Y if using DMA (dma6/dma7) for SPI on synchronous serial port 1. | ||
772 | |||
773 | config ETRAX_SPI_MMC_CD_SSER1_PIN | ||
774 | string "MMC/SD card detect pin for SPI on sser1" | ||
775 | depends on ETRAX_SPI_SSER1 && MMC_SPI | ||
776 | default "pd12" | ||
777 | help | ||
778 | The pin to use for SD/MMC card detect. This pin should be pulled up | ||
779 | and grounded when a card is present. If defined as " " (space), no | ||
780 | pin is selected. A card must then always be inserted for proper | ||
781 | action. | ||
782 | |||
783 | config ETRAX_SPI_MMC_WP_SSER1_PIN | ||
784 | string "MMC/SD card write-protect pin for SPI on sser1" | ||
785 | depends on ETRAX_SPI_SSER1 && MMC_SPI | ||
786 | default "pd9" | ||
787 | help | ||
788 | The pin to use for the SD/MMC write-protect signal for a memory | ||
789 | card. If defined as " " (space), the card is considered writable. | ||
790 | |||
791 | config ETRAX_SPI_GPIO | ||
792 | tristate "Bitbanged SPI using gpio pins" | ||
793 | depends on ETRAX_SPI_MMC | ||
794 | select SPI_ETRAX_GPIO | ||
795 | default m if MMC_SPI=m && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n | ||
796 | default y if MMC_SPI=y && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n | ||
797 | default y if MMC_SPI=n && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n | ||
798 | help | ||
799 | Say Y for an MMC/SD socket connected to general I/O pins (but not | ||
800 | a complete synchronous serial ports), or for devices using the SPI | ||
801 | protocol on general I/O pins. Slow and slows down the system. | ||
802 | Say m to build it as a module, which will be called spi_crisv32_gpio. | ||
803 | (You need to select MMC separately.) | ||
804 | |||
805 | # The default match that of sser0, only because that's how it was tested. | ||
806 | config ETRAX_SPI_CS_PIN | ||
807 | string "SPI chip select pin" | ||
808 | depends on ETRAX_SPI_GPIO | ||
809 | default "pc3" | ||
810 | help | ||
811 | The pin to use for SPI chip select. | ||
812 | |||
813 | config ETRAX_SPI_CLK_PIN | ||
814 | string "SPI clock pin" | ||
815 | depends on ETRAX_SPI_GPIO | ||
816 | default "pc1" | ||
817 | help | ||
818 | The pin to use for the SPI clock. | ||
819 | |||
820 | config ETRAX_SPI_DATAIN_PIN | ||
821 | string "SPI MISO (data in) pin" | ||
822 | depends on ETRAX_SPI_GPIO | ||
823 | default "pc16" | ||
824 | help | ||
825 | The pin to use for SPI data in from the device. | ||
826 | |||
827 | config ETRAX_SPI_DATAOUT_PIN | ||
828 | string "SPI MOSI (data out) pin" | ||
829 | depends on ETRAX_SPI_GPIO | ||
830 | default "pc0" | ||
831 | help | ||
832 | The pin to use for SPI data out to the device. | ||
833 | |||
834 | config ETRAX_SPI_MMC_CD_GPIO_PIN | ||
835 | string "MMC/SD card detect pin for SPI using gpio (space for none)" | ||
836 | depends on ETRAX_SPI_GPIO && MMC_SPI | ||
837 | default "pd11" | ||
838 | help | ||
839 | The pin to use for SD/MMC card detect. This pin should be pulled up | ||
840 | and grounded when a card is present. If defined as " " (space), no | ||
841 | pin is selected. A card must then always be inserted for proper | ||
842 | action. | ||
843 | |||
844 | config ETRAX_SPI_MMC_WP_GPIO_PIN | ||
845 | string "MMC/SD card write-protect pin for SPI using gpio (space for none)" | ||
846 | depends on ETRAX_SPI_GPIO && MMC_SPI | ||
847 | default "pd10" | ||
848 | help | ||
849 | The pin to use for the SD/MMC write-protect signal for a memory | ||
850 | card. If defined as " " (space), the card is considered writable. | ||
851 | |||
852 | # Avoid choices causing non-working configs by conditionalizing the inclusion. | ||
853 | if ETRAX_SPI_MMC | ||
854 | source drivers/spi/Kconfig | ||
855 | endif | ||
856 | |||
616 | endif | 857 | endif |
diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile index a359cd20ae75..e8c02437edaf 100644 --- a/arch/cris/arch-v32/drivers/Makefile +++ b/arch/cris/arch-v32/drivers/Makefile | |||
@@ -4,10 +4,11 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_ETRAX_STREAMCOPROC) += cryptocop.o | 5 | obj-$(CONFIG_ETRAX_STREAMCOPROC) += cryptocop.o |
6 | obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o | 6 | obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o |
7 | obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o | 7 | obj-$(CONFIG_ETRAXFS) += mach-fs/ |
8 | obj-$(CONFIG_ETRAX_GPIO) += gpio.o | 8 | obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/ |
9 | obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o | 9 | obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o |
10 | obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o | 10 | obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o |
11 | obj-$(CONFIG_ETRAX_I2C) += i2c.o | 11 | obj-$(CONFIG_ETRAX_I2C) += i2c.o |
12 | obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o | 12 | obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o |
13 | obj-$(CONFIG_PCI) += pci/ | 13 | obj-$(CONFIG_PCI) += pci/ |
14 | obj-$(CONFIG_ETRAX_SPI_MMC_BOARD) += board_mmcspi.o | ||
diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index c5ff95e18269..51e1e85df96d 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Physical mapping layer for MTD using the Axis partitiontable format | 2 | * Physical mapping layer for MTD using the Axis partitiontable format |
3 | * | 3 | * |
4 | * Copyright (c) 2001, 2002, 2003 Axis Communications AB | 4 | * Copyright (c) 2001-2007 Axis Communications AB |
5 | * | 5 | * |
6 | * This file is under the GPL. | 6 | * This file is under the GPL. |
7 | * | 7 | * |
@@ -10,9 +10,6 @@ | |||
10 | * tells us what other partitions to define. If there isn't, we use a default | 10 | * tells us what other partitions to define. If there isn't, we use a default |
11 | * partition split defined below. | 11 | * partition split defined below. |
12 | * | 12 | * |
13 | * Copy of os/lx25/arch/cris/arch-v10/drivers/axisflashmap.c 1.5 | ||
14 | * with minor changes. | ||
15 | * | ||
16 | */ | 13 | */ |
17 | 14 | ||
18 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -27,7 +24,8 @@ | |||
27 | #include <linux/mtd/mtdram.h> | 24 | #include <linux/mtd/mtdram.h> |
28 | #include <linux/mtd/partitions.h> | 25 | #include <linux/mtd/partitions.h> |
29 | 26 | ||
30 | #include <asm/arch/hwregs/config_defs.h> | 27 | #include <linux/cramfs_fs.h> |
28 | |||
31 | #include <asm/axisflashmap.h> | 29 | #include <asm/axisflashmap.h> |
32 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
33 | 31 | ||
@@ -37,16 +35,24 @@ | |||
37 | #define FLASH_UNCACHED_ADDR KSEG_E | 35 | #define FLASH_UNCACHED_ADDR KSEG_E |
38 | #define FLASH_CACHED_ADDR KSEG_F | 36 | #define FLASH_CACHED_ADDR KSEG_F |
39 | 37 | ||
38 | #define PAGESIZE (512) | ||
39 | |||
40 | #if CONFIG_ETRAX_FLASH_BUSWIDTH==1 | 40 | #if CONFIG_ETRAX_FLASH_BUSWIDTH==1 |
41 | #define flash_data __u8 | 41 | #define flash_data __u8 |
42 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 | 42 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 |
43 | #define flash_data __u16 | 43 | #define flash_data __u16 |
44 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 | 44 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 |
45 | #define flash_data __u16 | 45 | #define flash_data __u32 |
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | /* From head.S */ | 48 | /* From head.S */ |
49 | extern unsigned long romfs_start, romfs_length, romfs_in_flash; | 49 | extern unsigned long romfs_in_flash; /* 1 when romfs_start, _length in flash */ |
50 | extern unsigned long romfs_start, romfs_length; | ||
51 | extern unsigned long nand_boot; /* 1 when booted from nand flash */ | ||
52 | |||
53 | struct partition_name { | ||
54 | char name[6]; | ||
55 | }; | ||
50 | 56 | ||
51 | /* The master mtd for the entire flash. */ | 57 | /* The master mtd for the entire flash. */ |
52 | struct mtd_info* axisflash_mtd = NULL; | 58 | struct mtd_info* axisflash_mtd = NULL; |
@@ -112,32 +118,20 @@ static struct map_info map_cse1 = { | |||
112 | .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE | 118 | .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE |
113 | }; | 119 | }; |
114 | 120 | ||
115 | /* If no partition-table was found, we use this default-set. */ | 121 | #define MAX_PARTITIONS 7 |
116 | #define MAX_PARTITIONS 7 | 122 | #ifdef CONFIG_ETRAX_NANDBOOT |
117 | #define NUM_DEFAULT_PARTITIONS 3 | 123 | #define NUM_DEFAULT_PARTITIONS 4 |
124 | #define DEFAULT_ROOTFS_PARTITION_NO 2 | ||
125 | #define DEFAULT_MEDIA_SIZE 0x2000000 /* 32 megs */ | ||
126 | #else | ||
127 | #define NUM_DEFAULT_PARTITIONS 3 | ||
128 | #define DEFAULT_ROOTFS_PARTITION_NO (-1) | ||
129 | #define DEFAULT_MEDIA_SIZE 0x800000 /* 8 megs */ | ||
130 | #endif | ||
118 | 131 | ||
119 | /* | 132 | #if (MAX_PARTITIONS < NUM_DEFAULT_PARTITIONS) |
120 | * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the | 133 | #error MAX_PARTITIONS must be >= than NUM_DEFAULT_PARTITIONS |
121 | * size of one flash block and "filesystem"-partition needs 5 blocks to be able | 134 | #endif |
122 | * to use JFFS. | ||
123 | */ | ||
124 | static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { | ||
125 | { | ||
126 | .name = "boot firmware", | ||
127 | .size = CONFIG_ETRAX_PTABLE_SECTOR, | ||
128 | .offset = 0 | ||
129 | }, | ||
130 | { | ||
131 | .name = "kernel", | ||
132 | .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), | ||
133 | .offset = CONFIG_ETRAX_PTABLE_SECTOR | ||
134 | }, | ||
135 | { | ||
136 | .name = "filesystem", | ||
137 | .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, | ||
138 | .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) | ||
139 | } | ||
140 | }; | ||
141 | 135 | ||
142 | /* Initialize the ones normally used. */ | 136 | /* Initialize the ones normally used. */ |
143 | static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { | 137 | static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { |
@@ -178,6 +172,56 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { | |||
178 | }, | 172 | }, |
179 | }; | 173 | }; |
180 | 174 | ||
175 | |||
176 | /* If no partition-table was found, we use this default-set. | ||
177 | * Default flash size is 8MB (NOR). CONFIG_ETRAX_PTABLE_SECTOR is most | ||
178 | * likely the size of one flash block and "filesystem"-partition needs | ||
179 | * to be >=5 blocks to be able to use JFFS. | ||
180 | */ | ||
181 | static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { | ||
182 | { | ||
183 | .name = "boot firmware", | ||
184 | .size = CONFIG_ETRAX_PTABLE_SECTOR, | ||
185 | .offset = 0 | ||
186 | }, | ||
187 | { | ||
188 | .name = "kernel", | ||
189 | .size = 10 * CONFIG_ETRAX_PTABLE_SECTOR, | ||
190 | .offset = CONFIG_ETRAX_PTABLE_SECTOR | ||
191 | }, | ||
192 | #define FILESYSTEM_SECTOR (11 * CONFIG_ETRAX_PTABLE_SECTOR) | ||
193 | #ifdef CONFIG_ETRAX_NANDBOOT | ||
194 | { | ||
195 | .name = "rootfs", | ||
196 | .size = 10 * CONFIG_ETRAX_PTABLE_SECTOR, | ||
197 | .offset = FILESYSTEM_SECTOR | ||
198 | }, | ||
199 | #undef FILESYSTEM_SECTOR | ||
200 | #define FILESYSTEM_SECTOR (21 * CONFIG_ETRAX_PTABLE_SECTOR) | ||
201 | #endif | ||
202 | { | ||
203 | .name = "rwfs", | ||
204 | .size = DEFAULT_MEDIA_SIZE - FILESYSTEM_SECTOR, | ||
205 | .offset = FILESYSTEM_SECTOR | ||
206 | } | ||
207 | }; | ||
208 | |||
209 | #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE | ||
210 | /* Main flash device */ | ||
211 | static struct mtd_partition main_partition = { | ||
212 | .name = "main", | ||
213 | .size = 0, | ||
214 | .offset = 0 | ||
215 | }; | ||
216 | #endif | ||
217 | |||
218 | /* Auxilliary partition if we find another flash */ | ||
219 | static struct mtd_partition aux_partition = { | ||
220 | .name = "aux", | ||
221 | .size = 0, | ||
222 | .offset = 0 | ||
223 | }; | ||
224 | |||
181 | /* | 225 | /* |
182 | * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash | 226 | * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash |
183 | * chips in that order (because the amd_flash-driver is faster). | 227 | * chips in that order (because the amd_flash-driver is faster). |
@@ -191,7 +235,7 @@ static struct mtd_info *probe_cs(struct map_info *map_cs) | |||
191 | map_cs->name, map_cs->size, map_cs->map_priv_1); | 235 | map_cs->name, map_cs->size, map_cs->map_priv_1); |
192 | 236 | ||
193 | #ifdef CONFIG_MTD_CFI | 237 | #ifdef CONFIG_MTD_CFI |
194 | mtd_cs = do_map_probe("cfi_probe", map_cs); | 238 | mtd_cs = do_map_probe("cfi_probe", map_cs); |
195 | #endif | 239 | #endif |
196 | #ifdef CONFIG_MTD_JEDECPROBE | 240 | #ifdef CONFIG_MTD_JEDECPROBE |
197 | if (!mtd_cs) | 241 | if (!mtd_cs) |
@@ -204,7 +248,7 @@ static struct mtd_info *probe_cs(struct map_info *map_cs) | |||
204 | /* | 248 | /* |
205 | * Probe each chip select individually for flash chips. If there are chips on | 249 | * Probe each chip select individually for flash chips. If there are chips on |
206 | * both cse0 and cse1, the mtd_info structs will be concatenated to one struct | 250 | * both cse0 and cse1, the mtd_info structs will be concatenated to one struct |
207 | * so that MTD partitions can cross chip boundaries. | 251 | * so that MTD partitions can cross chip boundries. |
208 | * | 252 | * |
209 | * The only known restriction to how you can mount your chips is that each | 253 | * The only known restriction to how you can mount your chips is that each |
210 | * chip select must hold similar flash chips. But you need external hardware | 254 | * chip select must hold similar flash chips. But you need external hardware |
@@ -216,9 +260,8 @@ static struct mtd_info *flash_probe(void) | |||
216 | { | 260 | { |
217 | struct mtd_info *mtd_cse0; | 261 | struct mtd_info *mtd_cse0; |
218 | struct mtd_info *mtd_cse1; | 262 | struct mtd_info *mtd_cse1; |
219 | struct mtd_info *mtd_nand = NULL; | ||
220 | struct mtd_info *mtd_total; | 263 | struct mtd_info *mtd_total; |
221 | struct mtd_info *mtds[3]; | 264 | struct mtd_info *mtds[2]; |
222 | int count = 0; | 265 | int count = 0; |
223 | 266 | ||
224 | if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL) | 267 | if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL) |
@@ -226,12 +269,7 @@ static struct mtd_info *flash_probe(void) | |||
226 | if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL) | 269 | if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL) |
227 | mtds[count++] = mtd_cse1; | 270 | mtds[count++] = mtd_cse1; |
228 | 271 | ||
229 | #ifdef CONFIG_ETRAX_NANDFLASH | 272 | if (!mtd_cse0 && !mtd_cse1) { |
230 | if ((mtd_nand = crisv32_nand_flash_probe()) != NULL) | ||
231 | mtds[count++] = mtd_nand; | ||
232 | #endif | ||
233 | |||
234 | if (!mtd_cse0 && !mtd_cse1 && !mtd_nand) { | ||
235 | /* No chip found. */ | 273 | /* No chip found. */ |
236 | return NULL; | 274 | return NULL; |
237 | } | 275 | } |
@@ -245,9 +283,7 @@ static struct mtd_info *flash_probe(void) | |||
245 | * So we use the MTD concatenation layer instead of further | 283 | * So we use the MTD concatenation layer instead of further |
246 | * complicating the probing procedure. | 284 | * complicating the probing procedure. |
247 | */ | 285 | */ |
248 | mtd_total = mtd_concat_create(mtds, | 286 | mtd_total = mtd_concat_create(mtds, count, "cse0+cse1"); |
249 | count, | ||
250 | "cse0+cse1+nand"); | ||
251 | #else | 287 | #else |
252 | printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " | 288 | printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " |
253 | "(mis)configuration!\n", map_cse0.name, map_cse1.name); | 289 | "(mis)configuration!\n", map_cse0.name, map_cse1.name); |
@@ -255,61 +291,162 @@ static struct mtd_info *flash_probe(void) | |||
255 | #endif | 291 | #endif |
256 | if (!mtd_total) { | 292 | if (!mtd_total) { |
257 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", | 293 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", |
258 | map_cse0.name, map_cse1.name); | 294 | map_cse0.name, map_cse1.name); |
259 | 295 | ||
260 | /* The best we can do now is to only use what we found | 296 | /* The best we can do now is to only use what we found |
261 | * at cse0. | 297 | * at cse0. */ |
262 | */ | ||
263 | mtd_total = mtd_cse0; | 298 | mtd_total = mtd_cse0; |
264 | map_destroy(mtd_cse1); | 299 | map_destroy(mtd_cse1); |
265 | } | 300 | } |
266 | } else { | 301 | } else |
267 | mtd_total = mtd_cse0? mtd_cse0 : mtd_cse1 ? mtd_cse1 : mtd_nand; | 302 | mtd_total = mtd_cse0 ? mtd_cse0 : mtd_cse1; |
268 | |||
269 | } | ||
270 | 303 | ||
271 | return mtd_total; | 304 | return mtd_total; |
272 | } | 305 | } |
273 | 306 | ||
274 | extern unsigned long crisv32_nand_boot; | ||
275 | extern unsigned long crisv32_nand_cramfs_offset; | ||
276 | |||
277 | /* | 307 | /* |
278 | * Probe the flash chip(s) and, if it succeeds, read the partition-table | 308 | * Probe the flash chip(s) and, if it succeeds, read the partition-table |
279 | * and register the partitions with MTD. | 309 | * and register the partitions with MTD. |
280 | */ | 310 | */ |
281 | static int __init init_axis_flash(void) | 311 | static int __init init_axis_flash(void) |
282 | { | 312 | { |
283 | struct mtd_info *mymtd; | 313 | struct mtd_info *main_mtd; |
314 | struct mtd_info *aux_mtd = NULL; | ||
284 | int err = 0; | 315 | int err = 0; |
285 | int pidx = 0; | 316 | int pidx = 0; |
286 | struct partitiontable_head *ptable_head = NULL; | 317 | struct partitiontable_head *ptable_head = NULL; |
287 | struct partitiontable_entry *ptable; | 318 | struct partitiontable_entry *ptable; |
288 | int use_default_ptable = 1; /* Until proven otherwise. */ | 319 | int ptable_ok = 0; |
289 | const char *pmsg = KERN_INFO " /dev/flash%d at 0x%08x, size 0x%08x\n"; | 320 | static char page[PAGESIZE]; |
290 | static char page[512]; | ||
291 | size_t len; | 321 | size_t len; |
322 | int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */ | ||
323 | int part; | ||
324 | |||
325 | /* We need a root fs. If it resides in RAM, we need to use an | ||
326 | * MTDRAM device, so it must be enabled in the kernel config, | ||
327 | * but its size must be configured as 0 so as not to conflict | ||
328 | * with our usage. | ||
329 | */ | ||
330 | #if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) | ||
331 | if (!romfs_in_flash && !nand_boot) { | ||
332 | printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " | ||
333 | "device; configure CONFIG_MTD_MTDRAM with size = 0!\n"); | ||
334 | panic("This kernel cannot boot from RAM!\n"); | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | #ifndef CONFIG_ETRAX_VCS_SIM | ||
339 | main_mtd = flash_probe(); | ||
340 | if (main_mtd) | ||
341 | printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n", | ||
342 | main_mtd->name, main_mtd->size); | ||
343 | |||
344 | #ifdef CONFIG_ETRAX_NANDFLASH | ||
345 | aux_mtd = crisv32_nand_flash_probe(); | ||
346 | if (aux_mtd) | ||
347 | printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n", | ||
348 | aux_mtd->name, aux_mtd->size); | ||
349 | |||
350 | #ifdef CONFIG_ETRAX_NANDBOOT | ||
351 | { | ||
352 | struct mtd_info *tmp_mtd; | ||
292 | 353 | ||
293 | #ifndef CONFIG_ETRAXFS_SIM | 354 | printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, " |
294 | mymtd = flash_probe(); | 355 | "making NAND flash primary device.\n"); |
295 | mymtd->read(mymtd, CONFIG_ETRAX_PTABLE_SECTOR, 512, &len, page); | 356 | tmp_mtd = main_mtd; |
296 | ptable_head = (struct partitiontable_head *)(page + PARTITION_TABLE_OFFSET); | 357 | main_mtd = aux_mtd; |
358 | aux_mtd = tmp_mtd; | ||
359 | } | ||
360 | #endif /* CONFIG_ETRAX_NANDBOOT */ | ||
361 | #endif /* CONFIG_ETRAX_NANDFLASH */ | ||
297 | 362 | ||
298 | if (!mymtd) { | 363 | if (!main_mtd && !aux_mtd) { |
299 | /* There's no reason to use this module if no flash chip can | 364 | /* There's no reason to use this module if no flash chip can |
300 | * be identified. Make sure that's understood. | 365 | * be identified. Make sure that's understood. |
301 | */ | 366 | */ |
302 | printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); | 367 | printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); |
303 | } else { | ||
304 | printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n", | ||
305 | mymtd->name, mymtd->size); | ||
306 | axisflash_mtd = mymtd; | ||
307 | } | 368 | } |
308 | 369 | ||
309 | if (mymtd) { | 370 | #if 0 /* Dump flash memory so we can see what is going on */ |
310 | mymtd->owner = THIS_MODULE; | 371 | if (main_mtd) { |
372 | int sectoraddr, i; | ||
373 | for (sectoraddr = 0; sectoraddr < 2*65536+4096; | ||
374 | sectoraddr += PAGESIZE) { | ||
375 | main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len, | ||
376 | page); | ||
377 | printk(KERN_INFO | ||
378 | "Sector at %d (length %d):\n", | ||
379 | sectoraddr, len); | ||
380 | for (i = 0; i < PAGESIZE; i += 16) { | ||
381 | printk(KERN_INFO | ||
382 | "%02x %02x %02x %02x " | ||
383 | "%02x %02x %02x %02x " | ||
384 | "%02x %02x %02x %02x " | ||
385 | "%02x %02x %02x %02x\n", | ||
386 | page[i] & 255, page[i+1] & 255, | ||
387 | page[i+2] & 255, page[i+3] & 255, | ||
388 | page[i+4] & 255, page[i+5] & 255, | ||
389 | page[i+6] & 255, page[i+7] & 255, | ||
390 | page[i+8] & 255, page[i+9] & 255, | ||
391 | page[i+10] & 255, page[i+11] & 255, | ||
392 | page[i+12] & 255, page[i+13] & 255, | ||
393 | page[i+14] & 255, page[i+15] & 255); | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | #endif | ||
398 | |||
399 | if (main_mtd) { | ||
400 | main_mtd->owner = THIS_MODULE; | ||
401 | axisflash_mtd = main_mtd; | ||
402 | |||
403 | loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR; | ||
404 | |||
405 | /* First partition (rescue) is always set to the default. */ | ||
406 | pidx++; | ||
407 | #ifdef CONFIG_ETRAX_NANDBOOT | ||
408 | /* We know where the partition table should be located, | ||
409 | * it will be in first good block after that. | ||
410 | */ | ||
411 | int blockstat; | ||
412 | do { | ||
413 | blockstat = main_mtd->block_isbad(main_mtd, | ||
414 | ptable_sector); | ||
415 | if (blockstat < 0) | ||
416 | ptable_sector = 0; /* read error */ | ||
417 | else if (blockstat) | ||
418 | ptable_sector += main_mtd->erasesize; | ||
419 | } while (blockstat && ptable_sector); | ||
420 | #endif | ||
421 | if (ptable_sector) { | ||
422 | main_mtd->read(main_mtd, ptable_sector, PAGESIZE, | ||
423 | &len, page); | ||
424 | ptable_head = &((struct partitiontable *) page)->head; | ||
425 | } | ||
426 | |||
427 | #if 0 /* Dump partition table so we can see what is going on */ | ||
428 | printk(KERN_INFO | ||
429 | "axisflashmap: flash read %d bytes at 0x%08x, data: " | ||
430 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
431 | len, CONFIG_ETRAX_PTABLE_SECTOR, | ||
432 | page[0] & 255, page[1] & 255, | ||
433 | page[2] & 255, page[3] & 255, | ||
434 | page[4] & 255, page[5] & 255, | ||
435 | page[6] & 255, page[7] & 255); | ||
436 | printk(KERN_INFO | ||
437 | "axisflashmap: partition table offset %d, data: " | ||
438 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
439 | PARTITION_TABLE_OFFSET, | ||
440 | page[PARTITION_TABLE_OFFSET+0] & 255, | ||
441 | page[PARTITION_TABLE_OFFSET+1] & 255, | ||
442 | page[PARTITION_TABLE_OFFSET+2] & 255, | ||
443 | page[PARTITION_TABLE_OFFSET+3] & 255, | ||
444 | page[PARTITION_TABLE_OFFSET+4] & 255, | ||
445 | page[PARTITION_TABLE_OFFSET+5] & 255, | ||
446 | page[PARTITION_TABLE_OFFSET+6] & 255, | ||
447 | page[PARTITION_TABLE_OFFSET+7] & 255); | ||
448 | #endif | ||
311 | } | 449 | } |
312 | pidx++; /* First partition is always set to the default. */ | ||
313 | 450 | ||
314 | if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) | 451 | if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) |
315 | && (ptable_head->size < | 452 | && (ptable_head->size < |
@@ -322,7 +459,6 @@ static int __init init_axis_flash(void) | |||
322 | /* Looks like a start, sane length and end of a | 459 | /* Looks like a start, sane length and end of a |
323 | * partition table, lets check csum etc. | 460 | * partition table, lets check csum etc. |
324 | */ | 461 | */ |
325 | int ptable_ok = 0; | ||
326 | struct partitiontable_entry *max_addr = | 462 | struct partitiontable_entry *max_addr = |
327 | (struct partitiontable_entry *) | 463 | (struct partitiontable_entry *) |
328 | ((unsigned long)ptable_head + sizeof(*ptable_head) + | 464 | ((unsigned long)ptable_head + sizeof(*ptable_head) + |
@@ -346,104 +482,170 @@ static int __init init_axis_flash(void) | |||
346 | ptable_ok = (csum == ptable_head->checksum); | 482 | ptable_ok = (csum == ptable_head->checksum); |
347 | 483 | ||
348 | /* Read the entries and use/show the info. */ | 484 | /* Read the entries and use/show the info. */ |
349 | printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n", | 485 | printk(KERN_INFO "axisflashmap: " |
486 | "Found a%s partition table at 0x%p-0x%p.\n", | ||
350 | (ptable_ok ? " valid" : "n invalid"), ptable_head, | 487 | (ptable_ok ? " valid" : "n invalid"), ptable_head, |
351 | max_addr); | 488 | max_addr); |
352 | 489 | ||
353 | /* We have found a working bootblock. Now read the | 490 | /* We have found a working bootblock. Now read the |
354 | * partition table. Scan the table. It ends when | 491 | * partition table. Scan the table. It ends with 0xffffffff. |
355 | * there is 0xffffffff, that is, empty flash. | ||
356 | */ | 492 | */ |
357 | while (ptable_ok | 493 | while (ptable_ok |
358 | && ptable->offset != 0xffffffff | 494 | && ptable->offset != PARTITIONTABLE_END_MARKER |
359 | && ptable < max_addr | 495 | && ptable < max_addr |
360 | && pidx < MAX_PARTITIONS) { | 496 | && pidx < MAX_PARTITIONS - 1) { |
361 | 497 | ||
362 | axis_partitions[pidx].offset = offset + ptable->offset + (crisv32_nand_boot ? 16384 : 0); | 498 | axis_partitions[pidx].offset = offset + ptable->offset; |
363 | axis_partitions[pidx].size = ptable->size; | 499 | #ifdef CONFIG_ETRAX_NANDFLASH |
364 | 500 | if (main_mtd->type == MTD_NANDFLASH) { | |
365 | printk(pmsg, pidx, axis_partitions[pidx].offset, | 501 | axis_partitions[pidx].size = |
366 | axis_partitions[pidx].size); | 502 | (((ptable+1)->offset == |
503 | PARTITIONTABLE_END_MARKER) ? | ||
504 | main_mtd->size : | ||
505 | ((ptable+1)->offset + offset)) - | ||
506 | (ptable->offset + offset); | ||
507 | |||
508 | } else | ||
509 | #endif /* CONFIG_ETRAX_NANDFLASH */ | ||
510 | axis_partitions[pidx].size = ptable->size; | ||
511 | #ifdef CONFIG_ETRAX_NANDBOOT | ||
512 | /* Save partition number of jffs2 ro partition. | ||
513 | * Needed if RAM booting or root file system in RAM. | ||
514 | */ | ||
515 | if (!nand_boot && | ||
516 | ram_rootfs_partition < 0 && /* not already set */ | ||
517 | ptable->type == PARTITION_TYPE_JFFS2 && | ||
518 | (ptable->flags & PARTITION_FLAGS_READONLY_MASK) == | ||
519 | PARTITION_FLAGS_READONLY) | ||
520 | ram_rootfs_partition = pidx; | ||
521 | #endif /* CONFIG_ETRAX_NANDBOOT */ | ||
367 | pidx++; | 522 | pidx++; |
368 | ptable++; | 523 | ptable++; |
369 | } | 524 | } |
370 | use_default_ptable = !ptable_ok; | ||
371 | } | 525 | } |
372 | 526 | ||
373 | if (romfs_in_flash) { | 527 | /* Decide whether to use default partition table. */ |
374 | /* Add an overlapping device for the root partition (romfs). */ | 528 | /* Only use default table if we actually have a device (main_mtd) */ |
375 | 529 | ||
376 | axis_partitions[pidx].name = "romfs"; | 530 | struct mtd_partition *partition = &axis_partitions[0]; |
377 | if (crisv32_nand_boot) { | 531 | if (main_mtd && !ptable_ok) { |
378 | char* data = kmalloc(1024, GFP_KERNEL); | 532 | memcpy(axis_partitions, axis_default_partitions, |
379 | int len; | 533 | sizeof(axis_default_partitions)); |
380 | int offset = crisv32_nand_cramfs_offset & ~(1024-1); | 534 | pidx = NUM_DEFAULT_PARTITIONS; |
381 | char* tmp; | 535 | ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO; |
382 | 536 | } | |
383 | mymtd->read(mymtd, offset, 1024, &len, data); | ||
384 | tmp = &data[crisv32_nand_cramfs_offset % 512]; | ||
385 | axis_partitions[pidx].size = *(unsigned*)(tmp + 4); | ||
386 | axis_partitions[pidx].offset = crisv32_nand_cramfs_offset; | ||
387 | kfree(data); | ||
388 | } else { | ||
389 | axis_partitions[pidx].size = romfs_length; | ||
390 | axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; | ||
391 | } | ||
392 | 537 | ||
538 | /* Add artificial partitions for rootfs if necessary */ | ||
539 | if (romfs_in_flash) { | ||
540 | /* rootfs is in directly accessible flash memory = NOR flash. | ||
541 | Add an overlapping device for the rootfs partition. */ | ||
542 | printk(KERN_INFO "axisflashmap: Adding partition for " | ||
543 | "overlapping root file system image\n"); | ||
544 | axis_partitions[pidx].size = romfs_length; | ||
545 | axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; | ||
546 | axis_partitions[pidx].name = "romfs"; | ||
393 | axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; | 547 | axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; |
394 | 548 | ram_rootfs_partition = -1; | |
395 | printk(KERN_INFO | ||
396 | " Adding readonly flash partition for romfs image:\n"); | ||
397 | printk(pmsg, pidx, axis_partitions[pidx].offset, | ||
398 | axis_partitions[pidx].size); | ||
399 | pidx++; | 549 | pidx++; |
400 | } | 550 | } else if (romfs_length && !nand_boot) { |
401 | 551 | /* romfs exists in memory, but not in flash, so must be in RAM. | |
402 | if (mymtd) { | 552 | * Configure an MTDRAM partition. */ |
403 | if (use_default_ptable) { | 553 | if (ram_rootfs_partition < 0) { |
404 | printk(KERN_INFO " Using default partition table.\n"); | 554 | /* None set yet, put it at the end */ |
405 | err = add_mtd_partitions(mymtd, axis_default_partitions, | 555 | ram_rootfs_partition = pidx; |
406 | NUM_DEFAULT_PARTITIONS); | 556 | pidx++; |
407 | } else { | ||
408 | err = add_mtd_partitions(mymtd, axis_partitions, pidx); | ||
409 | } | 557 | } |
558 | printk(KERN_INFO "axisflashmap: Adding partition for " | ||
559 | "root file system image in RAM\n"); | ||
560 | axis_partitions[ram_rootfs_partition].size = romfs_length; | ||
561 | axis_partitions[ram_rootfs_partition].offset = romfs_start; | ||
562 | axis_partitions[ram_rootfs_partition].name = "romfs"; | ||
563 | axis_partitions[ram_rootfs_partition].mask_flags |= | ||
564 | MTD_WRITEABLE; | ||
565 | } | ||
410 | 566 | ||
411 | if (err) { | 567 | #ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE |
412 | panic("axisflashmap could not add MTD partitions!\n"); | 568 | if (main_mtd) { |
413 | } | 569 | main_partition.size = main_mtd->size; |
570 | err = add_mtd_partitions(main_mtd, &main_partition, 1); | ||
571 | if (err) | ||
572 | panic("axisflashmap: Could not initialize " | ||
573 | "partition for whole main mtd device!\n"); | ||
414 | } | 574 | } |
415 | /* CONFIG_EXTRAXFS_SIM */ | ||
416 | #endif | 575 | #endif |
417 | 576 | ||
418 | if (!romfs_in_flash) { | 577 | /* Now, register all partitions with mtd. |
419 | /* Create an RAM device for the root partition (romfs). */ | 578 | * We do this one at a time so we can slip in an MTDRAM device |
579 | * in the proper place if required. */ | ||
580 | |||
581 | for (part = 0; part < pidx; part++) { | ||
582 | if (part == ram_rootfs_partition) { | ||
583 | /* add MTDRAM partition here */ | ||
584 | struct mtd_info *mtd_ram; | ||
585 | |||
586 | mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); | ||
587 | if (!mtd_ram) | ||
588 | panic("axisflashmap: Couldn't allocate memory " | ||
589 | "for mtd_info!\n"); | ||
590 | printk(KERN_INFO "axisflashmap: Adding RAM partition " | ||
591 | "for rootfs image.\n"); | ||
592 | err = mtdram_init_device(mtd_ram, | ||
593 | (void *)partition[part].offset, | ||
594 | partition[part].size, | ||
595 | partition[part].name); | ||
596 | if (err) | ||
597 | panic("axisflashmap: Could not initialize " | ||
598 | "MTD RAM device!\n"); | ||
599 | /* JFFS2 likes to have an erasesize. Keep potential | ||
600 | * JFFS2 rootfs happy by providing one. Since image | ||
601 | * was most likely created for main mtd, use that | ||
602 | * erasesize, if available. Otherwise, make a guess. */ | ||
603 | mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize : | ||
604 | CONFIG_ETRAX_PTABLE_SECTOR); | ||
605 | } else { | ||
606 | err = add_mtd_partitions(main_mtd, &partition[part], 1); | ||
607 | if (err) | ||
608 | panic("axisflashmap: Could not add mtd " | ||
609 | "partition %d\n", part); | ||
610 | } | ||
611 | } | ||
612 | #endif /* CONFIG_EXTRAX_VCS_SIM */ | ||
613 | |||
614 | #ifdef CONFIG_ETRAX_VCS_SIM | ||
615 | /* For simulator, always use a RAM partition. | ||
616 | * The rootfs will be found after the kernel in RAM, | ||
617 | * with romfs_start and romfs_end indicating location and size. | ||
618 | */ | ||
619 | struct mtd_info *mtd_ram; | ||
620 | |||
621 | mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); | ||
622 | if (!mtd_ram) { | ||
623 | panic("axisflashmap: Couldn't allocate memory for " | ||
624 | "mtd_info!\n"); | ||
625 | } | ||
420 | 626 | ||
421 | #if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) | 627 | printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, " |
422 | /* No use trying to boot this kernel from RAM. Panic! */ | 628 | "at %u, size %u\n", |
423 | printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " | 629 | (unsigned) romfs_start, (unsigned) romfs_length); |
424 | "device due to kernel (mis)configuration!\n"); | ||
425 | panic("This kernel cannot boot from RAM!\n"); | ||
426 | #else | ||
427 | struct mtd_info *mtd_ram; | ||
428 | 630 | ||
429 | mtd_ram = kmalloc(sizeof(struct mtd_info), | 631 | err = mtdram_init_device(mtd_ram, (void *)romfs_start, |
430 | GFP_KERNEL); | 632 | romfs_length, "romfs"); |
431 | if (!mtd_ram) { | 633 | if (err) { |
432 | panic("axisflashmap couldn't allocate memory for " | 634 | panic("axisflashmap: Could not initialize MTD RAM " |
433 | "mtd_info!\n"); | 635 | "device!\n"); |
434 | } | 636 | } |
637 | #endif /* CONFIG_EXTRAX_VCS_SIM */ | ||
435 | 638 | ||
436 | printk(KERN_INFO " Adding RAM partition for romfs image:\n"); | 639 | #ifndef CONFIG_ETRAX_VCS_SIM |
437 | printk(pmsg, pidx, romfs_start, romfs_length); | 640 | if (aux_mtd) { |
641 | aux_partition.size = aux_mtd->size; | ||
642 | err = add_mtd_partitions(aux_mtd, &aux_partition, 1); | ||
643 | if (err) | ||
644 | panic("axisflashmap: Could not initialize " | ||
645 | "aux mtd device!\n"); | ||
438 | 646 | ||
439 | err = mtdram_init_device(mtd_ram, (void*)romfs_start, | ||
440 | romfs_length, "romfs"); | ||
441 | if (err) { | ||
442 | panic("axisflashmap could not initialize MTD RAM " | ||
443 | "device!\n"); | ||
444 | } | ||
445 | #endif | ||
446 | } | 647 | } |
648 | #endif /* CONFIG_EXTRAX_VCS_SIM */ | ||
447 | 649 | ||
448 | return err; | 650 | return err; |
449 | } | 651 | } |
diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index e8914d401696..9fb58202be99 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* $Id: cryptocop.c,v 1.13 2005/04/21 17:27:55 henriken Exp $ | 1 | /* |
2 | * | ||
3 | * Stream co-processor driver for the ETRAX FS | 2 | * Stream co-processor driver for the ETRAX FS |
4 | * | 3 | * |
5 | * Copyright (C) 2003-2005 Axis Communications AB | 4 | * Copyright (C) 2003-2007 Axis Communications AB |
6 | */ | 5 | */ |
7 | 6 | ||
8 | #include <linux/init.h> | 7 | #include <linux/init.h> |
@@ -25,17 +24,29 @@ | |||
25 | #include <asm/signal.h> | 24 | #include <asm/signal.h> |
26 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
27 | 26 | ||
28 | #include <asm/arch/dma.h> | 27 | #include <dma.h> |
29 | #include <asm/arch/hwregs/dma.h> | 28 | #include <hwregs/dma.h> |
30 | #include <asm/arch/hwregs/reg_map.h> | 29 | #include <hwregs/reg_map.h> |
31 | #include <asm/arch/hwregs/reg_rdwr.h> | 30 | #include <hwregs/reg_rdwr.h> |
32 | #include <asm/arch/hwregs/intr_vect_defs.h> | 31 | #include <hwregs/intr_vect_defs.h> |
33 | 32 | ||
34 | #include <asm/arch/hwregs/strcop.h> | 33 | #include <hwregs/strcop.h> |
35 | #include <asm/arch/hwregs/strcop_defs.h> | 34 | #include <hwregs/strcop_defs.h> |
36 | #include <asm/arch/cryptocop.h> | 35 | #include <cryptocop.h> |
37 | 36 | ||
38 | 37 | #ifdef CONFIG_ETRAXFS | |
38 | #define IN_DMA 9 | ||
39 | #define OUT_DMA 8 | ||
40 | #define IN_DMA_INST regi_dma9 | ||
41 | #define OUT_DMA_INST regi_dma8 | ||
42 | #define DMA_IRQ DMA9_INTR_VECT | ||
43 | #else | ||
44 | #define IN_DMA 3 | ||
45 | #define OUT_DMA 2 | ||
46 | #define IN_DMA_INST regi_dma3 | ||
47 | #define OUT_DMA_INST regi_dma2 | ||
48 | #define DMA_IRQ DMA3_INTR_VECT | ||
49 | #endif | ||
39 | 50 | ||
40 | #define DESCR_ALLOC_PAD (31) | 51 | #define DESCR_ALLOC_PAD (31) |
41 | 52 | ||
@@ -1886,14 +1897,14 @@ static void cryptocop_do_tasklet(unsigned long unused) | |||
1886 | } | 1897 | } |
1887 | 1898 | ||
1888 | static irqreturn_t | 1899 | static irqreturn_t |
1889 | dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs) | 1900 | dma_done_interrupt(int irq, void *dev_id) |
1890 | { | 1901 | { |
1891 | struct cryptocop_prio_job *done_job; | 1902 | struct cryptocop_prio_job *done_job; |
1892 | reg_dma_rw_ack_intr ack_intr = { | 1903 | reg_dma_rw_ack_intr ack_intr = { |
1893 | .data = 1, | 1904 | .data = 1, |
1894 | }; | 1905 | }; |
1895 | 1906 | ||
1896 | REG_WR (dma, regi_dma9, rw_ack_intr, ack_intr); | 1907 | REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); |
1897 | 1908 | ||
1898 | DEBUG(printk("cryptocop DMA done\n")); | 1909 | DEBUG(printk("cryptocop DMA done\n")); |
1899 | 1910 | ||
@@ -1937,7 +1948,6 @@ dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
1937 | static int init_cryptocop(void) | 1948 | static int init_cryptocop(void) |
1938 | { | 1949 | { |
1939 | unsigned long flags; | 1950 | unsigned long flags; |
1940 | reg_intr_vect_rw_mask intr_mask; | ||
1941 | reg_dma_rw_cfg dma_cfg = {.en = 1}; | 1951 | reg_dma_rw_cfg dma_cfg = {.en = 1}; |
1942 | reg_dma_rw_intr_mask intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */ | 1952 | reg_dma_rw_intr_mask intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */ |
1943 | reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; | 1953 | reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; |
@@ -1950,10 +1960,14 @@ static int init_cryptocop(void) | |||
1950 | .en = 1 | 1960 | .en = 1 |
1951 | }; | 1961 | }; |
1952 | 1962 | ||
1953 | if (request_irq(DMA9_INTR_VECT, dma_done_interrupt, 0, "stream co-processor DMA", NULL)) panic("request_irq stream co-processor irq dma9"); | 1963 | if (request_irq(DMA_IRQ, dma_done_interrupt, 0, |
1964 | "stream co-processor DMA", NULL)) | ||
1965 | panic("request_irq stream co-processor irq dma9"); | ||
1954 | 1966 | ||
1955 | (void)crisv32_request_dma(8, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp); | 1967 | (void)crisv32_request_dma(OUT_DMA, "strcop", DMA_PANIC_ON_ERROR, |
1956 | (void)crisv32_request_dma(9, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp); | 1968 | 0, dma_strp); |
1969 | (void)crisv32_request_dma(IN_DMA, "strcop", DMA_PANIC_ON_ERROR, | ||
1970 | 0, dma_strp); | ||
1957 | 1971 | ||
1958 | local_irq_save(flags); | 1972 | local_irq_save(flags); |
1959 | 1973 | ||
@@ -1963,24 +1977,19 @@ static int init_cryptocop(void) | |||
1963 | strcop_cfg.en = 1; | 1977 | strcop_cfg.en = 1; |
1964 | REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg); | 1978 | REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg); |
1965 | 1979 | ||
1966 | /* Enable DMA9 interrupt */ | ||
1967 | intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); | ||
1968 | intr_mask.dma9 = 1; | ||
1969 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | ||
1970 | |||
1971 | /* Enable DMAs. */ | 1980 | /* Enable DMAs. */ |
1972 | REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */ | 1981 | REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */ |
1973 | REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */ | 1982 | REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */ |
1974 | 1983 | ||
1975 | /* Set up wordsize = 4 for DMAs. */ | 1984 | /* Set up wordsize = 4 for DMAs. */ |
1976 | DMA_WR_CMD (regi_dma8, regk_dma_set_w_size4); | 1985 | DMA_WR_CMD(OUT_DMA_INST, regk_dma_set_w_size4); |
1977 | DMA_WR_CMD (regi_dma9, regk_dma_set_w_size4); | 1986 | DMA_WR_CMD(IN_DMA_INST, regk_dma_set_w_size4); |
1978 | 1987 | ||
1979 | /* Enable interrupts. */ | 1988 | /* Enable interrupts. */ |
1980 | REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in); | 1989 | REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in); |
1981 | 1990 | ||
1982 | /* Clear intr ack. */ | 1991 | /* Clear intr ack. */ |
1983 | REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr); | 1992 | REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); |
1984 | 1993 | ||
1985 | local_irq_restore(flags); | 1994 | local_irq_restore(flags); |
1986 | 1995 | ||
@@ -1991,7 +2000,6 @@ static int init_cryptocop(void) | |||
1991 | static void release_cryptocop(void) | 2000 | static void release_cryptocop(void) |
1992 | { | 2001 | { |
1993 | unsigned long flags; | 2002 | unsigned long flags; |
1994 | reg_intr_vect_rw_mask intr_mask; | ||
1995 | reg_dma_rw_cfg dma_cfg = {.en = 0}; | 2003 | reg_dma_rw_cfg dma_cfg = {.en = 0}; |
1996 | reg_dma_rw_intr_mask intr_mask_in = {0}; | 2004 | reg_dma_rw_intr_mask intr_mask_in = {0}; |
1997 | reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; | 2005 | reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; |
@@ -1999,26 +2007,21 @@ static void release_cryptocop(void) | |||
1999 | local_irq_save(flags); | 2007 | local_irq_save(flags); |
2000 | 2008 | ||
2001 | /* Clear intr ack. */ | 2009 | /* Clear intr ack. */ |
2002 | REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr); | 2010 | REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); |
2003 | |||
2004 | /* Disable DMA9 interrupt */ | ||
2005 | intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); | ||
2006 | intr_mask.dma9 = 0; | ||
2007 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | ||
2008 | 2011 | ||
2009 | /* Disable DMAs. */ | 2012 | /* Disable DMAs. */ |
2010 | REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */ | 2013 | REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */ |
2011 | REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */ | 2014 | REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */ |
2012 | 2015 | ||
2013 | /* Disable interrupts. */ | 2016 | /* Disable interrupts. */ |
2014 | REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in); | 2017 | REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in); |
2015 | 2018 | ||
2016 | local_irq_restore(flags); | 2019 | local_irq_restore(flags); |
2017 | 2020 | ||
2018 | free_irq(DMA9_INTR_VECT, NULL); | 2021 | free_irq(DMA_IRQ, NULL); |
2019 | 2022 | ||
2020 | (void)crisv32_free_dma(8); | 2023 | (void)crisv32_free_dma(OUT_DMA); |
2021 | (void)crisv32_free_dma(9); | 2024 | (void)crisv32_free_dma(IN_DMA); |
2022 | } | 2025 | } |
2023 | 2026 | ||
2024 | 2027 | ||
@@ -2076,13 +2079,13 @@ static void cryptocop_job_queue_close(void) | |||
2076 | reg_dma_rw_cfg dma_out_cfg, dma_in_cfg; | 2079 | reg_dma_rw_cfg dma_out_cfg, dma_in_cfg; |
2077 | 2080 | ||
2078 | /* Stop DMA. */ | 2081 | /* Stop DMA. */ |
2079 | dma_out_cfg = REG_RD(dma, regi_dma8, rw_cfg); | 2082 | dma_out_cfg = REG_RD(dma, OUT_DMA_INST, rw_cfg); |
2080 | dma_out_cfg.en = regk_dma_no; | 2083 | dma_out_cfg.en = regk_dma_no; |
2081 | REG_WR(dma, regi_dma8, rw_cfg, dma_out_cfg); | 2084 | REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_out_cfg); |
2082 | 2085 | ||
2083 | dma_in_cfg = REG_RD(dma, regi_dma9, rw_cfg); | 2086 | dma_in_cfg = REG_RD(dma, IN_DMA_INST, rw_cfg); |
2084 | dma_in_cfg.en = regk_dma_no; | 2087 | dma_in_cfg.en = regk_dma_no; |
2085 | REG_WR(dma, regi_dma9, rw_cfg, dma_in_cfg); | 2088 | REG_WR(dma, IN_DMA_INST, rw_cfg, dma_in_cfg); |
2086 | 2089 | ||
2087 | /* Disble the cryptocop. */ | 2090 | /* Disble the cryptocop. */ |
2088 | rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg); | 2091 | rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg); |
@@ -2226,10 +2229,11 @@ static void cryptocop_start_job(void) | |||
2226 | &pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out))); | 2229 | &pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out))); |
2227 | 2230 | ||
2228 | /* Start input DMA. */ | 2231 | /* Start input DMA. */ |
2229 | DMA_START_CONTEXT(regi_dma9, virt_to_phys(&pj->iop->ctx_in)); | 2232 | flush_dma_context(&pj->iop->ctx_in); |
2233 | DMA_START_CONTEXT(IN_DMA_INST, virt_to_phys(&pj->iop->ctx_in)); | ||
2230 | 2234 | ||
2231 | /* Start output DMA. */ | 2235 | /* Start output DMA. */ |
2232 | DMA_START_CONTEXT(regi_dma8, virt_to_phys(&pj->iop->ctx_out)); | 2236 | DMA_START_CONTEXT(OUT_DMA_INST, virt_to_phys(&pj->iop->ctx_out)); |
2233 | 2237 | ||
2234 | spin_unlock_irqrestore(&running_job_lock, running_job_flags); | 2238 | spin_unlock_irqrestore(&running_job_lock, running_job_flags); |
2235 | DEBUG(printk("cryptocop_start_job: exiting\n")); | 2239 | DEBUG(printk("cryptocop_start_job: exiting\n")); |
diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c index f1edd2e359b2..c2fb7a5c1396 100644 --- a/arch/cris/arch-v32/drivers/i2c.c +++ b/arch/cris/arch-v32/drivers/i2c.c | |||
@@ -19,10 +19,10 @@ | |||
19 | *! | 19 | *! |
20 | *! --------------------------------------------------------------------------- | 20 | *! --------------------------------------------------------------------------- |
21 | *! | 21 | *! |
22 | *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN | 22 | *! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN |
23 | *! | 23 | *! |
24 | *!***************************************************************************/ | 24 | *!***************************************************************************/ |
25 | /* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */ | 25 | |
26 | /****************** INCLUDE FILES SECTION ***********************************/ | 26 | /****************** INCLUDE FILES SECTION ***********************************/ |
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
@@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c"; | |||
79 | 79 | ||
80 | #define i2c_delay(usecs) udelay(usecs) | 80 | #define i2c_delay(usecs) udelay(usecs) |
81 | 81 | ||
82 | static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ | ||
83 | |||
82 | /****************** VARIABLE SECTION ************************************/ | 84 | /****************** VARIABLE SECTION ************************************/ |
83 | 85 | ||
84 | static struct crisv32_iopin cris_i2c_clk; | 86 | static struct crisv32_iopin cris_i2c_clk; |
@@ -252,6 +254,7 @@ i2c_getack(void) | |||
252 | * generate ACK clock pulse | 254 | * generate ACK clock pulse |
253 | */ | 255 | */ |
254 | i2c_clk(I2C_CLOCK_HIGH); | 256 | i2c_clk(I2C_CLOCK_HIGH); |
257 | #if 0 | ||
255 | /* | 258 | /* |
256 | * Use PORT PB instead of I2C | 259 | * Use PORT PB instead of I2C |
257 | * for input. (I2C not working) | 260 | * for input. (I2C not working) |
@@ -264,6 +267,8 @@ i2c_getack(void) | |||
264 | i2c_data(1); | 267 | i2c_data(1); |
265 | i2c_disable(); | 268 | i2c_disable(); |
266 | i2c_dir_in(); | 269 | i2c_dir_in(); |
270 | #endif | ||
271 | |||
267 | /* | 272 | /* |
268 | * now wait for ack | 273 | * now wait for ack |
269 | */ | 274 | */ |
@@ -271,11 +276,11 @@ i2c_getack(void) | |||
271 | /* | 276 | /* |
272 | * check for ack | 277 | * check for ack |
273 | */ | 278 | */ |
274 | if(i2c_getbit()) | 279 | if (i2c_getbit()) |
275 | ack = 0; | 280 | ack = 0; |
276 | i2c_delay(CLOCK_HIGH_TIME/2); | 281 | i2c_delay(CLOCK_HIGH_TIME/2); |
277 | if(!ack){ | 282 | if (!ack) { |
278 | if(!i2c_getbit()) /* receiver pulled SDA low */ | 283 | if (!i2c_getbit()) /* receiver pulld SDA low */ |
279 | ack = 1; | 284 | ack = 1; |
280 | i2c_delay(CLOCK_HIGH_TIME/2); | 285 | i2c_delay(CLOCK_HIGH_TIME/2); |
281 | } | 286 | } |
@@ -285,6 +290,7 @@ i2c_getack(void) | |||
285 | * before we enable our output. If we keep data high | 290 | * before we enable our output. If we keep data high |
286 | * and enable output, we would generate a stop condition. | 291 | * and enable output, we would generate a stop condition. |
287 | */ | 292 | */ |
293 | #if 0 | ||
288 | i2c_data(I2C_DATA_LOW); | 294 | i2c_data(I2C_DATA_LOW); |
289 | 295 | ||
290 | /* | 296 | /* |
@@ -292,6 +298,7 @@ i2c_getack(void) | |||
292 | */ | 298 | */ |
293 | i2c_enable(); | 299 | i2c_enable(); |
294 | i2c_dir_out(); | 300 | i2c_dir_out(); |
301 | #endif | ||
295 | i2c_clk(I2C_CLOCK_LOW); | 302 | i2c_clk(I2C_CLOCK_LOW); |
296 | i2c_delay(CLOCK_HIGH_TIME/4); | 303 | i2c_delay(CLOCK_HIGH_TIME/4); |
297 | /* | 304 | /* |
@@ -375,6 +382,121 @@ i2c_sendnack(void) | |||
375 | 382 | ||
376 | /*#--------------------------------------------------------------------------- | 383 | /*#--------------------------------------------------------------------------- |
377 | *# | 384 | *# |
385 | *# FUNCTION NAME: i2c_write | ||
386 | *# | ||
387 | *# DESCRIPTION : Writes a value to an I2C device | ||
388 | *# | ||
389 | *#--------------------------------------------------------------------------*/ | ||
390 | int | ||
391 | i2c_write(unsigned char theSlave, void *data, size_t nbytes) | ||
392 | { | ||
393 | int error, cntr = 3; | ||
394 | unsigned char bytes_wrote = 0; | ||
395 | unsigned char value; | ||
396 | unsigned long flags; | ||
397 | |||
398 | spin_lock_irqsave(&i2c_lock, flags); | ||
399 | |||
400 | do { | ||
401 | error = 0; | ||
402 | |||
403 | i2c_start(); | ||
404 | /* | ||
405 | * send slave address | ||
406 | */ | ||
407 | i2c_outbyte((theSlave & 0xfe)); | ||
408 | /* | ||
409 | * wait for ack | ||
410 | */ | ||
411 | if (!i2c_getack()) | ||
412 | error = 1; | ||
413 | /* | ||
414 | * send data | ||
415 | */ | ||
416 | for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) { | ||
417 | memcpy(&value, data + bytes_wrote, sizeof value); | ||
418 | i2c_outbyte(value); | ||
419 | /* | ||
420 | * now it's time to wait for ack | ||
421 | */ | ||
422 | if (!i2c_getack()) | ||
423 | error |= 4; | ||
424 | } | ||
425 | /* | ||
426 | * end byte stream | ||
427 | */ | ||
428 | i2c_stop(); | ||
429 | |||
430 | } while (error && cntr--); | ||
431 | |||
432 | i2c_delay(CLOCK_LOW_TIME); | ||
433 | |||
434 | spin_unlock_irqrestore(&i2c_lock, flags); | ||
435 | |||
436 | return -error; | ||
437 | } | ||
438 | |||
439 | /*#--------------------------------------------------------------------------- | ||
440 | *# | ||
441 | *# FUNCTION NAME: i2c_read | ||
442 | *# | ||
443 | *# DESCRIPTION : Reads a value from an I2C device | ||
444 | *# | ||
445 | *#--------------------------------------------------------------------------*/ | ||
446 | int | ||
447 | i2c_read(unsigned char theSlave, void *data, size_t nbytes) | ||
448 | { | ||
449 | unsigned char b = 0; | ||
450 | unsigned char bytes_read = 0; | ||
451 | int error, cntr = 3; | ||
452 | unsigned long flags; | ||
453 | |||
454 | spin_lock_irqsave(&i2c_lock, flags); | ||
455 | |||
456 | do { | ||
457 | error = 0; | ||
458 | memset(data, 0, nbytes); | ||
459 | /* | ||
460 | * generate start condition | ||
461 | */ | ||
462 | i2c_start(); | ||
463 | /* | ||
464 | * send slave address | ||
465 | */ | ||
466 | i2c_outbyte((theSlave | 0x01)); | ||
467 | /* | ||
468 | * wait for ack | ||
469 | */ | ||
470 | if (!i2c_getack()) | ||
471 | error = 1; | ||
472 | /* | ||
473 | * fetch data | ||
474 | */ | ||
475 | for (bytes_read = 0; bytes_read < nbytes; bytes_read++) { | ||
476 | b = i2c_inbyte(); | ||
477 | memcpy(data + bytes_read, &b, sizeof b); | ||
478 | |||
479 | if (bytes_read < (nbytes - 1)) | ||
480 | i2c_sendack(); | ||
481 | } | ||
482 | /* | ||
483 | * last received byte needs to be nacked | ||
484 | * instead of acked | ||
485 | */ | ||
486 | i2c_sendnack(); | ||
487 | /* | ||
488 | * end sequence | ||
489 | */ | ||
490 | i2c_stop(); | ||
491 | } while (error && cntr--); | ||
492 | |||
493 | spin_unlock_irqrestore(&i2c_lock, flags); | ||
494 | |||
495 | return -error; | ||
496 | } | ||
497 | |||
498 | /*#--------------------------------------------------------------------------- | ||
499 | *# | ||
378 | *# FUNCTION NAME: i2c_writereg | 500 | *# FUNCTION NAME: i2c_writereg |
379 | *# | 501 | *# |
380 | *# DESCRIPTION : Writes a value to an I2C device | 502 | *# DESCRIPTION : Writes a value to an I2C device |
@@ -387,12 +509,10 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, | |||
387 | int error, cntr = 3; | 509 | int error, cntr = 3; |
388 | unsigned long flags; | 510 | unsigned long flags; |
389 | 511 | ||
512 | spin_lock_irqsave(&i2c_lock, flags); | ||
513 | |||
390 | do { | 514 | do { |
391 | error = 0; | 515 | error = 0; |
392 | /* | ||
393 | * we don't like to be interrupted | ||
394 | */ | ||
395 | local_irq_save(flags); | ||
396 | 516 | ||
397 | i2c_start(); | 517 | i2c_start(); |
398 | /* | 518 | /* |
@@ -427,15 +547,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, | |||
427 | * end byte stream | 547 | * end byte stream |
428 | */ | 548 | */ |
429 | i2c_stop(); | 549 | i2c_stop(); |
430 | /* | ||
431 | * enable interrupt again | ||
432 | */ | ||
433 | local_irq_restore(flags); | ||
434 | |||
435 | } while(error && cntr--); | 550 | } while(error && cntr--); |
436 | 551 | ||
437 | i2c_delay(CLOCK_LOW_TIME); | 552 | i2c_delay(CLOCK_LOW_TIME); |
438 | 553 | ||
554 | spin_unlock_irqrestore(&i2c_lock, flags); | ||
555 | |||
439 | return -error; | 556 | return -error; |
440 | } | 557 | } |
441 | 558 | ||
@@ -453,13 +570,11 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
453 | int error, cntr = 3; | 570 | int error, cntr = 3; |
454 | unsigned long flags; | 571 | unsigned long flags; |
455 | 572 | ||
573 | spin_lock_irqsave(&i2c_lock, flags); | ||
574 | |||
456 | do { | 575 | do { |
457 | error = 0; | 576 | error = 0; |
458 | /* | 577 | /* |
459 | * we don't like to be interrupted | ||
460 | */ | ||
461 | local_irq_save(flags); | ||
462 | /* | ||
463 | * generate start condition | 578 | * generate start condition |
464 | */ | 579 | */ |
465 | i2c_start(); | 580 | i2c_start(); |
@@ -482,7 +597,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
482 | * now it's time to wait for ack | 597 | * now it's time to wait for ack |
483 | */ | 598 | */ |
484 | if(!i2c_getack()) | 599 | if(!i2c_getack()) |
485 | error = 1; | 600 | error |= 2; |
486 | /* | 601 | /* |
487 | * repeat start condition | 602 | * repeat start condition |
488 | */ | 603 | */ |
@@ -496,7 +611,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
496 | * wait for ack | 611 | * wait for ack |
497 | */ | 612 | */ |
498 | if(!i2c_getack()) | 613 | if(!i2c_getack()) |
499 | error = 1; | 614 | error |= 4; |
500 | /* | 615 | /* |
501 | * fetch register | 616 | * fetch register |
502 | */ | 617 | */ |
@@ -510,13 +625,11 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) | |||
510 | * end sequence | 625 | * end sequence |
511 | */ | 626 | */ |
512 | i2c_stop(); | 627 | i2c_stop(); |
513 | /* | ||
514 | * enable interrupt again | ||
515 | */ | ||
516 | local_irq_restore(flags); | ||
517 | 628 | ||
518 | } while(error && cntr--); | 629 | } while(error && cntr--); |
519 | 630 | ||
631 | spin_unlock_irqrestore(&i2c_lock, flags); | ||
632 | |||
520 | return b; | 633 | return b; |
521 | } | 634 | } |
522 | 635 | ||
@@ -540,7 +653,7 @@ i2c_ioctl(struct inode *inode, struct file *file, | |||
540 | unsigned int cmd, unsigned long arg) | 653 | unsigned int cmd, unsigned long arg) |
541 | { | 654 | { |
542 | if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { | 655 | if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { |
543 | return -EINVAL; | 656 | return -ENOTTY; |
544 | } | 657 | } |
545 | 658 | ||
546 | switch (_IOC_NR(cmd)) { | 659 | switch (_IOC_NR(cmd)) { |
@@ -580,31 +693,52 @@ static const struct file_operations i2c_fops = { | |||
580 | .release = i2c_release, | 693 | .release = i2c_release, |
581 | }; | 694 | }; |
582 | 695 | ||
583 | int __init | 696 | static int __init i2c_init(void) |
584 | i2c_init(void) | ||
585 | { | 697 | { |
586 | int res; | 698 | static int res; |
699 | static int first = 1; | ||
587 | 700 | ||
588 | /* Setup and enable the Port B I2C interface */ | 701 | if (!first) |
702 | return res; | ||
589 | 703 | ||
590 | crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT); | 704 | first = 0; |
591 | crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT); | 705 | |
706 | /* Setup and enable the DATA and CLK pins */ | ||
707 | |||
708 | res = crisv32_io_get_name(&cris_i2c_data, | ||
709 | CONFIG_ETRAX_V32_I2C_DATA_PORT); | ||
710 | if (res < 0) | ||
711 | return res; | ||
712 | |||
713 | res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT); | ||
714 | crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out); | ||
715 | |||
716 | return res; | ||
717 | } | ||
718 | |||
719 | |||
720 | static int __init i2c_register(void) | ||
721 | { | ||
722 | int res; | ||
723 | |||
724 | res = i2c_init(); | ||
725 | if (res < 0) | ||
726 | return res; | ||
592 | 727 | ||
593 | /* register char device */ | 728 | /* register char device */ |
594 | 729 | ||
595 | res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); | 730 | res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); |
596 | if(res < 0) { | 731 | if (res < 0) { |
597 | printk(KERN_ERR "i2c: couldn't get a major number.\n"); | 732 | printk(KERN_ERR "i2c: couldn't get a major number.\n"); |
598 | return res; | 733 | return res; |
599 | } | 734 | } |
600 | 735 | ||
601 | printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); | 736 | printk(KERN_INFO |
737 | "I2C driver v2.2, (c) 1999-2007 Axis Communications AB\n"); | ||
602 | 738 | ||
603 | return 0; | 739 | return 0; |
604 | } | 740 | } |
605 | |||
606 | /* this makes sure that i2c_init is called during boot */ | 741 | /* this makes sure that i2c_init is called during boot */ |
607 | 742 | module_init(i2c_register); | |
608 | module_init(i2c_init); | ||
609 | 743 | ||
610 | /****************** END OF FILE i2c.c ********************************/ | 744 | /****************** END OF FILE i2c.c ********************************/ |
diff --git a/arch/cris/arch-v32/drivers/i2c.h b/arch/cris/arch-v32/drivers/i2c.h index bfe1a13f9f35..c073cf4ba016 100644 --- a/arch/cris/arch-v32/drivers/i2c.h +++ b/arch/cris/arch-v32/drivers/i2c.h | |||
@@ -3,6 +3,8 @@ | |||
3 | 3 | ||
4 | /* High level I2C actions */ | 4 | /* High level I2C actions */ |
5 | int __init i2c_init(void); | 5 | int __init i2c_init(void); |
6 | int i2c_write(unsigned char theSlave, void *data, size_t nbytes); | ||
7 | int i2c_read(unsigned char theSlave, void *data, size_t nbytes); | ||
6 | int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); | 8 | int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); |
7 | unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); | 9 | unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); |
8 | 10 | ||
diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c index f4bdc1dfa320..3b3857ec1f15 100644 --- a/arch/cris/arch-v32/drivers/iop_fw_load.c +++ b/arch/cris/arch-v32/drivers/iop_fw_load.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* $Id: iop_fw_load.c,v 1.4 2005/04/07 09:27:46 larsv Exp $ | 1 | /* |
2 | * | ||
3 | * Firmware loader for ETRAX FS IO-Processor | 2 | * Firmware loader for ETRAX FS IO-Processor |
4 | * | 3 | * |
5 | * Copyright (C) 2004 Axis Communications AB | 4 | * Copyright (C) 2004 Axis Communications AB |
@@ -11,12 +10,13 @@ | |||
11 | #include <linux/device.h> | 10 | #include <linux/device.h> |
12 | #include <linux/firmware.h> | 11 | #include <linux/firmware.h> |
13 | 12 | ||
14 | #include <asm/arch/hwregs/reg_map.h> | 13 | #include <hwregs/reg_rdwr.h> |
15 | #include <asm/arch/hwregs/iop/iop_reg_space.h> | 14 | #include <hwregs/reg_map.h> |
16 | #include <asm/arch/hwregs/iop/iop_mpu_macros.h> | 15 | #include <hwregs/iop/iop_reg_space.h> |
17 | #include <asm/arch/hwregs/iop/iop_mpu_defs.h> | 16 | #include <hwregs/iop/iop_mpu_macros.h> |
18 | #include <asm/arch/hwregs/iop/iop_spu_defs.h> | 17 | #include <hwregs/iop/iop_mpu_defs.h> |
19 | #include <asm/arch/hwregs/iop/iop_sw_cpu_defs.h> | 18 | #include <hwregs/iop/iop_spu_defs.h> |
19 | #include <hwregs/iop/iop_sw_cpu_defs.h> | ||
20 | 20 | ||
21 | #define IOP_TIMEOUT 100 | 21 | #define IOP_TIMEOUT 100 |
22 | 22 | ||
diff --git a/arch/cris/arch-v32/drivers/mach-a3/Makefile b/arch/cris/arch-v32/drivers/mach-a3/Makefile new file mode 100644 index 000000000000..5c6d2a2a080e --- /dev/null +++ b/arch/cris/arch-v32/drivers/mach-a3/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for Etrax-specific drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o | ||
6 | obj-$(CONFIG_ETRAX_GPIO) += gpio.o | ||
diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c new file mode 100644 index 000000000000..de107dad9f4f --- /dev/null +++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c | |||
@@ -0,0 +1,984 @@ | |||
1 | /* | ||
2 | * Artec-3 general port I/O device | ||
3 | * | ||
4 | * Copyright (c) 2007 Axis Communications AB | ||
5 | * | ||
6 | * Authors: Bjorn Wesen (initial version) | ||
7 | * Ola Knutsson (LED handling) | ||
8 | * Johan Adolfsson (read/set directions, write, port G, | ||
9 | * port to ETRAX FS. | ||
10 | * Ricard Wanderlof (PWM for Artpec-3) | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/fs.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/poll.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | |||
27 | #include <asm/etraxgpio.h> | ||
28 | #include <hwregs/reg_map.h> | ||
29 | #include <hwregs/reg_rdwr.h> | ||
30 | #include <hwregs/gio_defs.h> | ||
31 | #include <hwregs/intr_vect_defs.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/system.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/arch/mach/pinmux.h> | ||
36 | |||
37 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
38 | #include "../i2c.h" | ||
39 | |||
40 | #define VIRT_I2C_ADDR 0x40 | ||
41 | #endif | ||
42 | |||
43 | /* The following gio ports on ARTPEC-3 is available: | ||
44 | * pa 32 bits | ||
45 | * pb 32 bits | ||
46 | * pc 16 bits | ||
47 | * each port has a rw_px_dout, r_px_din and rw_px_oe register. | ||
48 | */ | ||
49 | |||
50 | #define GPIO_MAJOR 120 /* experimental MAJOR number */ | ||
51 | |||
52 | #define I2C_INTERRUPT_BITS 0x300 /* i2c0_done and i2c1_done bits */ | ||
53 | |||
54 | #define D(x) | ||
55 | |||
56 | #if 0 | ||
57 | static int dp_cnt; | ||
58 | #define DP(x) \ | ||
59 | do { \ | ||
60 | dp_cnt++; \ | ||
61 | if (dp_cnt % 1000 == 0) \ | ||
62 | x; \ | ||
63 | } while (0) | ||
64 | #else | ||
65 | #define DP(x) | ||
66 | #endif | ||
67 | |||
68 | static char gpio_name[] = "etrax gpio"; | ||
69 | |||
70 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
71 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, | ||
72 | unsigned long arg); | ||
73 | #endif | ||
74 | static int gpio_ioctl(struct inode *inode, struct file *file, | ||
75 | unsigned int cmd, unsigned long arg); | ||
76 | static ssize_t gpio_write(struct file *file, const char __user *buf, | ||
77 | size_t count, loff_t *off); | ||
78 | static int gpio_open(struct inode *inode, struct file *filp); | ||
79 | static int gpio_release(struct inode *inode, struct file *filp); | ||
80 | static unsigned int gpio_poll(struct file *filp, | ||
81 | struct poll_table_struct *wait); | ||
82 | |||
83 | /* private data per open() of this driver */ | ||
84 | |||
85 | struct gpio_private { | ||
86 | struct gpio_private *next; | ||
87 | /* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */ | ||
88 | unsigned char clk_mask; | ||
89 | unsigned char data_mask; | ||
90 | unsigned char write_msb; | ||
91 | unsigned char pad1; | ||
92 | /* These fields are generic */ | ||
93 | unsigned long highalarm, lowalarm; | ||
94 | wait_queue_head_t alarm_wq; | ||
95 | int minor; | ||
96 | }; | ||
97 | |||
98 | static void gpio_set_alarm(struct gpio_private *priv); | ||
99 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); | ||
100 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, | ||
101 | unsigned long arg); | ||
102 | |||
103 | |||
104 | /* linked list of alarms to check for */ | ||
105 | |||
106 | static struct gpio_private *alarmlist; | ||
107 | |||
108 | static int wanted_interrupts; | ||
109 | |||
110 | static DEFINE_SPINLOCK(gpio_lock); | ||
111 | |||
112 | #define NUM_PORTS (GPIO_MINOR_LAST+1) | ||
113 | #define GIO_REG_RD_ADDR(reg) \ | ||
114 | (unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) | ||
115 | #define GIO_REG_WR_ADDR(reg) \ | ||
116 | (unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg) | ||
117 | static unsigned long led_dummy; | ||
118 | static unsigned long port_d_dummy; /* Only input on Artpec-3 */ | ||
119 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
120 | static unsigned long port_e_dummy; /* Non existent on Artpec-3 */ | ||
121 | static unsigned long virtual_dummy; | ||
122 | static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; | ||
123 | static unsigned short cached_virtual_gpio_read; | ||
124 | #endif | ||
125 | |||
126 | static unsigned long *data_out[NUM_PORTS] = { | ||
127 | GIO_REG_WR_ADDR(rw_pa_dout), | ||
128 | GIO_REG_WR_ADDR(rw_pb_dout), | ||
129 | &led_dummy, | ||
130 | GIO_REG_WR_ADDR(rw_pc_dout), | ||
131 | &port_d_dummy, | ||
132 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
133 | &port_e_dummy, | ||
134 | &virtual_dummy, | ||
135 | #endif | ||
136 | }; | ||
137 | |||
138 | static unsigned long *data_in[NUM_PORTS] = { | ||
139 | GIO_REG_RD_ADDR(r_pa_din), | ||
140 | GIO_REG_RD_ADDR(r_pb_din), | ||
141 | &led_dummy, | ||
142 | GIO_REG_RD_ADDR(r_pc_din), | ||
143 | GIO_REG_RD_ADDR(r_pd_din), | ||
144 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
145 | &port_e_dummy, | ||
146 | &virtual_dummy, | ||
147 | #endif | ||
148 | }; | ||
149 | |||
150 | static unsigned long changeable_dir[NUM_PORTS] = { | ||
151 | CONFIG_ETRAX_PA_CHANGEABLE_DIR, | ||
152 | CONFIG_ETRAX_PB_CHANGEABLE_DIR, | ||
153 | 0, | ||
154 | CONFIG_ETRAX_PC_CHANGEABLE_DIR, | ||
155 | 0, | ||
156 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
157 | 0, | ||
158 | CONFIG_ETRAX_PV_CHANGEABLE_DIR, | ||
159 | #endif | ||
160 | }; | ||
161 | |||
162 | static unsigned long changeable_bits[NUM_PORTS] = { | ||
163 | CONFIG_ETRAX_PA_CHANGEABLE_BITS, | ||
164 | CONFIG_ETRAX_PB_CHANGEABLE_BITS, | ||
165 | 0, | ||
166 | CONFIG_ETRAX_PC_CHANGEABLE_BITS, | ||
167 | 0, | ||
168 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
169 | 0, | ||
170 | CONFIG_ETRAX_PV_CHANGEABLE_BITS, | ||
171 | #endif | ||
172 | }; | ||
173 | |||
174 | static unsigned long *dir_oe[NUM_PORTS] = { | ||
175 | GIO_REG_WR_ADDR(rw_pa_oe), | ||
176 | GIO_REG_WR_ADDR(rw_pb_oe), | ||
177 | &led_dummy, | ||
178 | GIO_REG_WR_ADDR(rw_pc_oe), | ||
179 | &port_d_dummy, | ||
180 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
181 | &port_e_dummy, | ||
182 | &virtual_rw_pv_oe, | ||
183 | #endif | ||
184 | }; | ||
185 | |||
186 | static void gpio_set_alarm(struct gpio_private *priv) | ||
187 | { | ||
188 | int bit; | ||
189 | int intr_cfg; | ||
190 | int mask; | ||
191 | int pins; | ||
192 | unsigned long flags; | ||
193 | |||
194 | spin_lock_irqsave(&gpio_lock, flags); | ||
195 | intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg); | ||
196 | pins = REG_RD_INT(gio, regi_gio, rw_intr_pins); | ||
197 | mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS; | ||
198 | |||
199 | for (bit = 0; bit < 32; bit++) { | ||
200 | int intr = bit % 8; | ||
201 | int pin = bit / 8; | ||
202 | if (priv->minor < GPIO_MINOR_LEDS) | ||
203 | pin += priv->minor * 4; | ||
204 | else | ||
205 | pin += (priv->minor - 1) * 4; | ||
206 | |||
207 | if (priv->highalarm & (1<<bit)) { | ||
208 | intr_cfg |= (regk_gio_hi << (intr * 3)); | ||
209 | mask |= 1 << intr; | ||
210 | wanted_interrupts = mask & 0xff; | ||
211 | pins |= pin << (intr * 4); | ||
212 | } else if (priv->lowalarm & (1<<bit)) { | ||
213 | intr_cfg |= (regk_gio_lo << (intr * 3)); | ||
214 | mask |= 1 << intr; | ||
215 | wanted_interrupts = mask & 0xff; | ||
216 | pins |= pin << (intr * 4); | ||
217 | } | ||
218 | } | ||
219 | |||
220 | REG_WR_INT(gio, regi_gio, rw_intr_cfg, intr_cfg); | ||
221 | REG_WR_INT(gio, regi_gio, rw_intr_pins, pins); | ||
222 | REG_WR_INT(gio, regi_gio, rw_intr_mask, mask); | ||
223 | |||
224 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
225 | } | ||
226 | |||
227 | static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) | ||
228 | { | ||
229 | unsigned int mask = 0; | ||
230 | struct gpio_private *priv = file->private_data; | ||
231 | unsigned long data; | ||
232 | unsigned long tmp; | ||
233 | |||
234 | if (priv->minor >= GPIO_MINOR_PWM0 && | ||
235 | priv->minor <= GPIO_MINOR_LAST_PWM) | ||
236 | return 0; | ||
237 | |||
238 | poll_wait(file, &priv->alarm_wq, wait); | ||
239 | if (priv->minor <= GPIO_MINOR_D) { | ||
240 | data = readl(data_in[priv->minor]); | ||
241 | REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts); | ||
242 | tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask); | ||
243 | tmp &= I2C_INTERRUPT_BITS; | ||
244 | tmp |= wanted_interrupts; | ||
245 | REG_WR_INT(gio, regi_gio, rw_intr_mask, tmp); | ||
246 | } else | ||
247 | return 0; | ||
248 | |||
249 | if ((data & priv->highalarm) || (~data & priv->lowalarm)) | ||
250 | mask = POLLIN|POLLRDNORM; | ||
251 | |||
252 | DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask)); | ||
253 | return mask; | ||
254 | } | ||
255 | |||
256 | static irqreturn_t gpio_interrupt(int irq, void *dev_id) | ||
257 | { | ||
258 | reg_gio_rw_intr_mask intr_mask; | ||
259 | reg_gio_r_masked_intr masked_intr; | ||
260 | reg_gio_rw_ack_intr ack_intr; | ||
261 | unsigned long flags; | ||
262 | unsigned long tmp; | ||
263 | unsigned long tmp2; | ||
264 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
265 | unsigned char enable_gpiov_ack = 0; | ||
266 | #endif | ||
267 | |||
268 | /* Find what PA interrupts are active */ | ||
269 | masked_intr = REG_RD(gio, regi_gio, r_masked_intr); | ||
270 | tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); | ||
271 | |||
272 | /* Find those that we have enabled */ | ||
273 | spin_lock_irqsave(&gpio_lock, flags); | ||
274 | tmp &= wanted_interrupts; | ||
275 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
276 | |||
277 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
278 | /* Something changed on virtual GPIO. Interrupt is acked by | ||
279 | * reading the device. | ||
280 | */ | ||
281 | if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) { | ||
282 | i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read, | ||
283 | sizeof(cached_virtual_gpio_read)); | ||
284 | enable_gpiov_ack = 1; | ||
285 | } | ||
286 | #endif | ||
287 | |||
288 | /* Ack them */ | ||
289 | ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); | ||
290 | REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); | ||
291 | |||
292 | /* Disable those interrupts.. */ | ||
293 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | ||
294 | tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); | ||
295 | tmp2 &= ~tmp; | ||
296 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
297 | /* Do not disable interrupt on virtual GPIO. Changes on virtual | ||
298 | * pins are only noticed by an interrupt. | ||
299 | */ | ||
300 | if (enable_gpiov_ack) | ||
301 | tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
302 | #endif | ||
303 | intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); | ||
304 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | ||
305 | |||
306 | return IRQ_RETVAL(tmp); | ||
307 | } | ||
308 | |||
309 | static void gpio_write_bit(unsigned long *port, unsigned char data, int bit, | ||
310 | unsigned char clk_mask, unsigned char data_mask) | ||
311 | { | ||
312 | unsigned long shadow = readl(port) & ~clk_mask; | ||
313 | writel(shadow, port); | ||
314 | if (data & 1 << bit) | ||
315 | shadow |= data_mask; | ||
316 | else | ||
317 | shadow &= ~data_mask; | ||
318 | writel(shadow, port); | ||
319 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
320 | shadow |= clk_mask; | ||
321 | writel(shadow, port); | ||
322 | } | ||
323 | |||
324 | static void gpio_write_byte(struct gpio_private *priv, unsigned long *port, | ||
325 | unsigned char data) | ||
326 | { | ||
327 | int i; | ||
328 | |||
329 | if (priv->write_msb) | ||
330 | for (i = 7; i >= 0; i--) | ||
331 | gpio_write_bit(port, data, i, priv->clk_mask, | ||
332 | priv->data_mask); | ||
333 | else | ||
334 | for (i = 0; i <= 7; i++) | ||
335 | gpio_write_bit(port, data, i, priv->clk_mask, | ||
336 | priv->data_mask); | ||
337 | } | ||
338 | |||
339 | |||
340 | static ssize_t gpio_write(struct file *file, const char __user *buf, | ||
341 | size_t count, loff_t *off) | ||
342 | { | ||
343 | struct gpio_private *priv = file->private_data; | ||
344 | unsigned long flags; | ||
345 | ssize_t retval = count; | ||
346 | /* Only bits 0-7 may be used for write operations but allow all | ||
347 | devices except leds... */ | ||
348 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
349 | if (priv->minor == GPIO_MINOR_V) | ||
350 | return -EFAULT; | ||
351 | #endif | ||
352 | if (priv->minor == GPIO_MINOR_LEDS) | ||
353 | return -EFAULT; | ||
354 | |||
355 | if (priv->minor >= GPIO_MINOR_PWM0 && | ||
356 | priv->minor <= GPIO_MINOR_LAST_PWM) | ||
357 | return -EFAULT; | ||
358 | |||
359 | if (!access_ok(VERIFY_READ, buf, count)) | ||
360 | return -EFAULT; | ||
361 | |||
362 | /* It must have been configured using the IO_CFG_WRITE_MODE */ | ||
363 | /* Perhaps a better error code? */ | ||
364 | if (priv->clk_mask == 0 || priv->data_mask == 0) | ||
365 | return -EPERM; | ||
366 | |||
367 | D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " | ||
368 | "msb: %i\n", | ||
369 | count, priv->data_mask, priv->clk_mask, priv->write_msb)); | ||
370 | |||
371 | spin_lock_irqsave(&gpio_lock, flags); | ||
372 | |||
373 | while (count--) | ||
374 | gpio_write_byte(priv, data_out[priv->minor], *buf++); | ||
375 | |||
376 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
377 | return retval; | ||
378 | } | ||
379 | |||
380 | static int gpio_open(struct inode *inode, struct file *filp) | ||
381 | { | ||
382 | struct gpio_private *priv; | ||
383 | int p = iminor(inode); | ||
384 | |||
385 | if (p > GPIO_MINOR_LAST_PWM || | ||
386 | (p > GPIO_MINOR_LAST && p < GPIO_MINOR_PWM0)) | ||
387 | return -EINVAL; | ||
388 | |||
389 | priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL); | ||
390 | |||
391 | if (!priv) | ||
392 | return -ENOMEM; | ||
393 | memset(priv, 0, sizeof(*priv)); | ||
394 | |||
395 | priv->minor = p; | ||
396 | filp->private_data = priv; | ||
397 | |||
398 | /* initialize the io/alarm struct, not for PWM ports though */ | ||
399 | if (p <= GPIO_MINOR_LAST) { | ||
400 | |||
401 | priv->clk_mask = 0; | ||
402 | priv->data_mask = 0; | ||
403 | priv->highalarm = 0; | ||
404 | priv->lowalarm = 0; | ||
405 | |||
406 | init_waitqueue_head(&priv->alarm_wq); | ||
407 | |||
408 | /* link it into our alarmlist */ | ||
409 | spin_lock_irq(&gpio_lock); | ||
410 | priv->next = alarmlist; | ||
411 | alarmlist = priv; | ||
412 | spin_unlock_irq(&gpio_lock); | ||
413 | } | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int gpio_release(struct inode *inode, struct file *filp) | ||
419 | { | ||
420 | struct gpio_private *p; | ||
421 | struct gpio_private *todel; | ||
422 | /* local copies while updating them: */ | ||
423 | unsigned long a_high, a_low; | ||
424 | |||
425 | /* prepare to free private structure */ | ||
426 | todel = filp->private_data; | ||
427 | |||
428 | /* unlink from alarmlist - only for non-PWM ports though */ | ||
429 | if (todel->minor <= GPIO_MINOR_LAST) { | ||
430 | spin_lock_irq(&gpio_lock); | ||
431 | p = alarmlist; | ||
432 | |||
433 | if (p == todel) | ||
434 | alarmlist = todel->next; | ||
435 | else { | ||
436 | while (p->next != todel) | ||
437 | p = p->next; | ||
438 | p->next = todel->next; | ||
439 | } | ||
440 | |||
441 | /* Check if there are still any alarms set */ | ||
442 | p = alarmlist; | ||
443 | a_high = 0; | ||
444 | a_low = 0; | ||
445 | while (p) { | ||
446 | if (p->minor == GPIO_MINOR_A) { | ||
447 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
448 | p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
449 | #endif | ||
450 | a_high |= p->highalarm; | ||
451 | a_low |= p->lowalarm; | ||
452 | } | ||
453 | |||
454 | p = p->next; | ||
455 | } | ||
456 | |||
457 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
458 | /* Variable 'a_low' needs to be set here again | ||
459 | * to ensure that interrupt for virtual GPIO is handled. | ||
460 | */ | ||
461 | a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
462 | #endif | ||
463 | |||
464 | spin_unlock_irq(&gpio_lock); | ||
465 | } | ||
466 | kfree(todel); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | /* Main device API. ioctl's to read/set/clear bits, as well as to | ||
472 | * set alarms to wait for using a subsequent select(). | ||
473 | */ | ||
474 | |||
475 | inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) | ||
476 | { | ||
477 | /* Set direction 0=unchanged 1=input, | ||
478 | * return mask with 1=input | ||
479 | */ | ||
480 | unsigned long flags; | ||
481 | unsigned long dir_shadow; | ||
482 | |||
483 | spin_lock_irqsave(&gpio_lock, flags); | ||
484 | |||
485 | dir_shadow = readl(dir_oe[priv->minor]) & | ||
486 | ~(arg & changeable_dir[priv->minor]); | ||
487 | writel(dir_shadow, dir_oe[priv->minor]); | ||
488 | |||
489 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
490 | |||
491 | if (priv->minor == GPIO_MINOR_C) | ||
492 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | ||
493 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
494 | else if (priv->minor == GPIO_MINOR_V) | ||
495 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | ||
496 | #endif | ||
497 | else | ||
498 | dir_shadow ^= 0xFFFFFFFF; /* PA, PB and PD 32 bits */ | ||
499 | |||
500 | return dir_shadow; | ||
501 | |||
502 | } /* setget_input */ | ||
503 | |||
504 | static inline unsigned long setget_output(struct gpio_private *priv, | ||
505 | unsigned long arg) | ||
506 | { | ||
507 | unsigned long flags; | ||
508 | unsigned long dir_shadow; | ||
509 | |||
510 | spin_lock_irqsave(&gpio_lock, flags); | ||
511 | |||
512 | dir_shadow = readl(dir_oe[priv->minor]) | | ||
513 | (arg & changeable_dir[priv->minor]); | ||
514 | writel(dir_shadow, dir_oe[priv->minor]); | ||
515 | |||
516 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
517 | return dir_shadow; | ||
518 | } /* setget_output */ | ||
519 | |||
520 | static int gpio_ioctl(struct inode *inode, struct file *file, | ||
521 | unsigned int cmd, unsigned long arg) | ||
522 | { | ||
523 | unsigned long flags; | ||
524 | unsigned long val; | ||
525 | unsigned long shadow; | ||
526 | struct gpio_private *priv = file->private_data; | ||
527 | |||
528 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) | ||
529 | return -ENOTTY; | ||
530 | |||
531 | /* Check for special ioctl handlers first */ | ||
532 | |||
533 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
534 | if (priv->minor == GPIO_MINOR_V) | ||
535 | return virtual_gpio_ioctl(file, cmd, arg); | ||
536 | #endif | ||
537 | |||
538 | if (priv->minor == GPIO_MINOR_LEDS) | ||
539 | return gpio_leds_ioctl(cmd, arg); | ||
540 | |||
541 | if (priv->minor >= GPIO_MINOR_PWM0 && | ||
542 | priv->minor <= GPIO_MINOR_LAST_PWM) | ||
543 | return gpio_pwm_ioctl(priv, cmd, arg); | ||
544 | |||
545 | switch (_IOC_NR(cmd)) { | ||
546 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | ||
547 | /* Read the port. */ | ||
548 | return readl(data_in[priv->minor]); | ||
549 | case IO_SETBITS: | ||
550 | spin_lock_irqsave(&gpio_lock, flags); | ||
551 | /* Set changeable bits with a 1 in arg. */ | ||
552 | shadow = readl(data_out[priv->minor]) | | ||
553 | (arg & changeable_bits[priv->minor]); | ||
554 | writel(shadow, data_out[priv->minor]); | ||
555 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
556 | break; | ||
557 | case IO_CLRBITS: | ||
558 | spin_lock_irqsave(&gpio_lock, flags); | ||
559 | /* Clear changeable bits with a 1 in arg. */ | ||
560 | shadow = readl(data_out[priv->minor]) & | ||
561 | ~(arg & changeable_bits[priv->minor]); | ||
562 | writel(shadow, data_out[priv->minor]); | ||
563 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
564 | break; | ||
565 | case IO_HIGHALARM: | ||
566 | /* Set alarm when bits with 1 in arg go high. */ | ||
567 | priv->highalarm |= arg; | ||
568 | gpio_set_alarm(priv); | ||
569 | break; | ||
570 | case IO_LOWALARM: | ||
571 | /* Set alarm when bits with 1 in arg go low. */ | ||
572 | priv->lowalarm |= arg; | ||
573 | gpio_set_alarm(priv); | ||
574 | break; | ||
575 | case IO_CLRALARM: | ||
576 | /* Clear alarm for bits with 1 in arg. */ | ||
577 | priv->highalarm &= ~arg; | ||
578 | priv->lowalarm &= ~arg; | ||
579 | gpio_set_alarm(priv); | ||
580 | break; | ||
581 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | ||
582 | /* Read direction 0=input 1=output */ | ||
583 | return readl(dir_oe[priv->minor]); | ||
584 | |||
585 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ | ||
586 | /* Set direction 0=unchanged 1=input, | ||
587 | * return mask with 1=input | ||
588 | */ | ||
589 | return setget_input(priv, arg); | ||
590 | |||
591 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ | ||
592 | /* Set direction 0=unchanged 1=output, | ||
593 | * return mask with 1=output | ||
594 | */ | ||
595 | return setget_output(priv, arg); | ||
596 | |||
597 | case IO_CFG_WRITE_MODE: | ||
598 | { | ||
599 | int res = -EPERM; | ||
600 | unsigned long dir_shadow, clk_mask, data_mask, write_msb; | ||
601 | |||
602 | clk_mask = arg & 0xFF; | ||
603 | data_mask = (arg >> 8) & 0xFF; | ||
604 | write_msb = (arg >> 16) & 0x01; | ||
605 | |||
606 | /* Check if we're allowed to change the bits and | ||
607 | * the direction is correct | ||
608 | */ | ||
609 | spin_lock_irqsave(&gpio_lock, flags); | ||
610 | dir_shadow = readl(dir_oe[priv->minor]); | ||
611 | if ((clk_mask & changeable_bits[priv->minor]) && | ||
612 | (data_mask & changeable_bits[priv->minor]) && | ||
613 | (clk_mask & dir_shadow) && | ||
614 | (data_mask & dir_shadow)) { | ||
615 | priv->clk_mask = clk_mask; | ||
616 | priv->data_mask = data_mask; | ||
617 | priv->write_msb = write_msb; | ||
618 | res = 0; | ||
619 | } | ||
620 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
621 | |||
622 | return res; | ||
623 | } | ||
624 | case IO_READ_INBITS: | ||
625 | /* *arg is result of reading the input pins */ | ||
626 | val = readl(data_in[priv->minor]); | ||
627 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
628 | return -EFAULT; | ||
629 | return 0; | ||
630 | case IO_READ_OUTBITS: | ||
631 | /* *arg is result of reading the output shadow */ | ||
632 | val = *data_out[priv->minor]; | ||
633 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
634 | return -EFAULT; | ||
635 | break; | ||
636 | case IO_SETGET_INPUT: | ||
637 | /* bits set in *arg is set to input, | ||
638 | * *arg updated with current input pins. | ||
639 | */ | ||
640 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) | ||
641 | return -EFAULT; | ||
642 | val = setget_input(priv, val); | ||
643 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
644 | return -EFAULT; | ||
645 | break; | ||
646 | case IO_SETGET_OUTPUT: | ||
647 | /* bits set in *arg is set to output, | ||
648 | * *arg updated with current output pins. | ||
649 | */ | ||
650 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) | ||
651 | return -EFAULT; | ||
652 | val = setget_output(priv, val); | ||
653 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
654 | return -EFAULT; | ||
655 | break; | ||
656 | default: | ||
657 | return -EINVAL; | ||
658 | } /* switch */ | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
664 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, | ||
665 | unsigned long arg) | ||
666 | { | ||
667 | unsigned long flags; | ||
668 | unsigned short val; | ||
669 | unsigned short shadow; | ||
670 | struct gpio_private *priv = file->private_data; | ||
671 | |||
672 | switch (_IOC_NR(cmd)) { | ||
673 | case IO_SETBITS: | ||
674 | spin_lock_irqsave(&gpio_lock, flags); | ||
675 | /* Set changeable bits with a 1 in arg. */ | ||
676 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
677 | shadow |= ~readl(dir_oe[priv->minor]) | | ||
678 | (arg & changeable_bits[priv->minor]); | ||
679 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
680 | spin_lock_irqrestore(&gpio_lock, flags); | ||
681 | break; | ||
682 | case IO_CLRBITS: | ||
683 | spin_lock_irqsave(&gpio_lock, flags); | ||
684 | /* Clear changeable bits with a 1 in arg. */ | ||
685 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
686 | shadow |= ~readl(dir_oe[priv->minor]) & | ||
687 | ~(arg & changeable_bits[priv->minor]); | ||
688 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
689 | spin_lock_irqrestore(&gpio_lock, flags); | ||
690 | break; | ||
691 | case IO_HIGHALARM: | ||
692 | /* Set alarm when bits with 1 in arg go high. */ | ||
693 | priv->highalarm |= arg; | ||
694 | break; | ||
695 | case IO_LOWALARM: | ||
696 | /* Set alarm when bits with 1 in arg go low. */ | ||
697 | priv->lowalarm |= arg; | ||
698 | break; | ||
699 | case IO_CLRALARM: | ||
700 | /* Clear alarm for bits with 1 in arg. */ | ||
701 | priv->highalarm &= ~arg; | ||
702 | priv->lowalarm &= ~arg; | ||
703 | break; | ||
704 | case IO_CFG_WRITE_MODE: | ||
705 | { | ||
706 | unsigned long dir_shadow; | ||
707 | dir_shadow = readl(dir_oe[priv->minor]); | ||
708 | |||
709 | priv->clk_mask = arg & 0xFF; | ||
710 | priv->data_mask = (arg >> 8) & 0xFF; | ||
711 | priv->write_msb = (arg >> 16) & 0x01; | ||
712 | /* Check if we're allowed to change the bits and | ||
713 | * the direction is correct | ||
714 | */ | ||
715 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && | ||
716 | (priv->data_mask & changeable_bits[priv->minor]) && | ||
717 | (priv->clk_mask & dir_shadow) && | ||
718 | (priv->data_mask & dir_shadow))) { | ||
719 | priv->clk_mask = 0; | ||
720 | priv->data_mask = 0; | ||
721 | return -EPERM; | ||
722 | } | ||
723 | break; | ||
724 | } | ||
725 | case IO_READ_INBITS: | ||
726 | /* *arg is result of reading the input pins */ | ||
727 | val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]); | ||
728 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
729 | return -EFAULT; | ||
730 | return 0; | ||
731 | |||
732 | case IO_READ_OUTBITS: | ||
733 | /* *arg is result of reading the output shadow */ | ||
734 | i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); | ||
735 | val &= readl(dir_oe[priv->minor]); | ||
736 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
737 | return -EFAULT; | ||
738 | break; | ||
739 | case IO_SETGET_INPUT: | ||
740 | { | ||
741 | /* bits set in *arg is set to input, | ||
742 | * *arg updated with current input pins. | ||
743 | */ | ||
744 | unsigned short input_mask = ~readl(dir_oe[priv->minor]); | ||
745 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) | ||
746 | return -EFAULT; | ||
747 | val = setget_input(priv, val); | ||
748 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
749 | return -EFAULT; | ||
750 | if ((input_mask & val) != input_mask) { | ||
751 | /* Input pins changed. All ports desired as input | ||
752 | * should be set to logic 1. | ||
753 | */ | ||
754 | unsigned short change = input_mask ^ val; | ||
755 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, | ||
756 | sizeof(shadow)); | ||
757 | shadow &= ~change; | ||
758 | shadow |= val; | ||
759 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, | ||
760 | sizeof(shadow)); | ||
761 | } | ||
762 | break; | ||
763 | } | ||
764 | case IO_SETGET_OUTPUT: | ||
765 | /* bits set in *arg is set to output, | ||
766 | * *arg updated with current output pins. | ||
767 | */ | ||
768 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) | ||
769 | return -EFAULT; | ||
770 | val = setget_output(priv, val); | ||
771 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | ||
772 | return -EFAULT; | ||
773 | break; | ||
774 | default: | ||
775 | return -EINVAL; | ||
776 | } /* switch */ | ||
777 | return 0; | ||
778 | } | ||
779 | #endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ | ||
780 | |||
781 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | ||
782 | { | ||
783 | unsigned char green; | ||
784 | unsigned char red; | ||
785 | |||
786 | switch (_IOC_NR(cmd)) { | ||
787 | case IO_LEDACTIVE_SET: | ||
788 | green = ((unsigned char) arg) & 1; | ||
789 | red = (((unsigned char) arg) >> 1) & 1; | ||
790 | CRIS_LED_ACTIVE_SET_G(green); | ||
791 | CRIS_LED_ACTIVE_SET_R(red); | ||
792 | break; | ||
793 | |||
794 | default: | ||
795 | return -EINVAL; | ||
796 | } /* switch */ | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static int gpio_pwm_set_mode(unsigned long arg, int pwm_port) | ||
802 | { | ||
803 | int pinmux_pwm = pinmux_pwm0 + pwm_port; | ||
804 | int mode; | ||
805 | reg_gio_rw_pwm0_ctrl rw_pwm_ctrl = { | ||
806 | .ccd_val = 0, | ||
807 | .ccd_override = regk_gio_no, | ||
808 | .mode = regk_gio_no | ||
809 | }; | ||
810 | int allocstatus; | ||
811 | |||
812 | if (get_user(mode, &((struct io_pwm_set_mode *) arg)->mode)) | ||
813 | return -EFAULT; | ||
814 | rw_pwm_ctrl.mode = mode; | ||
815 | if (mode != PWM_OFF) | ||
816 | allocstatus = crisv32_pinmux_alloc_fixed(pinmux_pwm); | ||
817 | else | ||
818 | allocstatus = crisv32_pinmux_dealloc_fixed(pinmux_pwm); | ||
819 | if (allocstatus) | ||
820 | return allocstatus; | ||
821 | REG_WRITE(reg_gio_rw_pwm0_ctrl, REG_ADDR(gio, regi_gio, rw_pwm0_ctrl) + | ||
822 | 12 * pwm_port, rw_pwm_ctrl); | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static int gpio_pwm_set_period(unsigned long arg, int pwm_port) | ||
827 | { | ||
828 | struct io_pwm_set_period periods; | ||
829 | reg_gio_rw_pwm0_var rw_pwm_widths; | ||
830 | |||
831 | if (copy_from_user(&periods, (void __user *)arg, sizeof(periods))) | ||
832 | return -EFAULT; | ||
833 | if (periods.lo > 8191 || periods.hi > 8191) | ||
834 | return -EINVAL; | ||
835 | rw_pwm_widths.lo = periods.lo; | ||
836 | rw_pwm_widths.hi = periods.hi; | ||
837 | REG_WRITE(reg_gio_rw_pwm0_var, REG_ADDR(gio, regi_gio, rw_pwm0_var) + | ||
838 | 12 * pwm_port, rw_pwm_widths); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | static int gpio_pwm_set_duty(unsigned long arg, int pwm_port) | ||
843 | { | ||
844 | unsigned int duty; | ||
845 | reg_gio_rw_pwm0_data rw_pwm_duty; | ||
846 | |||
847 | if (get_user(duty, &((struct io_pwm_set_duty *) arg)->duty)) | ||
848 | return -EFAULT; | ||
849 | if (duty > 255) | ||
850 | return -EINVAL; | ||
851 | rw_pwm_duty.data = duty; | ||
852 | REG_WRITE(reg_gio_rw_pwm0_data, REG_ADDR(gio, regi_gio, rw_pwm0_data) + | ||
853 | 12 * pwm_port, rw_pwm_duty); | ||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, | ||
858 | unsigned long arg) | ||
859 | { | ||
860 | int pwm_port = priv->minor - GPIO_MINOR_PWM0; | ||
861 | |||
862 | switch (_IOC_NR(cmd)) { | ||
863 | case IO_PWM_SET_MODE: | ||
864 | return gpio_pwm_set_mode(arg, pwm_port); | ||
865 | case IO_PWM_SET_PERIOD: | ||
866 | return gpio_pwm_set_period(arg, pwm_port); | ||
867 | case IO_PWM_SET_DUTY: | ||
868 | return gpio_pwm_set_duty(arg, pwm_port); | ||
869 | default: | ||
870 | return -EINVAL; | ||
871 | } | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | static const struct file_operations gpio_fops = { | ||
876 | .owner = THIS_MODULE, | ||
877 | .poll = gpio_poll, | ||
878 | .ioctl = gpio_ioctl, | ||
879 | .write = gpio_write, | ||
880 | .open = gpio_open, | ||
881 | .release = gpio_release, | ||
882 | }; | ||
883 | |||
884 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
885 | static void __init virtual_gpio_init(void) | ||
886 | { | ||
887 | reg_gio_rw_intr_cfg intr_cfg; | ||
888 | reg_gio_rw_intr_mask intr_mask; | ||
889 | unsigned short shadow; | ||
890 | |||
891 | shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */ | ||
892 | shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT; | ||
893 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
894 | |||
895 | /* Set interrupt mask and on what state the interrupt shall trigger. | ||
896 | * For virtual gpio the interrupt shall trigger on logic '0'. | ||
897 | */ | ||
898 | intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); | ||
899 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | ||
900 | |||
901 | switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) { | ||
902 | case 0: | ||
903 | intr_cfg.pa0 = regk_gio_lo; | ||
904 | intr_mask.pa0 = regk_gio_yes; | ||
905 | break; | ||
906 | case 1: | ||
907 | intr_cfg.pa1 = regk_gio_lo; | ||
908 | intr_mask.pa1 = regk_gio_yes; | ||
909 | break; | ||
910 | case 2: | ||
911 | intr_cfg.pa2 = regk_gio_lo; | ||
912 | intr_mask.pa2 = regk_gio_yes; | ||
913 | break; | ||
914 | case 3: | ||
915 | intr_cfg.pa3 = regk_gio_lo; | ||
916 | intr_mask.pa3 = regk_gio_yes; | ||
917 | break; | ||
918 | case 4: | ||
919 | intr_cfg.pa4 = regk_gio_lo; | ||
920 | intr_mask.pa4 = regk_gio_yes; | ||
921 | break; | ||
922 | case 5: | ||
923 | intr_cfg.pa5 = regk_gio_lo; | ||
924 | intr_mask.pa5 = regk_gio_yes; | ||
925 | break; | ||
926 | case 6: | ||
927 | intr_cfg.pa6 = regk_gio_lo; | ||
928 | intr_mask.pa6 = regk_gio_yes; | ||
929 | break; | ||
930 | case 7: | ||
931 | intr_cfg.pa7 = regk_gio_lo; | ||
932 | intr_mask.pa7 = regk_gio_yes; | ||
933 | break; | ||
934 | } | ||
935 | |||
936 | REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); | ||
937 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | ||
938 | } | ||
939 | #endif | ||
940 | |||
941 | /* main driver initialization routine, called from mem.c */ | ||
942 | |||
943 | static int __init gpio_init(void) | ||
944 | { | ||
945 | int res; | ||
946 | |||
947 | printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 " | ||
948 | "Axis Communications AB\n"); | ||
949 | |||
950 | /* do the formalities */ | ||
951 | |||
952 | res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); | ||
953 | if (res < 0) { | ||
954 | printk(KERN_ERR "gpio: couldn't get a major number.\n"); | ||
955 | return res; | ||
956 | } | ||
957 | |||
958 | /* Clear all leds */ | ||
959 | CRIS_LED_NETWORK_GRP0_SET(0); | ||
960 | CRIS_LED_NETWORK_GRP1_SET(0); | ||
961 | CRIS_LED_ACTIVE_SET(0); | ||
962 | CRIS_LED_DISK_READ(0); | ||
963 | CRIS_LED_DISK_WRITE(0); | ||
964 | |||
965 | int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, | ||
966 | IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist); | ||
967 | if (res2) { | ||
968 | printk(KERN_ERR "err: irq for gpio\n"); | ||
969 | return res2; | ||
970 | } | ||
971 | |||
972 | /* No IRQs by default. */ | ||
973 | REG_WR_INT(gio, regi_gio, rw_intr_pins, 0); | ||
974 | |||
975 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
976 | virtual_gpio_init(); | ||
977 | #endif | ||
978 | |||
979 | return res; | ||
980 | } | ||
981 | |||
982 | /* this makes sure that gpio_init is called during kernel boot */ | ||
983 | |||
984 | module_init(gpio_init); | ||
diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c new file mode 100644 index 000000000000..01ed0be2d0d1 --- /dev/null +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * arch/cris/arch-v32/drivers/nandflash.c | ||
3 | * | ||
4 | * Copyright (c) 2007 | ||
5 | * | ||
6 | * Derived from drivers/mtd/nand/spia.c | ||
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | ||
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 | |||
15 | #include <linux/slab.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/mtd/mtd.h> | ||
19 | #include <linux/mtd/nand.h> | ||
20 | #include <linux/mtd/partitions.h> | ||
21 | #include <asm/arch/memmap.h> | ||
22 | #include <hwregs/reg_map.h> | ||
23 | #include <hwregs/reg_rdwr.h> | ||
24 | #include <hwregs/pio_defs.h> | ||
25 | #include <pinmux.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #define MANUAL_ALE_CLE_CONTROL 1 | ||
29 | |||
30 | #define regf_ALE a0 | ||
31 | #define regf_CLE a1 | ||
32 | #define regf_NCE ce0_n | ||
33 | |||
34 | #define CLE_BIT 10 | ||
35 | #define ALE_BIT 11 | ||
36 | #define CE_BIT 12 | ||
37 | |||
38 | struct mtd_info_wrapper { | ||
39 | struct mtd_info info; | ||
40 | struct nand_chip chip; | ||
41 | }; | ||
42 | |||
43 | /* Bitmask for control pins */ | ||
44 | #define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) | ||
45 | |||
46 | static struct mtd_info *crisv32_mtd; | ||
47 | /* | ||
48 | * hardware specific access to control-lines | ||
49 | */ | ||
50 | static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, | ||
51 | unsigned int ctrl) | ||
52 | { | ||
53 | unsigned long flags; | ||
54 | reg_pio_rw_dout dout; | ||
55 | struct nand_chip *this = mtd->priv; | ||
56 | |||
57 | local_irq_save(flags); | ||
58 | |||
59 | /* control bits change */ | ||
60 | if (ctrl & NAND_CTRL_CHANGE) { | ||
61 | dout = REG_RD(pio, regi_pio, rw_dout); | ||
62 | dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1; | ||
63 | |||
64 | #if !MANUAL_ALE_CLE_CONTROL | ||
65 | if (ctrl & NAND_ALE) { | ||
66 | /* A0 = ALE high */ | ||
67 | this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, | ||
68 | regi_pio, rw_io_access1); | ||
69 | } else if (ctrl & NAND_CLE) { | ||
70 | /* A1 = CLE high */ | ||
71 | this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, | ||
72 | regi_pio, rw_io_access2); | ||
73 | } else { | ||
74 | /* A1 = CLE and A0 = ALE low */ | ||
75 | this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, | ||
76 | regi_pio, rw_io_access0); | ||
77 | } | ||
78 | #else | ||
79 | |||
80 | dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0; | ||
81 | dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0; | ||
82 | #endif | ||
83 | REG_WR(pio, regi_pio, rw_dout, dout); | ||
84 | } | ||
85 | |||
86 | /* command to chip */ | ||
87 | if (cmd != NAND_CMD_NONE) | ||
88 | writeb(cmd, this->IO_ADDR_W); | ||
89 | |||
90 | local_irq_restore(flags); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * read device ready pin | ||
95 | */ | ||
96 | static int crisv32_device_ready(struct mtd_info *mtd) | ||
97 | { | ||
98 | reg_pio_r_din din = REG_RD(pio, regi_pio, r_din); | ||
99 | return din.rdy; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Main initialization routine | ||
104 | */ | ||
105 | struct mtd_info *__init crisv32_nand_flash_probe(void) | ||
106 | { | ||
107 | void __iomem *read_cs; | ||
108 | void __iomem *write_cs; | ||
109 | |||
110 | struct mtd_info_wrapper *wrapper; | ||
111 | struct nand_chip *this; | ||
112 | int err = 0; | ||
113 | |||
114 | reg_pio_rw_man_ctrl man_ctrl = { | ||
115 | .regf_NCE = regk_pio_yes, | ||
116 | #if MANUAL_ALE_CLE_CONTROL | ||
117 | .regf_ALE = regk_pio_yes, | ||
118 | .regf_CLE = regk_pio_yes | ||
119 | #endif | ||
120 | }; | ||
121 | reg_pio_rw_oe oe = { | ||
122 | .regf_NCE = regk_pio_yes, | ||
123 | #if MANUAL_ALE_CLE_CONTROL | ||
124 | .regf_ALE = regk_pio_yes, | ||
125 | .regf_CLE = regk_pio_yes | ||
126 | #endif | ||
127 | }; | ||
128 | reg_pio_rw_dout dout = { .regf_NCE = 1 }; | ||
129 | |||
130 | /* Allocate pio pins to pio */ | ||
131 | crisv32_pinmux_alloc_fixed(pinmux_pio); | ||
132 | /* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */ | ||
133 | REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl); | ||
134 | REG_WR(pio, regi_pio, rw_dout, dout); | ||
135 | REG_WR(pio, regi_pio, rw_oe, oe); | ||
136 | |||
137 | /* Allocate memory for MTD device structure and private data */ | ||
138 | wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); | ||
139 | if (!wrapper) { | ||
140 | printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " | ||
141 | "device structure.\n"); | ||
142 | err = -ENOMEM; | ||
143 | return NULL; | ||
144 | } | ||
145 | |||
146 | read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio, | ||
147 | rw_io_access0); | ||
148 | |||
149 | /* Get pointer to private data */ | ||
150 | this = &wrapper->chip; | ||
151 | crisv32_mtd = &wrapper->info; | ||
152 | |||
153 | /* Link the private data with the MTD structure */ | ||
154 | crisv32_mtd->priv = this; | ||
155 | |||
156 | /* Set address of NAND IO lines */ | ||
157 | this->IO_ADDR_R = read_cs; | ||
158 | this->IO_ADDR_W = write_cs; | ||
159 | this->cmd_ctrl = crisv32_hwcontrol; | ||
160 | this->dev_ready = crisv32_device_ready; | ||
161 | /* 20 us command delay time */ | ||
162 | this->chip_delay = 20; | ||
163 | this->ecc.mode = NAND_ECC_SOFT; | ||
164 | |||
165 | /* Enable the following for a flash based bad block table */ | ||
166 | /* this->options = NAND_USE_FLASH_BBT; */ | ||
167 | |||
168 | /* Scan to find existance of the device */ | ||
169 | if (nand_scan(crisv32_mtd, 1)) { | ||
170 | err = -ENXIO; | ||
171 | goto out_mtd; | ||
172 | } | ||
173 | |||
174 | return crisv32_mtd; | ||
175 | |||
176 | out_mtd: | ||
177 | kfree(wrapper); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
diff --git a/arch/cris/arch-v32/drivers/mach-fs/Makefile b/arch/cris/arch-v32/drivers/mach-fs/Makefile new file mode 100644 index 000000000000..5c6d2a2a080e --- /dev/null +++ b/arch/cris/arch-v32/drivers/mach-fs/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for Etrax-specific drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o | ||
6 | obj-$(CONFIG_ETRAX_GPIO) += gpio.o | ||
diff --git a/arch/cris/arch-v32/drivers/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c index d82c5c561135..7863fd4efc2b 100644 --- a/arch/cris/arch-v32/drivers/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c | |||
@@ -1,68 +1,15 @@ | |||
1 | /* $Id: gpio.c,v 1.16 2005/06/19 17:06:49 starvik Exp $ | 1 | /* |
2 | * | ||
3 | * ETRAX CRISv32 general port I/O device | 2 | * ETRAX CRISv32 general port I/O device |
4 | * | 3 | * |
5 | * Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB | 4 | * Copyright (c) 1999-2006 Axis Communications AB |
6 | * | 5 | * |
7 | * Authors: Bjorn Wesen (initial version) | 6 | * Authors: Bjorn Wesen (initial version) |
8 | * Ola Knutsson (LED handling) | 7 | * Ola Knutsson (LED handling) |
9 | * Johan Adolfsson (read/set directions, write, port G, | 8 | * Johan Adolfsson (read/set directions, write, port G, |
10 | * port to ETRAX FS. | 9 | * port to ETRAX FS. |
11 | * | 10 | * |
12 | * $Log: gpio.c,v $ | ||
13 | * Revision 1.16 2005/06/19 17:06:49 starvik | ||
14 | * Merge of Linux 2.6.12. | ||
15 | * | ||
16 | * Revision 1.15 2005/05/25 08:22:20 starvik | ||
17 | * Changed GPIO port order to fit packages/devices/axis-2.4. | ||
18 | * | ||
19 | * Revision 1.14 2005/04/24 18:35:08 starvik | ||
20 | * Updated with final register headers. | ||
21 | * | ||
22 | * Revision 1.13 2005/03/15 15:43:00 starvik | ||
23 | * dev_id needs to be supplied for shared IRQs. | ||
24 | * | ||
25 | * Revision 1.12 2005/03/10 17:12:00 starvik | ||
26 | * Protect alarm list with spinlock. | ||
27 | * | ||
28 | * Revision 1.11 2005/01/05 06:08:59 starvik | ||
29 | * No need to do local_irq_disable after local_irq_save. | ||
30 | * | ||
31 | * Revision 1.10 2004/11/19 08:38:31 starvik | ||
32 | * Removed old crap. | ||
33 | * | ||
34 | * Revision 1.9 2004/05/14 07:58:02 starvik | ||
35 | * Merge of changes from 2.4 | ||
36 | * | ||
37 | * Revision 1.8 2003/09/11 07:29:50 starvik | ||
38 | * Merge of Linux 2.6.0-test5 | ||
39 | * | ||
40 | * Revision 1.7 2003/07/10 13:25:46 starvik | ||
41 | * Compiles for 2.5.74 | ||
42 | * Lindented ethernet.c | ||
43 | * | ||
44 | * Revision 1.6 2003/07/04 08:27:46 starvik | ||
45 | * Merge of Linux 2.5.74 | ||
46 | * | ||
47 | * Revision 1.5 2003/06/10 08:26:37 johana | ||
48 | * Etrax -> ETRAX CRISv32 | ||
49 | * | ||
50 | * Revision 1.4 2003/06/05 14:22:48 johana | ||
51 | * Initialise some_alarms. | ||
52 | * | ||
53 | * Revision 1.3 2003/06/05 10:15:46 johana | ||
54 | * New INTR_VECT macros. | ||
55 | * Enable interrupts in global config. | ||
56 | * | ||
57 | * Revision 1.2 2003/06/03 15:52:50 johana | ||
58 | * Initial CRIS v32 version. | ||
59 | * | ||
60 | * Revision 1.1 2003/06/03 08:53:15 johana | ||
61 | * Copy of os/lx25/arch/cris/arch-v10/drivers/gpio.c version 1.7. | ||
62 | * | ||
63 | */ | 11 | */ |
64 | 12 | ||
65 | |||
66 | #include <linux/module.h> | 13 | #include <linux/module.h> |
67 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
68 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
@@ -77,14 +24,20 @@ | |||
77 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
78 | 25 | ||
79 | #include <asm/etraxgpio.h> | 26 | #include <asm/etraxgpio.h> |
80 | #include <asm/arch/hwregs/reg_map.h> | 27 | #include <hwregs/reg_map.h> |
81 | #include <asm/arch/hwregs/reg_rdwr.h> | 28 | #include <hwregs/reg_rdwr.h> |
82 | #include <asm/arch/hwregs/gio_defs.h> | 29 | #include <hwregs/gio_defs.h> |
83 | #include <asm/arch/hwregs/intr_vect_defs.h> | 30 | #include <hwregs/intr_vect_defs.h> |
84 | #include <asm/io.h> | 31 | #include <asm/io.h> |
85 | #include <asm/system.h> | 32 | #include <asm/system.h> |
86 | #include <asm/irq.h> | 33 | #include <asm/irq.h> |
87 | 34 | ||
35 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
36 | #include "../i2c.h" | ||
37 | |||
38 | #define VIRT_I2C_ADDR 0x40 | ||
39 | #endif | ||
40 | |||
88 | /* The following gio ports on ETRAX FS is available: | 41 | /* The following gio ports on ETRAX FS is available: |
89 | * pa 8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge | 42 | * pa 8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge |
90 | * pb 18 bits | 43 | * pb 18 bits |
@@ -100,7 +53,12 @@ | |||
100 | 53 | ||
101 | #if 0 | 54 | #if 0 |
102 | static int dp_cnt; | 55 | static int dp_cnt; |
103 | #define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0) | 56 | #define DP(x) \ |
57 | do { \ | ||
58 | dp_cnt++; \ | ||
59 | if (dp_cnt % 1000 == 0) \ | ||
60 | x; \ | ||
61 | } while (0) | ||
104 | #else | 62 | #else |
105 | #define DP(x) | 63 | #define DP(x) |
106 | #endif | 64 | #endif |
@@ -111,13 +69,18 @@ static char gpio_name[] = "etrax gpio"; | |||
111 | static wait_queue_head_t *gpio_wq; | 69 | static wait_queue_head_t *gpio_wq; |
112 | #endif | 70 | #endif |
113 | 71 | ||
72 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
73 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, | ||
74 | unsigned long arg); | ||
75 | #endif | ||
114 | static int gpio_ioctl(struct inode *inode, struct file *file, | 76 | static int gpio_ioctl(struct inode *inode, struct file *file, |
115 | unsigned int cmd, unsigned long arg); | 77 | unsigned int cmd, unsigned long arg); |
116 | static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | 78 | static ssize_t gpio_write(struct file *file, const char *buf, size_t count, |
117 | loff_t *off); | 79 | loff_t *off); |
118 | static int gpio_open(struct inode *inode, struct file *filp); | 80 | static int gpio_open(struct inode *inode, struct file *filp); |
119 | static int gpio_release(struct inode *inode, struct file *filp); | 81 | static int gpio_release(struct inode *inode, struct file *filp); |
120 | static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); | 82 | static unsigned int gpio_poll(struct file *filp, |
83 | struct poll_table_struct *wait); | ||
121 | 84 | ||
122 | /* private data per open() of this driver */ | 85 | /* private data per open() of this driver */ |
123 | 86 | ||
@@ -136,18 +99,25 @@ struct gpio_private { | |||
136 | 99 | ||
137 | /* linked list of alarms to check for */ | 100 | /* linked list of alarms to check for */ |
138 | 101 | ||
139 | static struct gpio_private *alarmlist = 0; | 102 | static struct gpio_private *alarmlist; |
140 | 103 | ||
141 | static int gpio_some_alarms = 0; /* Set if someone uses alarm */ | 104 | static int gpio_some_alarms; /* Set if someone uses alarm */ |
142 | static unsigned long gpio_pa_high_alarms = 0; | 105 | static unsigned long gpio_pa_high_alarms; |
143 | static unsigned long gpio_pa_low_alarms = 0; | 106 | static unsigned long gpio_pa_low_alarms; |
144 | 107 | ||
145 | static DEFINE_SPINLOCK(alarm_lock); | 108 | static DEFINE_SPINLOCK(alarm_lock); |
146 | 109 | ||
147 | #define NUM_PORTS (GPIO_MINOR_LAST+1) | 110 | #define NUM_PORTS (GPIO_MINOR_LAST+1) |
148 | #define GIO_REG_RD_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg ) | 111 | #define GIO_REG_RD_ADDR(reg) \ |
149 | #define GIO_REG_WR_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg ) | 112 | (volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) |
113 | #define GIO_REG_WR_ADDR(reg) \ | ||
114 | (volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) | ||
150 | unsigned long led_dummy; | 115 | unsigned long led_dummy; |
116 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
117 | static unsigned long virtual_dummy; | ||
118 | static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; | ||
119 | static unsigned short cached_virtual_gpio_read; | ||
120 | #endif | ||
151 | 121 | ||
152 | static volatile unsigned long *data_out[NUM_PORTS] = { | 122 | static volatile unsigned long *data_out[NUM_PORTS] = { |
153 | GIO_REG_WR_ADDR(rw_pa_dout), | 123 | GIO_REG_WR_ADDR(rw_pa_dout), |
@@ -156,6 +126,9 @@ static volatile unsigned long *data_out[NUM_PORTS] = { | |||
156 | GIO_REG_WR_ADDR(rw_pc_dout), | 126 | GIO_REG_WR_ADDR(rw_pc_dout), |
157 | GIO_REG_WR_ADDR(rw_pd_dout), | 127 | GIO_REG_WR_ADDR(rw_pd_dout), |
158 | GIO_REG_WR_ADDR(rw_pe_dout), | 128 | GIO_REG_WR_ADDR(rw_pe_dout), |
129 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
130 | &virtual_dummy, | ||
131 | #endif | ||
159 | }; | 132 | }; |
160 | 133 | ||
161 | static volatile unsigned long *data_in[NUM_PORTS] = { | 134 | static volatile unsigned long *data_in[NUM_PORTS] = { |
@@ -165,6 +138,9 @@ static volatile unsigned long *data_in[NUM_PORTS] = { | |||
165 | GIO_REG_RD_ADDR(r_pc_din), | 138 | GIO_REG_RD_ADDR(r_pc_din), |
166 | GIO_REG_RD_ADDR(r_pd_din), | 139 | GIO_REG_RD_ADDR(r_pd_din), |
167 | GIO_REG_RD_ADDR(r_pe_din), | 140 | GIO_REG_RD_ADDR(r_pe_din), |
141 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
142 | &virtual_dummy, | ||
143 | #endif | ||
168 | }; | 144 | }; |
169 | 145 | ||
170 | static unsigned long changeable_dir[NUM_PORTS] = { | 146 | static unsigned long changeable_dir[NUM_PORTS] = { |
@@ -174,6 +150,9 @@ static unsigned long changeable_dir[NUM_PORTS] = { | |||
174 | CONFIG_ETRAX_PC_CHANGEABLE_DIR, | 150 | CONFIG_ETRAX_PC_CHANGEABLE_DIR, |
175 | CONFIG_ETRAX_PD_CHANGEABLE_DIR, | 151 | CONFIG_ETRAX_PD_CHANGEABLE_DIR, |
176 | CONFIG_ETRAX_PE_CHANGEABLE_DIR, | 152 | CONFIG_ETRAX_PE_CHANGEABLE_DIR, |
153 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
154 | CONFIG_ETRAX_PV_CHANGEABLE_DIR, | ||
155 | #endif | ||
177 | }; | 156 | }; |
178 | 157 | ||
179 | static unsigned long changeable_bits[NUM_PORTS] = { | 158 | static unsigned long changeable_bits[NUM_PORTS] = { |
@@ -183,6 +162,9 @@ static unsigned long changeable_bits[NUM_PORTS] = { | |||
183 | CONFIG_ETRAX_PC_CHANGEABLE_BITS, | 162 | CONFIG_ETRAX_PC_CHANGEABLE_BITS, |
184 | CONFIG_ETRAX_PD_CHANGEABLE_BITS, | 163 | CONFIG_ETRAX_PD_CHANGEABLE_BITS, |
185 | CONFIG_ETRAX_PE_CHANGEABLE_BITS, | 164 | CONFIG_ETRAX_PE_CHANGEABLE_BITS, |
165 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
166 | CONFIG_ETRAX_PV_CHANGEABLE_BITS, | ||
167 | #endif | ||
186 | }; | 168 | }; |
187 | 169 | ||
188 | static volatile unsigned long *dir_oe[NUM_PORTS] = { | 170 | static volatile unsigned long *dir_oe[NUM_PORTS] = { |
@@ -192,13 +174,14 @@ static volatile unsigned long *dir_oe[NUM_PORTS] = { | |||
192 | GIO_REG_WR_ADDR(rw_pc_oe), | 174 | GIO_REG_WR_ADDR(rw_pc_oe), |
193 | GIO_REG_WR_ADDR(rw_pd_oe), | 175 | GIO_REG_WR_ADDR(rw_pd_oe), |
194 | GIO_REG_WR_ADDR(rw_pe_oe), | 176 | GIO_REG_WR_ADDR(rw_pe_oe), |
177 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
178 | &virtual_rw_pv_oe, | ||
179 | #endif | ||
195 | }; | 180 | }; |
196 | 181 | ||
197 | 182 | ||
198 | 183 | ||
199 | static unsigned int | 184 | static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) |
200 | gpio_poll(struct file *file, | ||
201 | poll_table *wait) | ||
202 | { | 185 | { |
203 | unsigned int mask = 0; | 186 | unsigned int mask = 0; |
204 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 187 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
@@ -210,65 +193,50 @@ gpio_poll(struct file *file, | |||
210 | unsigned long flags; | 193 | unsigned long flags; |
211 | 194 | ||
212 | local_irq_save(flags); | 195 | local_irq_save(flags); |
213 | data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, REG_RD(gio, regi_gio, r_pa_din)); | 196 | data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, |
197 | REG_RD(gio, regi_gio, r_pa_din)); | ||
214 | /* PA has support for interrupt | 198 | /* PA has support for interrupt |
215 | * lets activate high for those low and with highalarm set | 199 | * lets activate high for those low and with highalarm set |
216 | */ | 200 | */ |
217 | intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); | 201 | intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); |
218 | 202 | ||
219 | tmp = ~data & priv->highalarm & 0xFF; | 203 | tmp = ~data & priv->highalarm & 0xFF; |
220 | if (tmp & (1 << 0)) { | 204 | if (tmp & (1 << 0)) |
221 | intr_cfg.pa0 = regk_gio_hi; | 205 | intr_cfg.pa0 = regk_gio_hi; |
222 | } | 206 | if (tmp & (1 << 1)) |
223 | if (tmp & (1 << 1)) { | ||
224 | intr_cfg.pa1 = regk_gio_hi; | 207 | intr_cfg.pa1 = regk_gio_hi; |
225 | } | 208 | if (tmp & (1 << 2)) |
226 | if (tmp & (1 << 2)) { | ||
227 | intr_cfg.pa2 = regk_gio_hi; | 209 | intr_cfg.pa2 = regk_gio_hi; |
228 | } | 210 | if (tmp & (1 << 3)) |
229 | if (tmp & (1 << 3)) { | ||
230 | intr_cfg.pa3 = regk_gio_hi; | 211 | intr_cfg.pa3 = regk_gio_hi; |
231 | } | 212 | if (tmp & (1 << 4)) |
232 | if (tmp & (1 << 4)) { | ||
233 | intr_cfg.pa4 = regk_gio_hi; | 213 | intr_cfg.pa4 = regk_gio_hi; |
234 | } | 214 | if (tmp & (1 << 5)) |
235 | if (tmp & (1 << 5)) { | ||
236 | intr_cfg.pa5 = regk_gio_hi; | 215 | intr_cfg.pa5 = regk_gio_hi; |
237 | } | 216 | if (tmp & (1 << 6)) |
238 | if (tmp & (1 << 6)) { | ||
239 | intr_cfg.pa6 = regk_gio_hi; | 217 | intr_cfg.pa6 = regk_gio_hi; |
240 | } | 218 | if (tmp & (1 << 7)) |
241 | if (tmp & (1 << 7)) { | ||
242 | intr_cfg.pa7 = regk_gio_hi; | 219 | intr_cfg.pa7 = regk_gio_hi; |
243 | } | ||
244 | /* | 220 | /* |
245 | * lets activate low for those high and with lowalarm set | 221 | * lets activate low for those high and with lowalarm set |
246 | */ | 222 | */ |
247 | tmp = data & priv->lowalarm & 0xFF; | 223 | tmp = data & priv->lowalarm & 0xFF; |
248 | if (tmp & (1 << 0)) { | 224 | if (tmp & (1 << 0)) |
249 | intr_cfg.pa0 = regk_gio_lo; | 225 | intr_cfg.pa0 = regk_gio_lo; |
250 | } | 226 | if (tmp & (1 << 1)) |
251 | if (tmp & (1 << 1)) { | ||
252 | intr_cfg.pa1 = regk_gio_lo; | 227 | intr_cfg.pa1 = regk_gio_lo; |
253 | } | 228 | if (tmp & (1 << 2)) |
254 | if (tmp & (1 << 2)) { | ||
255 | intr_cfg.pa2 = regk_gio_lo; | 229 | intr_cfg.pa2 = regk_gio_lo; |
256 | } | 230 | if (tmp & (1 << 3)) |
257 | if (tmp & (1 << 3)) { | ||
258 | intr_cfg.pa3 = regk_gio_lo; | 231 | intr_cfg.pa3 = regk_gio_lo; |
259 | } | 232 | if (tmp & (1 << 4)) |
260 | if (tmp & (1 << 4)) { | ||
261 | intr_cfg.pa4 = regk_gio_lo; | 233 | intr_cfg.pa4 = regk_gio_lo; |
262 | } | 234 | if (tmp & (1 << 5)) |
263 | if (tmp & (1 << 5)) { | ||
264 | intr_cfg.pa5 = regk_gio_lo; | 235 | intr_cfg.pa5 = regk_gio_lo; |
265 | } | 236 | if (tmp & (1 << 6)) |
266 | if (tmp & (1 << 6)) { | ||
267 | intr_cfg.pa6 = regk_gio_lo; | 237 | intr_cfg.pa6 = regk_gio_lo; |
268 | } | 238 | if (tmp & (1 << 7)) |
269 | if (tmp & (1 << 7)) { | ||
270 | intr_cfg.pa7 = regk_gio_lo; | 239 | intr_cfg.pa7 = regk_gio_lo; |
271 | } | ||
272 | 240 | ||
273 | REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); | 241 | REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); |
274 | local_irq_restore(flags); | 242 | local_irq_restore(flags); |
@@ -277,50 +245,65 @@ gpio_poll(struct file *file, | |||
277 | else | 245 | else |
278 | return 0; | 246 | return 0; |
279 | 247 | ||
280 | if ((data & priv->highalarm) || | 248 | if ((data & priv->highalarm) || (~data & priv->lowalarm)) |
281 | (~data & priv->lowalarm)) { | ||
282 | mask = POLLIN|POLLRDNORM; | 249 | mask = POLLIN|POLLRDNORM; |
283 | } | ||
284 | 250 | ||
285 | DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); | 251 | DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask)); |
286 | return mask; | 252 | return mask; |
287 | } | 253 | } |
288 | 254 | ||
289 | int etrax_gpio_wake_up_check(void) | 255 | int etrax_gpio_wake_up_check(void) |
290 | { | 256 | { |
291 | struct gpio_private *priv = alarmlist; | 257 | struct gpio_private *priv; |
292 | unsigned long data = 0; | 258 | unsigned long data = 0; |
293 | int ret = 0; | 259 | unsigned long flags; |
260 | int ret = 0; | ||
261 | spin_lock_irqsave(&alarm_lock, flags); | ||
262 | priv = alarmlist; | ||
294 | while (priv) { | 263 | while (priv) { |
264 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
265 | if (priv->minor == GPIO_MINOR_V) | ||
266 | data = (unsigned long)cached_virtual_gpio_read; | ||
267 | else { | ||
268 | data = *data_in[priv->minor]; | ||
269 | if (priv->minor == GPIO_MINOR_A) | ||
270 | priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
271 | } | ||
272 | #else | ||
295 | data = *data_in[priv->minor]; | 273 | data = *data_in[priv->minor]; |
274 | #endif | ||
296 | if ((data & priv->highalarm) || | 275 | if ((data & priv->highalarm) || |
297 | (~data & priv->lowalarm)) { | 276 | (~data & priv->lowalarm)) { |
298 | DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor)); | 277 | DP(printk(KERN_DEBUG |
278 | "etrax_gpio_wake_up_check %i\n", priv->minor)); | ||
299 | wake_up_interruptible(&priv->alarm_wq); | 279 | wake_up_interruptible(&priv->alarm_wq); |
300 | ret = 1; | 280 | ret = 1; |
301 | } | 281 | } |
302 | priv = priv->next; | 282 | priv = priv->next; |
303 | } | 283 | } |
304 | return ret; | 284 | spin_unlock_irqrestore(&alarm_lock, flags); |
285 | return ret; | ||
305 | } | 286 | } |
306 | 287 | ||
307 | static irqreturn_t | 288 | static irqreturn_t |
308 | gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 289 | gpio_poll_timer_interrupt(int irq, void *dev_id) |
309 | { | 290 | { |
310 | if (gpio_some_alarms) { | 291 | if (gpio_some_alarms) |
311 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); | 292 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); |
312 | } | 293 | return IRQ_NONE; |
313 | return IRQ_NONE; | ||
314 | } | 294 | } |
315 | 295 | ||
316 | static irqreturn_t | 296 | static irqreturn_t |
317 | gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 297 | gpio_pa_interrupt(int irq, void *dev_id) |
318 | { | 298 | { |
319 | reg_gio_rw_intr_mask intr_mask; | 299 | reg_gio_rw_intr_mask intr_mask; |
320 | reg_gio_r_masked_intr masked_intr; | 300 | reg_gio_r_masked_intr masked_intr; |
321 | reg_gio_rw_ack_intr ack_intr; | 301 | reg_gio_rw_ack_intr ack_intr; |
322 | unsigned long tmp; | 302 | unsigned long tmp; |
323 | unsigned long tmp2; | 303 | unsigned long tmp2; |
304 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
305 | unsigned char enable_gpiov_ack = 0; | ||
306 | #endif | ||
324 | 307 | ||
325 | /* Find what PA interrupts are active */ | 308 | /* Find what PA interrupts are active */ |
326 | masked_intr = REG_RD(gio, regi_gio, r_masked_intr); | 309 | masked_intr = REG_RD(gio, regi_gio, r_masked_intr); |
@@ -331,6 +314,17 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
331 | tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms); | 314 | tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms); |
332 | spin_unlock(&alarm_lock); | 315 | spin_unlock(&alarm_lock); |
333 | 316 | ||
317 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
318 | /* Something changed on virtual GPIO. Interrupt is acked by | ||
319 | * reading the device. | ||
320 | */ | ||
321 | if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) { | ||
322 | i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read, | ||
323 | sizeof(cached_virtual_gpio_read)); | ||
324 | enable_gpiov_ack = 1; | ||
325 | } | ||
326 | #endif | ||
327 | |||
334 | /* Ack them */ | 328 | /* Ack them */ |
335 | ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); | 329 | ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); |
336 | REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); | 330 | REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); |
@@ -339,18 +333,24 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
339 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | 333 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); |
340 | tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); | 334 | tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); |
341 | tmp2 &= ~tmp; | 335 | tmp2 &= ~tmp; |
336 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
337 | /* Do not disable interrupt on virtual GPIO. Changes on virtual | ||
338 | * pins are only noticed by an interrupt. | ||
339 | */ | ||
340 | if (enable_gpiov_ack) | ||
341 | tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
342 | #endif | ||
342 | intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); | 343 | intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); |
343 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | 344 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); |
344 | 345 | ||
345 | if (gpio_some_alarms) { | 346 | if (gpio_some_alarms) |
346 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); | 347 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); |
347 | } | 348 | return IRQ_NONE; |
348 | return IRQ_NONE; | ||
349 | } | 349 | } |
350 | 350 | ||
351 | 351 | ||
352 | static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | 352 | static ssize_t gpio_write(struct file *file, const char *buf, size_t count, |
353 | loff_t *off) | 353 | loff_t *off) |
354 | { | 354 | { |
355 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 355 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
356 | unsigned char data, clk_mask, data_mask, write_msb; | 356 | unsigned char data, clk_mask, data_mask, write_msb; |
@@ -360,29 +360,31 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
360 | ssize_t retval = count; | 360 | ssize_t retval = count; |
361 | /* Only bits 0-7 may be used for write operations but allow all | 361 | /* Only bits 0-7 may be used for write operations but allow all |
362 | devices except leds... */ | 362 | devices except leds... */ |
363 | if (priv->minor == GPIO_MINOR_LEDS) { | 363 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
364 | if (priv->minor == GPIO_MINOR_V) | ||
365 | return -EFAULT; | ||
366 | #endif | ||
367 | if (priv->minor == GPIO_MINOR_LEDS) | ||
364 | return -EFAULT; | 368 | return -EFAULT; |
365 | } | ||
366 | 369 | ||
367 | if (!access_ok(VERIFY_READ, buf, count)) { | 370 | if (!access_ok(VERIFY_READ, buf, count)) |
368 | return -EFAULT; | 371 | return -EFAULT; |
369 | } | ||
370 | clk_mask = priv->clk_mask; | 372 | clk_mask = priv->clk_mask; |
371 | data_mask = priv->data_mask; | 373 | data_mask = priv->data_mask; |
372 | /* It must have been configured using the IO_CFG_WRITE_MODE */ | 374 | /* It must have been configured using the IO_CFG_WRITE_MODE */ |
373 | /* Perhaps a better error code? */ | 375 | /* Perhaps a better error code? */ |
374 | if (clk_mask == 0 || data_mask == 0) { | 376 | if (clk_mask == 0 || data_mask == 0) |
375 | return -EPERM; | 377 | return -EPERM; |
376 | } | ||
377 | write_msb = priv->write_msb; | 378 | write_msb = priv->write_msb; |
378 | D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); | 379 | D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " |
380 | "msb: %i\n", count, data_mask, clk_mask, write_msb)); | ||
379 | port = data_out[priv->minor]; | 381 | port = data_out[priv->minor]; |
380 | 382 | ||
381 | while (count--) { | 383 | while (count--) { |
382 | int i; | 384 | int i; |
383 | data = *buf++; | 385 | data = *buf++; |
384 | if (priv->write_msb) { | 386 | if (priv->write_msb) { |
385 | for (i = 7; i >= 0;i--) { | 387 | for (i = 7; i >= 0; i--) { |
386 | local_irq_save(flags); | 388 | local_irq_save(flags); |
387 | shadow = *port; | 389 | shadow = *port; |
388 | *port = shadow &= ~clk_mask; | 390 | *port = shadow &= ~clk_mask; |
@@ -395,7 +397,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | |||
395 | local_irq_restore(flags); | 397 | local_irq_restore(flags); |
396 | } | 398 | } |
397 | } else { | 399 | } else { |
398 | for (i = 0; i <= 7;i++) { | 400 | for (i = 0; i <= 7; i++) { |
399 | local_irq_save(flags); | 401 | local_irq_save(flags); |
400 | shadow = *port; | 402 | shadow = *port; |
401 | *port = shadow &= ~clk_mask; | 403 | *port = shadow &= ~clk_mask; |
@@ -423,18 +425,16 @@ gpio_open(struct inode *inode, struct file *filp) | |||
423 | if (p > GPIO_MINOR_LAST) | 425 | if (p > GPIO_MINOR_LAST) |
424 | return -EINVAL; | 426 | return -EINVAL; |
425 | 427 | ||
426 | priv = kmalloc(sizeof(struct gpio_private), | 428 | priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL); |
427 | GFP_KERNEL); | ||
428 | 429 | ||
429 | if (!priv) | 430 | if (!priv) |
430 | return -ENOMEM; | 431 | return -ENOMEM; |
432 | memset(priv, 0, sizeof(*priv)); | ||
431 | 433 | ||
432 | priv->minor = p; | 434 | priv->minor = p; |
433 | 435 | ||
434 | /* initialize the io/alarm struct and link it into our alarmlist */ | 436 | /* initialize the io/alarm struct */ |
435 | 437 | ||
436 | priv->next = alarmlist; | ||
437 | alarmlist = priv; | ||
438 | priv->clk_mask = 0; | 438 | priv->clk_mask = 0; |
439 | priv->data_mask = 0; | 439 | priv->data_mask = 0; |
440 | priv->highalarm = 0; | 440 | priv->highalarm = 0; |
@@ -443,20 +443,30 @@ gpio_open(struct inode *inode, struct file *filp) | |||
443 | 443 | ||
444 | filp->private_data = (void *)priv; | 444 | filp->private_data = (void *)priv; |
445 | 445 | ||
446 | /* link it into our alarmlist */ | ||
447 | spin_lock_irq(&alarm_lock); | ||
448 | priv->next = alarmlist; | ||
449 | alarmlist = priv; | ||
450 | spin_unlock_irq(&alarm_lock); | ||
451 | |||
446 | return 0; | 452 | return 0; |
447 | } | 453 | } |
448 | 454 | ||
449 | static int | 455 | static int |
450 | gpio_release(struct inode *inode, struct file *filp) | 456 | gpio_release(struct inode *inode, struct file *filp) |
451 | { | 457 | { |
452 | struct gpio_private *p = alarmlist; | 458 | struct gpio_private *p; |
453 | struct gpio_private *todel = (struct gpio_private *)filp->private_data; | 459 | struct gpio_private *todel; |
454 | /* local copies while updating them: */ | 460 | /* local copies while updating them: */ |
455 | unsigned long a_high, a_low; | 461 | unsigned long a_high, a_low; |
456 | unsigned long some_alarms; | 462 | unsigned long some_alarms; |
457 | 463 | ||
458 | /* unlink from alarmlist and free the private structure */ | 464 | /* unlink from alarmlist and free the private structure */ |
459 | 465 | ||
466 | spin_lock_irq(&alarm_lock); | ||
467 | p = alarmlist; | ||
468 | todel = (struct gpio_private *)filp->private_data; | ||
469 | |||
460 | if (p == todel) { | 470 | if (p == todel) { |
461 | alarmlist = todel->next; | 471 | alarmlist = todel->next; |
462 | } else { | 472 | } else { |
@@ -468,26 +478,35 @@ gpio_release(struct inode *inode, struct file *filp) | |||
468 | kfree(todel); | 478 | kfree(todel); |
469 | /* Check if there are still any alarms set */ | 479 | /* Check if there are still any alarms set */ |
470 | p = alarmlist; | 480 | p = alarmlist; |
471 | some_alarms = 0; | 481 | some_alarms = 0; |
472 | a_high = 0; | 482 | a_high = 0; |
473 | a_low = 0; | 483 | a_low = 0; |
474 | while (p) { | 484 | while (p) { |
475 | if (p->minor == GPIO_MINOR_A) { | 485 | if (p->minor == GPIO_MINOR_A) { |
486 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
487 | p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
488 | #endif | ||
476 | a_high |= p->highalarm; | 489 | a_high |= p->highalarm; |
477 | a_low |= p->lowalarm; | 490 | a_low |= p->lowalarm; |
478 | } | 491 | } |
479 | 492 | ||
480 | if (p->highalarm | p->lowalarm) { | 493 | if (p->highalarm | p->lowalarm) |
481 | some_alarms = 1; | 494 | some_alarms = 1; |
482 | } | ||
483 | p = p->next; | 495 | p = p->next; |
484 | } | 496 | } |
485 | 497 | ||
486 | spin_lock(&alarm_lock); | 498 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
499 | /* Variables 'some_alarms' and 'a_low' needs to be set here again | ||
500 | * to ensure that interrupt for virtual GPIO is handled. | ||
501 | */ | ||
502 | some_alarms = 1; | ||
503 | a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
504 | #endif | ||
505 | |||
487 | gpio_some_alarms = some_alarms; | 506 | gpio_some_alarms = some_alarms; |
488 | gpio_pa_high_alarms = a_high; | 507 | gpio_pa_high_alarms = a_high; |
489 | gpio_pa_low_alarms = a_low; | 508 | gpio_pa_low_alarms = a_low; |
490 | spin_unlock(&alarm_lock); | 509 | spin_unlock_irq(&alarm_lock); |
491 | 510 | ||
492 | return 0; | 511 | return 0; |
493 | } | 512 | } |
@@ -496,7 +515,7 @@ gpio_release(struct inode *inode, struct file *filp) | |||
496 | * set alarms to wait for using a subsequent select(). | 515 | * set alarms to wait for using a subsequent select(). |
497 | */ | 516 | */ |
498 | 517 | ||
499 | unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) | 518 | inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) |
500 | { | 519 | { |
501 | /* Set direction 0=unchanged 1=input, | 520 | /* Set direction 0=unchanged 1=input, |
502 | * return mask with 1=input | 521 | * return mask with 1=input |
@@ -512,13 +531,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) | |||
512 | 531 | ||
513 | if (priv->minor == GPIO_MINOR_A) | 532 | if (priv->minor == GPIO_MINOR_A) |
514 | dir_shadow ^= 0xFF; /* Only 8 bits */ | 533 | dir_shadow ^= 0xFF; /* Only 8 bits */ |
534 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
535 | else if (priv->minor == GPIO_MINOR_V) | ||
536 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | ||
537 | #endif | ||
515 | else | 538 | else |
516 | dir_shadow ^= 0x3FFFF; /* Only 18 bits */ | 539 | dir_shadow ^= 0x3FFFF; /* Only 18 bits */ |
517 | return dir_shadow; | 540 | return dir_shadow; |
518 | 541 | ||
519 | } /* setget_input */ | 542 | } /* setget_input */ |
520 | 543 | ||
521 | unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) | 544 | inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg) |
522 | { | 545 | { |
523 | unsigned long flags; | 546 | unsigned long flags; |
524 | unsigned long dir_shadow; | 547 | unsigned long dir_shadow; |
@@ -542,20 +565,22 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
542 | unsigned long val; | 565 | unsigned long val; |
543 | unsigned long shadow; | 566 | unsigned long shadow; |
544 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | 567 | struct gpio_private *priv = (struct gpio_private *)file->private_data; |
545 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { | 568 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) |
546 | return -EINVAL; | 569 | return -EINVAL; |
547 | } | 570 | |
571 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
572 | if (priv->minor == GPIO_MINOR_V) | ||
573 | return virtual_gpio_ioctl(file, cmd, arg); | ||
574 | #endif | ||
548 | 575 | ||
549 | switch (_IOC_NR(cmd)) { | 576 | switch (_IOC_NR(cmd)) { |
550 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | 577 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ |
551 | // read the port | 578 | /* Read the port. */ |
552 | return *data_in[priv->minor]; | 579 | return *data_in[priv->minor]; |
553 | break; | 580 | break; |
554 | case IO_SETBITS: | 581 | case IO_SETBITS: |
555 | local_irq_save(flags); | 582 | local_irq_save(flags); |
556 | if (arg & 0x04) | 583 | /* Set changeable bits with a 1 in arg. */ |
557 | printk("GPIO SET 2\n"); | ||
558 | // set changeable bits with a 1 in arg | ||
559 | shadow = *data_out[priv->minor]; | 584 | shadow = *data_out[priv->minor]; |
560 | shadow |= (arg & changeable_bits[priv->minor]); | 585 | shadow |= (arg & changeable_bits[priv->minor]); |
561 | *data_out[priv->minor] = shadow; | 586 | *data_out[priv->minor] = shadow; |
@@ -563,46 +588,42 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
563 | break; | 588 | break; |
564 | case IO_CLRBITS: | 589 | case IO_CLRBITS: |
565 | local_irq_save(flags); | 590 | local_irq_save(flags); |
566 | if (arg & 0x04) | 591 | /* Clear changeable bits with a 1 in arg. */ |
567 | printk("GPIO CLR 2\n"); | ||
568 | // clear changeable bits with a 1 in arg | ||
569 | shadow = *data_out[priv->minor]; | 592 | shadow = *data_out[priv->minor]; |
570 | shadow &= ~(arg & changeable_bits[priv->minor]); | 593 | shadow &= ~(arg & changeable_bits[priv->minor]); |
571 | *data_out[priv->minor] = shadow; | 594 | *data_out[priv->minor] = shadow; |
572 | local_irq_restore(flags); | 595 | local_irq_restore(flags); |
573 | break; | 596 | break; |
574 | case IO_HIGHALARM: | 597 | case IO_HIGHALARM: |
575 | // set alarm when bits with 1 in arg go high | 598 | /* Set alarm when bits with 1 in arg go high. */ |
576 | priv->highalarm |= arg; | 599 | priv->highalarm |= arg; |
577 | spin_lock(&alarm_lock); | 600 | spin_lock_irqsave(&alarm_lock, flags); |
578 | gpio_some_alarms = 1; | 601 | gpio_some_alarms = 1; |
579 | if (priv->minor == GPIO_MINOR_A) { | 602 | if (priv->minor == GPIO_MINOR_A) |
580 | gpio_pa_high_alarms |= arg; | 603 | gpio_pa_high_alarms |= arg; |
581 | } | 604 | spin_unlock_irqrestore(&alarm_lock, flags); |
582 | spin_unlock(&alarm_lock); | ||
583 | break; | 605 | break; |
584 | case IO_LOWALARM: | 606 | case IO_LOWALARM: |
585 | // set alarm when bits with 1 in arg go low | 607 | /* Set alarm when bits with 1 in arg go low. */ |
586 | priv->lowalarm |= arg; | 608 | priv->lowalarm |= arg; |
587 | spin_lock(&alarm_lock); | 609 | spin_lock_irqsave(&alarm_lock, flags); |
588 | gpio_some_alarms = 1; | 610 | gpio_some_alarms = 1; |
589 | if (priv->minor == GPIO_MINOR_A) { | 611 | if (priv->minor == GPIO_MINOR_A) |
590 | gpio_pa_low_alarms |= arg; | 612 | gpio_pa_low_alarms |= arg; |
591 | } | 613 | spin_unlock_irqrestore(&alarm_lock, flags); |
592 | spin_unlock(&alarm_lock); | ||
593 | break; | 614 | break; |
594 | case IO_CLRALARM: | 615 | case IO_CLRALARM: |
595 | // clear alarm for bits with 1 in arg | 616 | /* Clear alarm for bits with 1 in arg. */ |
596 | priv->highalarm &= ~arg; | 617 | priv->highalarm &= ~arg; |
597 | priv->lowalarm &= ~arg; | 618 | priv->lowalarm &= ~arg; |
598 | spin_lock(&alarm_lock); | 619 | spin_lock_irqsave(&alarm_lock, flags); |
599 | if (priv->minor == GPIO_MINOR_A) { | 620 | if (priv->minor == GPIO_MINOR_A) { |
600 | if (gpio_pa_high_alarms & arg || | 621 | if (gpio_pa_high_alarms & arg || |
601 | gpio_pa_low_alarms & arg) { | 622 | gpio_pa_low_alarms & arg) |
602 | /* Must update the gpio_pa_*alarms masks */ | 623 | /* Must update the gpio_pa_*alarms masks */ |
603 | } | 624 | ; |
604 | } | 625 | } |
605 | spin_unlock(&alarm_lock); | 626 | spin_unlock_irqrestore(&alarm_lock, flags); |
606 | break; | 627 | break; |
607 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | 628 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ |
608 | /* Read direction 0=input 1=output */ | 629 | /* Read direction 0=input 1=output */ |
@@ -633,8 +654,7 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
633 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && | 654 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && |
634 | (priv->data_mask & changeable_bits[priv->minor]) && | 655 | (priv->data_mask & changeable_bits[priv->minor]) && |
635 | (priv->clk_mask & dir_shadow) && | 656 | (priv->clk_mask & dir_shadow) && |
636 | (priv->data_mask & dir_shadow))) | 657 | (priv->data_mask & dir_shadow))) { |
637 | { | ||
638 | priv->clk_mask = 0; | 658 | priv->clk_mask = 0; |
639 | priv->data_mask = 0; | 659 | priv->data_mask = 0; |
640 | return -EPERM; | 660 | return -EPERM; |
@@ -644,34 +664,34 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
644 | case IO_READ_INBITS: | 664 | case IO_READ_INBITS: |
645 | /* *arg is result of reading the input pins */ | 665 | /* *arg is result of reading the input pins */ |
646 | val = *data_in[priv->minor]; | 666 | val = *data_in[priv->minor]; |
647 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 667 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) |
648 | return -EFAULT; | 668 | return -EFAULT; |
649 | return 0; | 669 | return 0; |
650 | break; | 670 | break; |
651 | case IO_READ_OUTBITS: | 671 | case IO_READ_OUTBITS: |
652 | /* *arg is result of reading the output shadow */ | 672 | /* *arg is result of reading the output shadow */ |
653 | val = *data_out[priv->minor]; | 673 | val = *data_out[priv->minor]; |
654 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 674 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) |
655 | return -EFAULT; | 675 | return -EFAULT; |
656 | break; | 676 | break; |
657 | case IO_SETGET_INPUT: | 677 | case IO_SETGET_INPUT: |
658 | /* bits set in *arg is set to input, | 678 | /* bits set in *arg is set to input, |
659 | * *arg updated with current input pins. | 679 | * *arg updated with current input pins. |
660 | */ | 680 | */ |
661 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | 681 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) |
662 | return -EFAULT; | 682 | return -EFAULT; |
663 | val = setget_input(priv, val); | 683 | val = setget_input(priv, val); |
664 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 684 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) |
665 | return -EFAULT; | 685 | return -EFAULT; |
666 | break; | 686 | break; |
667 | case IO_SETGET_OUTPUT: | 687 | case IO_SETGET_OUTPUT: |
668 | /* bits set in *arg is set to output, | 688 | /* bits set in *arg is set to output, |
669 | * *arg updated with current output pins. | 689 | * *arg updated with current output pins. |
670 | */ | 690 | */ |
671 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | 691 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) |
672 | return -EFAULT; | 692 | return -EFAULT; |
673 | val = setget_output(priv, val); | 693 | val = setget_output(priv, val); |
674 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | 694 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) |
675 | return -EFAULT; | 695 | return -EFAULT; |
676 | break; | 696 | break; |
677 | default: | 697 | default: |
@@ -684,6 +704,133 @@ gpio_ioctl(struct inode *inode, struct file *file, | |||
684 | return 0; | 704 | return 0; |
685 | } | 705 | } |
686 | 706 | ||
707 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
708 | static int | ||
709 | virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
710 | { | ||
711 | unsigned long flags; | ||
712 | unsigned short val; | ||
713 | unsigned short shadow; | ||
714 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | ||
715 | |||
716 | switch (_IOC_NR(cmd)) { | ||
717 | case IO_SETBITS: | ||
718 | local_irq_save(flags); | ||
719 | /* Set changeable bits with a 1 in arg. */ | ||
720 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
721 | shadow |= ~*dir_oe[priv->minor]; | ||
722 | shadow |= (arg & changeable_bits[priv->minor]); | ||
723 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
724 | local_irq_restore(flags); | ||
725 | break; | ||
726 | case IO_CLRBITS: | ||
727 | local_irq_save(flags); | ||
728 | /* Clear changeable bits with a 1 in arg. */ | ||
729 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
730 | shadow |= ~*dir_oe[priv->minor]; | ||
731 | shadow &= ~(arg & changeable_bits[priv->minor]); | ||
732 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
733 | local_irq_restore(flags); | ||
734 | break; | ||
735 | case IO_HIGHALARM: | ||
736 | /* Set alarm when bits with 1 in arg go high. */ | ||
737 | priv->highalarm |= arg; | ||
738 | spin_lock(&alarm_lock); | ||
739 | gpio_some_alarms = 1; | ||
740 | spin_unlock(&alarm_lock); | ||
741 | break; | ||
742 | case IO_LOWALARM: | ||
743 | /* Set alarm when bits with 1 in arg go low. */ | ||
744 | priv->lowalarm |= arg; | ||
745 | spin_lock(&alarm_lock); | ||
746 | gpio_some_alarms = 1; | ||
747 | spin_unlock(&alarm_lock); | ||
748 | break; | ||
749 | case IO_CLRALARM: | ||
750 | /* Clear alarm for bits with 1 in arg. */ | ||
751 | priv->highalarm &= ~arg; | ||
752 | priv->lowalarm &= ~arg; | ||
753 | spin_lock(&alarm_lock); | ||
754 | spin_unlock(&alarm_lock); | ||
755 | break; | ||
756 | case IO_CFG_WRITE_MODE: | ||
757 | { | ||
758 | unsigned long dir_shadow; | ||
759 | dir_shadow = *dir_oe[priv->minor]; | ||
760 | |||
761 | priv->clk_mask = arg & 0xFF; | ||
762 | priv->data_mask = (arg >> 8) & 0xFF; | ||
763 | priv->write_msb = (arg >> 16) & 0x01; | ||
764 | /* Check if we're allowed to change the bits and | ||
765 | * the direction is correct | ||
766 | */ | ||
767 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && | ||
768 | (priv->data_mask & changeable_bits[priv->minor]) && | ||
769 | (priv->clk_mask & dir_shadow) && | ||
770 | (priv->data_mask & dir_shadow))) { | ||
771 | priv->clk_mask = 0; | ||
772 | priv->data_mask = 0; | ||
773 | return -EPERM; | ||
774 | } | ||
775 | break; | ||
776 | } | ||
777 | case IO_READ_INBITS: | ||
778 | /* *arg is result of reading the input pins */ | ||
779 | val = cached_virtual_gpio_read; | ||
780 | val &= ~*dir_oe[priv->minor]; | ||
781 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | ||
782 | return -EFAULT; | ||
783 | return 0; | ||
784 | break; | ||
785 | case IO_READ_OUTBITS: | ||
786 | /* *arg is result of reading the output shadow */ | ||
787 | i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); | ||
788 | val &= *dir_oe[priv->minor]; | ||
789 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | ||
790 | return -EFAULT; | ||
791 | break; | ||
792 | case IO_SETGET_INPUT: | ||
793 | { | ||
794 | /* bits set in *arg is set to input, | ||
795 | * *arg updated with current input pins. | ||
796 | */ | ||
797 | unsigned short input_mask = ~*dir_oe[priv->minor]; | ||
798 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | ||
799 | return -EFAULT; | ||
800 | val = setget_input(priv, val); | ||
801 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | ||
802 | return -EFAULT; | ||
803 | if ((input_mask & val) != input_mask) { | ||
804 | /* Input pins changed. All ports desired as input | ||
805 | * should be set to logic 1. | ||
806 | */ | ||
807 | unsigned short change = input_mask ^ val; | ||
808 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, | ||
809 | sizeof(shadow)); | ||
810 | shadow &= ~change; | ||
811 | shadow |= val; | ||
812 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, | ||
813 | sizeof(shadow)); | ||
814 | } | ||
815 | break; | ||
816 | } | ||
817 | case IO_SETGET_OUTPUT: | ||
818 | /* bits set in *arg is set to output, | ||
819 | * *arg updated with current output pins. | ||
820 | */ | ||
821 | if (copy_from_user(&val, (unsigned long *)arg, sizeof(val))) | ||
822 | return -EFAULT; | ||
823 | val = setget_output(priv, val); | ||
824 | if (copy_to_user((unsigned long *)arg, &val, sizeof(val))) | ||
825 | return -EFAULT; | ||
826 | break; | ||
827 | default: | ||
828 | return -EINVAL; | ||
829 | } /* switch */ | ||
830 | return 0; | ||
831 | } | ||
832 | #endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ | ||
833 | |||
687 | static int | 834 | static int |
688 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | 835 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) |
689 | { | 836 | { |
@@ -694,8 +841,8 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | |||
694 | case IO_LEDACTIVE_SET: | 841 | case IO_LEDACTIVE_SET: |
695 | green = ((unsigned char) arg) & 1; | 842 | green = ((unsigned char) arg) & 1; |
696 | red = (((unsigned char) arg) >> 1) & 1; | 843 | red = (((unsigned char) arg) >> 1) & 1; |
697 | LED_ACTIVE_SET_G(green); | 844 | CRIS_LED_ACTIVE_SET_G(green); |
698 | LED_ACTIVE_SET_R(red); | 845 | CRIS_LED_ACTIVE_SET_R(red); |
699 | break; | 846 | break; |
700 | 847 | ||
701 | default: | 848 | default: |
@@ -705,7 +852,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | |||
705 | return 0; | 852 | return 0; |
706 | } | 853 | } |
707 | 854 | ||
708 | const struct file_operations gpio_fops = { | 855 | struct file_operations gpio_fops = { |
709 | .owner = THIS_MODULE, | 856 | .owner = THIS_MODULE, |
710 | .poll = gpio_poll, | 857 | .poll = gpio_poll, |
711 | .ioctl = gpio_ioctl, | 858 | .ioctl = gpio_ioctl, |
@@ -714,6 +861,66 @@ const struct file_operations gpio_fops = { | |||
714 | .release = gpio_release, | 861 | .release = gpio_release, |
715 | }; | 862 | }; |
716 | 863 | ||
864 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | ||
865 | static void | ||
866 | virtual_gpio_init(void) | ||
867 | { | ||
868 | reg_gio_rw_intr_cfg intr_cfg; | ||
869 | reg_gio_rw_intr_mask intr_mask; | ||
870 | unsigned short shadow; | ||
871 | |||
872 | shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */ | ||
873 | shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT; | ||
874 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | ||
875 | |||
876 | /* Set interrupt mask and on what state the interrupt shall trigger. | ||
877 | * For virtual gpio the interrupt shall trigger on logic '0'. | ||
878 | */ | ||
879 | intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); | ||
880 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | ||
881 | |||
882 | switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) { | ||
883 | case 0: | ||
884 | intr_cfg.pa0 = regk_gio_lo; | ||
885 | intr_mask.pa0 = regk_gio_yes; | ||
886 | break; | ||
887 | case 1: | ||
888 | intr_cfg.pa1 = regk_gio_lo; | ||
889 | intr_mask.pa1 = regk_gio_yes; | ||
890 | break; | ||
891 | case 2: | ||
892 | intr_cfg.pa2 = regk_gio_lo; | ||
893 | intr_mask.pa2 = regk_gio_yes; | ||
894 | break; | ||
895 | case 3: | ||
896 | intr_cfg.pa3 = regk_gio_lo; | ||
897 | intr_mask.pa3 = regk_gio_yes; | ||
898 | break; | ||
899 | case 4: | ||
900 | intr_cfg.pa4 = regk_gio_lo; | ||
901 | intr_mask.pa4 = regk_gio_yes; | ||
902 | break; | ||
903 | case 5: | ||
904 | intr_cfg.pa5 = regk_gio_lo; | ||
905 | intr_mask.pa5 = regk_gio_yes; | ||
906 | break; | ||
907 | case 6: | ||
908 | intr_cfg.pa6 = regk_gio_lo; | ||
909 | intr_mask.pa6 = regk_gio_yes; | ||
910 | break; | ||
911 | case 7: | ||
912 | intr_cfg.pa7 = regk_gio_lo; | ||
913 | intr_mask.pa7 = regk_gio_yes; | ||
914 | break; | ||
915 | } | ||
916 | |||
917 | REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); | ||
918 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | ||
919 | |||
920 | gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | ||
921 | gpio_some_alarms = 1; | ||
922 | } | ||
923 | #endif | ||
717 | 924 | ||
718 | /* main driver initialization routine, called from mem.c */ | 925 | /* main driver initialization routine, called from mem.c */ |
719 | 926 | ||
@@ -721,7 +928,6 @@ static __init int | |||
721 | gpio_init(void) | 928 | gpio_init(void) |
722 | { | 929 | { |
723 | int res; | 930 | int res; |
724 | reg_intr_vect_rw_mask intr_mask; | ||
725 | 931 | ||
726 | /* do the formalities */ | 932 | /* do the formalities */ |
727 | 933 | ||
@@ -732,30 +938,30 @@ gpio_init(void) | |||
732 | } | 938 | } |
733 | 939 | ||
734 | /* Clear all leds */ | 940 | /* Clear all leds */ |
735 | LED_NETWORK_SET(0); | 941 | CRIS_LED_NETWORK_GRP0_SET(0); |
736 | LED_ACTIVE_SET(0); | 942 | CRIS_LED_NETWORK_GRP1_SET(0); |
737 | LED_DISK_READ(0); | 943 | CRIS_LED_ACTIVE_SET(0); |
738 | LED_DISK_WRITE(0); | 944 | CRIS_LED_DISK_READ(0); |
739 | 945 | CRIS_LED_DISK_WRITE(0); | |
740 | printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications AB\n"); | 946 | |
947 | printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 " | ||
948 | "Axis Communications AB\n"); | ||
741 | /* We call etrax_gpio_wake_up_check() from timer interrupt and | 949 | /* We call etrax_gpio_wake_up_check() from timer interrupt and |
742 | * from cpu_idle() in kernel/process.c | 950 | * from cpu_idle() in kernel/process.c |
743 | * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms | 951 | * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms |
744 | * in some tests. | 952 | * in some tests. |
745 | */ | 953 | */ |
746 | if (request_irq(TIMER_INTR_VECT, gpio_poll_timer_interrupt, | 954 | if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt, |
747 | IRQF_SHARED | IRQF_DISABLED,"gpio poll", &alarmlist)) { | 955 | IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist)) |
748 | printk("err: timer0 irq for gpio\n"); | 956 | printk(KERN_ERR "timer0 irq for gpio\n"); |
749 | } | 957 | |
750 | if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt, | 958 | if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt, |
751 | IRQF_SHARED | IRQF_DISABLED,"gpio PA", &alarmlist)) { | 959 | IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist)) |
752 | printk("err: PA irq for gpio\n"); | 960 | printk(KERN_ERR "PA irq for gpio\n"); |
753 | } | 961 | |
754 | /* enable the gio and timer irq in global config */ | 962 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
755 | intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); | 963 | virtual_gpio_init(); |
756 | intr_mask.timer = 1; | 964 | #endif |
757 | intr_mask.gen_io = 1; | ||
758 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | ||
759 | 965 | ||
760 | return res; | 966 | return res; |
761 | } | 967 | } |
diff --git a/arch/cris/arch-v32/drivers/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index 5ce015c6bb0d..aa01b134458a 100644 --- a/arch/cris/arch-v32/drivers/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c | |||
@@ -4,9 +4,7 @@ | |||
4 | * Copyright (c) 2004 | 4 | * Copyright (c) 2004 |
5 | * | 5 | * |
6 | * Derived from drivers/mtd/nand/spia.c | 6 | * Derived from drivers/mtd/nand/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | ||
9 | * $Id: nandflash.c,v 1.3 2005/06/01 10:57:12 starvik Exp $ | ||
10 | * | 8 | * |
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
@@ -21,10 +19,10 @@ | |||
21 | #include <linux/mtd/nand.h> | 19 | #include <linux/mtd/nand.h> |
22 | #include <linux/mtd/partitions.h> | 20 | #include <linux/mtd/partitions.h> |
23 | #include <asm/arch/memmap.h> | 21 | #include <asm/arch/memmap.h> |
24 | #include <asm/arch/hwregs/reg_map.h> | 22 | #include <hwregs/reg_map.h> |
25 | #include <asm/arch/hwregs/reg_rdwr.h> | 23 | #include <hwregs/reg_rdwr.h> |
26 | #include <asm/arch/hwregs/gio_defs.h> | 24 | #include <hwregs/gio_defs.h> |
27 | #include <asm/arch/hwregs/bif_core_defs.h> | 25 | #include <hwregs/bif_core_defs.h> |
28 | #include <asm/io.h> | 26 | #include <asm/io.h> |
29 | 27 | ||
30 | #define CE_BIT 4 | 28 | #define CE_BIT 4 |
@@ -32,44 +30,65 @@ | |||
32 | #define ALE_BIT 6 | 30 | #define ALE_BIT 6 |
33 | #define BY_BIT 7 | 31 | #define BY_BIT 7 |
34 | 32 | ||
35 | static struct mtd_info *crisv32_mtd = NULL; | 33 | struct mtd_info_wrapper { |
34 | struct mtd_info info; | ||
35 | struct nand_chip chip; | ||
36 | }; | ||
37 | |||
38 | /* Bitmask for control pins */ | ||
39 | #define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) | ||
40 | |||
41 | /* Bitmask for mtd nand control bits */ | ||
42 | #define CTRL_BITMASK (NAND_NCE | NAND_CLE | NAND_ALE) | ||
43 | |||
44 | |||
45 | static struct mtd_info *crisv32_mtd; | ||
36 | /* | 46 | /* |
37 | * hardware specific access to control-lines | 47 | * hardware specific access to control-lines |
38 | */ | 48 | */ |
39 | static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd) | 49 | static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, |
50 | unsigned int ctrl) | ||
40 | { | 51 | { |
41 | unsigned long flags; | 52 | unsigned long flags; |
42 | reg_gio_rw_pa_dout dout = REG_RD(gio, regi_gio, rw_pa_dout); | 53 | reg_gio_rw_pa_dout dout; |
54 | struct nand_chip *this = mtd->priv; | ||
43 | 55 | ||
44 | local_irq_save(flags); | 56 | local_irq_save(flags); |
45 | switch(cmd){ | 57 | |
46 | case NAND_CTL_SETCLE: | 58 | /* control bits change */ |
47 | dout.data |= (1<<CLE_BIT); | 59 | if (ctrl & NAND_CTRL_CHANGE) { |
48 | break; | 60 | dout = REG_RD(gio, regi_gio, rw_pa_dout); |
49 | case NAND_CTL_CLRCLE: | 61 | dout.data &= ~PIN_BITMASK; |
50 | dout.data &= ~(1<<CLE_BIT); | 62 | |
51 | break; | 63 | #if (CE_BIT == 4 && NAND_NCE == 1 && \ |
52 | case NAND_CTL_SETALE: | 64 | CLE_BIT == 5 && NAND_CLE == 2 && \ |
53 | dout.data |= (1<<ALE_BIT); | 65 | ALE_BIT == 6 && NAND_ALE == 4) |
54 | break; | 66 | /* Pins in same order as control bits, but shifted. |
55 | case NAND_CTL_CLRALE: | 67 | * Optimize for this case; works for 2.6.18 */ |
56 | dout.data &= ~(1<<ALE_BIT); | 68 | dout.data |= ((ctrl & CTRL_BITMASK) ^ NAND_NCE) << CE_BIT; |
57 | break; | 69 | #else |
58 | case NAND_CTL_SETNCE: | 70 | /* the slow way */ |
59 | dout.data |= (1<<CE_BIT); | 71 | if (!(ctrl & NAND_NCE)) |
60 | break; | 72 | dout.data |= (1 << CE_BIT); |
61 | case NAND_CTL_CLRNCE: | 73 | if (ctrl & NAND_CLE) |
62 | dout.data &= ~(1<<CE_BIT); | 74 | dout.data |= (1 << CLE_BIT); |
63 | break; | 75 | if (ctrl & NAND_ALE) |
76 | dout.data |= (1 << ALE_BIT); | ||
77 | #endif | ||
78 | REG_WR(gio, regi_gio, rw_pa_dout, dout); | ||
64 | } | 79 | } |
65 | REG_WR(gio, regi_gio, rw_pa_dout, dout); | 80 | |
81 | /* command to chip */ | ||
82 | if (cmd != NAND_CMD_NONE) | ||
83 | writeb(cmd, this->IO_ADDR_W); | ||
84 | |||
66 | local_irq_restore(flags); | 85 | local_irq_restore(flags); |
67 | } | 86 | } |
68 | 87 | ||
69 | /* | 88 | /* |
70 | * read device ready pin | 89 | * read device ready pin |
71 | */ | 90 | */ |
72 | int crisv32_device_ready(struct mtd_info *mtd) | 91 | static int crisv32_device_ready(struct mtd_info *mtd) |
73 | { | 92 | { |
74 | reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din); | 93 | reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din); |
75 | return ((din.data & (1 << BY_BIT)) >> BY_BIT); | 94 | return ((din.data & (1 << BY_BIT)) >> BY_BIT); |
@@ -78,21 +97,23 @@ int crisv32_device_ready(struct mtd_info *mtd) | |||
78 | /* | 97 | /* |
79 | * Main initialization routine | 98 | * Main initialization routine |
80 | */ | 99 | */ |
81 | struct mtd_info* __init crisv32_nand_flash_probe (void) | 100 | struct mtd_info *__init crisv32_nand_flash_probe(void) |
82 | { | 101 | { |
83 | void __iomem *read_cs; | 102 | void __iomem *read_cs; |
84 | void __iomem *write_cs; | 103 | void __iomem *write_cs; |
85 | 104 | ||
86 | reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, rw_grp3_cfg); | 105 | reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, |
106 | rw_grp3_cfg); | ||
87 | reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe); | 107 | reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe); |
108 | struct mtd_info_wrapper *wrapper; | ||
88 | struct nand_chip *this; | 109 | struct nand_chip *this; |
89 | int err = 0; | 110 | int err = 0; |
90 | 111 | ||
91 | /* Allocate memory for MTD device structure and private data */ | 112 | /* Allocate memory for MTD device structure and private data */ |
92 | crisv32_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), | 113 | wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); |
93 | GFP_KERNEL); | 114 | if (!wrapper) { |
94 | if (!crisv32_mtd) { | 115 | printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " |
95 | printk ("Unable to allocate CRISv32 NAND MTD device structure.\n"); | 116 | "device structure.\n"); |
96 | err = -ENOMEM; | 117 | err = -ENOMEM; |
97 | return NULL; | 118 | return NULL; |
98 | } | 119 | } |
@@ -101,45 +122,42 @@ struct mtd_info* __init crisv32_nand_flash_probe (void) | |||
101 | write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192); | 122 | write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192); |
102 | 123 | ||
103 | if (!read_cs || !write_cs) { | 124 | if (!read_cs || !write_cs) { |
104 | printk("CRISv32 NAND ioremap failed\n"); | 125 | printk(KERN_ERR "CRISv32 NAND ioremap failed\n"); |
105 | err = -EIO; | 126 | err = -EIO; |
106 | goto out_mtd; | 127 | goto out_mtd; |
107 | } | 128 | } |
108 | 129 | ||
109 | /* Get pointer to private data */ | 130 | /* Get pointer to private data */ |
110 | this = (struct nand_chip *) (&crisv32_mtd[1]); | 131 | this = &wrapper->chip; |
132 | crisv32_mtd = &wrapper->info; | ||
111 | 133 | ||
112 | pa_oe.oe |= 1 << CE_BIT; | 134 | pa_oe.oe |= 1 << CE_BIT; |
113 | pa_oe.oe |= 1 << ALE_BIT; | 135 | pa_oe.oe |= 1 << ALE_BIT; |
114 | pa_oe.oe |= 1 << CLE_BIT; | 136 | pa_oe.oe |= 1 << CLE_BIT; |
115 | pa_oe.oe &= ~ (1 << BY_BIT); | 137 | pa_oe.oe &= ~(1 << BY_BIT); |
116 | REG_WR(gio, regi_gio, rw_pa_oe, pa_oe); | 138 | REG_WR(gio, regi_gio, rw_pa_oe, pa_oe); |
117 | 139 | ||
118 | bif_cfg.gated_csp0 = regk_bif_core_rd; | 140 | bif_cfg.gated_csp0 = regk_bif_core_rd; |
119 | bif_cfg.gated_csp1 = regk_bif_core_wr; | 141 | bif_cfg.gated_csp1 = regk_bif_core_wr; |
120 | REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg); | 142 | REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg); |
121 | 143 | ||
122 | /* Initialize structures */ | ||
123 | memset((char *) crisv32_mtd, 0, sizeof(struct mtd_info)); | ||
124 | memset((char *) this, 0, sizeof(struct nand_chip)); | ||
125 | |||
126 | /* Link the private data with the MTD structure */ | 144 | /* Link the private data with the MTD structure */ |
127 | crisv32_mtd->priv = this; | 145 | crisv32_mtd->priv = this; |
128 | 146 | ||
129 | /* Set address of NAND IO lines */ | 147 | /* Set address of NAND IO lines */ |
130 | this->IO_ADDR_R = read_cs; | 148 | this->IO_ADDR_R = read_cs; |
131 | this->IO_ADDR_W = write_cs; | 149 | this->IO_ADDR_W = write_cs; |
132 | this->hwcontrol = crisv32_hwcontrol; | 150 | this->cmd_ctrl = crisv32_hwcontrol; |
133 | this->dev_ready = crisv32_device_ready; | 151 | this->dev_ready = crisv32_device_ready; |
134 | /* 20 us command delay time */ | 152 | /* 20 us command delay time */ |
135 | this->chip_delay = 20; | 153 | this->chip_delay = 20; |
136 | this->eccmode = NAND_ECC_SOFT; | 154 | this->ecc.mode = NAND_ECC_SOFT; |
137 | 155 | ||
138 | /* Enable the following for a flash based bad block table */ | 156 | /* Enable the following for a flash based bad block table */ |
139 | this->options = NAND_USE_FLASH_BBT; | 157 | /* this->options = NAND_USE_FLASH_BBT; */ |
140 | 158 | ||
141 | /* Scan to find existence of the device */ | 159 | /* Scan to find existance of the device */ |
142 | if (nand_scan (crisv32_mtd, 1)) { | 160 | if (nand_scan(crisv32_mtd, 1)) { |
143 | err = -ENXIO; | 161 | err = -ENXIO; |
144 | goto out_ior; | 162 | goto out_ior; |
145 | } | 163 | } |
@@ -150,7 +168,7 @@ out_ior: | |||
150 | iounmap((void *)read_cs); | 168 | iounmap((void *)read_cs); |
151 | iounmap((void *)write_cs); | 169 | iounmap((void *)write_cs); |
152 | out_mtd: | 170 | out_mtd: |
153 | kfree (crisv32_mtd); | 171 | kfree(wrapper); |
154 | return NULL; | 172 | return NULL; |
155 | } | 173 | } |
156 | 174 | ||
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c index 6dbd700d3d66..53db3870ba04 100644 --- a/arch/cris/arch-v32/drivers/pcf8563.c +++ b/arch/cris/arch-v32/drivers/pcf8563.c | |||
@@ -10,7 +10,7 @@ | |||
10 | * 400 kbits/s. The built-in word address register is incremented | 10 | * 400 kbits/s. The built-in word address register is incremented |
11 | * automatically after each written or read byte. | 11 | * automatically after each written or read byte. |
12 | * | 12 | * |
13 | * Copyright (c) 2002-2003, Axis Communications AB | 13 | * Copyright (c) 2002-2007, Axis Communications AB |
14 | * All rights reserved. | 14 | * All rights reserved. |
15 | * | 15 | * |
16 | * Author: Tobias Anderberg <tobiasa@axis.com>. | 16 | * Author: Tobias Anderberg <tobiasa@axis.com>. |
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/ioctl.h> | 26 | #include <linux/ioctl.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/bcd.h> | 28 | #include <linux/bcd.h> |
29 | #include <linux/mutex.h> | ||
29 | 30 | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
@@ -37,24 +38,27 @@ | |||
37 | #define PCF8563_MAJOR 121 /* Local major number. */ | 38 | #define PCF8563_MAJOR 121 /* Local major number. */ |
38 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ | 39 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ |
39 | #define PCF8563_NAME "PCF8563" | 40 | #define PCF8563_NAME "PCF8563" |
40 | #define DRIVER_VERSION "$Revision: 1.1 $" | 41 | #define DRIVER_VERSION "$Revision: 1.17 $" |
41 | 42 | ||
42 | /* Two simple wrapper macros, saves a few keystrokes. */ | 43 | /* Two simple wrapper macros, saves a few keystrokes. */ |
43 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) | 44 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) |
44 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) | 45 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) |
45 | 46 | ||
47 | static DEFINE_MUTEX(rtc_lock); /* Protect state etc */ | ||
48 | |||
46 | static const unsigned char days_in_month[] = | 49 | static const unsigned char days_in_month[] = |
47 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | 50 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
48 | 51 | ||
49 | int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | 52 | int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); |
50 | int pcf8563_open(struct inode *, struct file *); | 53 | |
51 | int pcf8563_release(struct inode *, struct file *); | 54 | /* Cache VL bit value read at driver init since writing the RTC_SECOND |
55 | * register clears the VL status. | ||
56 | */ | ||
57 | static int voltage_low; | ||
52 | 58 | ||
53 | static const struct file_operations pcf8563_fops = { | 59 | static const struct file_operations pcf8563_fops = { |
54 | .owner = THIS_MODULE, | 60 | .owner = THIS_MODULE, |
55 | .ioctl = pcf8563_ioctl, | 61 | .ioctl = pcf8563_ioctl |
56 | .open = pcf8563_open, | ||
57 | .release = pcf8563_release, | ||
58 | }; | 62 | }; |
59 | 63 | ||
60 | unsigned char | 64 | unsigned char |
@@ -62,7 +66,7 @@ pcf8563_readreg(int reg) | |||
62 | { | 66 | { |
63 | unsigned char res = rtc_read(reg); | 67 | unsigned char res = rtc_read(reg); |
64 | 68 | ||
65 | /* The PCF8563 does not return 0 for unimplemented bits */ | 69 | /* The PCF8563 does not return 0 for unimplemented bits. */ |
66 | switch (reg) { | 70 | switch (reg) { |
67 | case RTC_SECONDS: | 71 | case RTC_SECONDS: |
68 | case RTC_MINUTES: | 72 | case RTC_MINUTES: |
@@ -95,11 +99,6 @@ pcf8563_readreg(int reg) | |||
95 | void | 99 | void |
96 | pcf8563_writereg(int reg, unsigned char val) | 100 | pcf8563_writereg(int reg, unsigned char val) |
97 | { | 101 | { |
98 | #ifdef CONFIG_ETRAX_RTC_READONLY | ||
99 | if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR)) | ||
100 | return; | ||
101 | #endif | ||
102 | |||
103 | rtc_write(reg, val); | 102 | rtc_write(reg, val); |
104 | } | 103 | } |
105 | 104 | ||
@@ -114,11 +113,13 @@ get_rtc_time(struct rtc_time *tm) | |||
114 | tm->tm_mon = rtc_read(RTC_MONTH); | 113 | tm->tm_mon = rtc_read(RTC_MONTH); |
115 | tm->tm_year = rtc_read(RTC_YEAR); | 114 | tm->tm_year = rtc_read(RTC_YEAR); |
116 | 115 | ||
117 | if (tm->tm_sec & 0x80) | 116 | if (tm->tm_sec & 0x80) { |
118 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " | 117 | printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time " |
119 | "information is no longer guaranteed!\n", PCF8563_NAME); | 118 | "information is no longer guaranteed!\n", PCF8563_NAME); |
119 | } | ||
120 | 120 | ||
121 | tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0); | 121 | tm->tm_year = BCD_TO_BIN(tm->tm_year) + |
122 | ((tm->tm_mon & 0x80) ? 100 : 0); | ||
122 | tm->tm_sec &= 0x7F; | 123 | tm->tm_sec &= 0x7F; |
123 | tm->tm_min &= 0x7F; | 124 | tm->tm_min &= 0x7F; |
124 | tm->tm_hour &= 0x3F; | 125 | tm->tm_hour &= 0x3F; |
@@ -137,8 +138,19 @@ get_rtc_time(struct rtc_time *tm) | |||
137 | int __init | 138 | int __init |
138 | pcf8563_init(void) | 139 | pcf8563_init(void) |
139 | { | 140 | { |
141 | static int res; | ||
142 | static int first = 1; | ||
143 | |||
144 | if (!first) | ||
145 | return res; | ||
146 | first = 0; | ||
147 | |||
140 | /* Initiate the i2c protocol. */ | 148 | /* Initiate the i2c protocol. */ |
141 | i2c_init(); | 149 | res = i2c_init(); |
150 | if (res < 0) { | ||
151 | printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n"); | ||
152 | return res; | ||
153 | } | ||
142 | 154 | ||
143 | /* | 155 | /* |
144 | * First of all we need to reset the chip. This is done by | 156 | * First of all we need to reset the chip. This is done by |
@@ -170,24 +182,20 @@ pcf8563_init(void) | |||
170 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0) | 182 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0) |
171 | goto err; | 183 | goto err; |
172 | 184 | ||
173 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { | 185 | /* Check for low voltage, and warn about it. */ |
174 | printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n", | 186 | if (rtc_read(RTC_SECONDS) & 0x80) { |
175 | PCF8563_NAME, PCF8563_MAJOR); | 187 | voltage_low = 1; |
176 | return -1; | 188 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " |
189 | "date/time information is no longer guaranteed!\n", | ||
190 | PCF8563_NAME); | ||
177 | } | 191 | } |
178 | 192 | ||
179 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | 193 | return res; |
180 | |||
181 | /* Check for low voltage, and warn about it.. */ | ||
182 | if (rtc_read(RTC_SECONDS) & 0x80) | ||
183 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " | ||
184 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
185 | |||
186 | return 0; | ||
187 | 194 | ||
188 | err: | 195 | err: |
189 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); | 196 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); |
190 | return -1; | 197 | res = -1; |
198 | return res; | ||
191 | } | 199 | } |
192 | 200 | ||
193 | void __exit | 201 | void __exit |
@@ -200,8 +208,8 @@ pcf8563_exit(void) | |||
200 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because | 208 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because |
201 | * POSIX says so! | 209 | * POSIX says so! |
202 | */ | 210 | */ |
203 | int | 211 | int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
204 | pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) | 212 | unsigned long arg) |
205 | { | 213 | { |
206 | /* Some sanity checks. */ | 214 | /* Some sanity checks. */ |
207 | if (_IOC_TYPE(cmd) != RTC_MAGIC) | 215 | if (_IOC_TYPE(cmd) != RTC_MAGIC) |
@@ -211,125 +219,147 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned | |||
211 | return -ENOTTY; | 219 | return -ENOTTY; |
212 | 220 | ||
213 | switch (cmd) { | 221 | switch (cmd) { |
214 | case RTC_RD_TIME: | 222 | case RTC_RD_TIME: |
215 | { | 223 | { |
216 | struct rtc_time tm; | 224 | struct rtc_time tm; |
217 | 225 | ||
218 | memset(&tm, 0, sizeof (struct rtc_time)); | 226 | mutex_lock(&rtc_lock); |
219 | get_rtc_time(&tm); | 227 | memset(&tm, 0, sizeof tm); |
220 | 228 | get_rtc_time(&tm); | |
221 | if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) { | 229 | |
222 | return -EFAULT; | 230 | if (copy_to_user((struct rtc_time *) arg, &tm, |
223 | } | 231 | sizeof tm)) { |
224 | 232 | spin_unlock(&rtc_lock); | |
225 | return 0; | 233 | return -EFAULT; |
226 | } | 234 | } |
227 | 235 | ||
228 | case RTC_SET_TIME: | 236 | mutex_unlock(&rtc_lock); |
229 | { | 237 | |
230 | #ifdef CONFIG_ETRAX_RTC_READONLY | 238 | return 0; |
239 | } | ||
240 | case RTC_SET_TIME: | ||
241 | { | ||
242 | int leap; | ||
243 | int year; | ||
244 | int century; | ||
245 | struct rtc_time tm; | ||
246 | |||
247 | memset(&tm, 0, sizeof tm); | ||
248 | if (!capable(CAP_SYS_TIME)) | ||
231 | return -EPERM; | 249 | return -EPERM; |
232 | #else | ||
233 | int leap; | ||
234 | int year; | ||
235 | int century; | ||
236 | struct rtc_time tm; | ||
237 | |||
238 | if (!capable(CAP_SYS_TIME)) | ||
239 | return -EPERM; | ||
240 | |||
241 | if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm)) | ||
242 | return -EFAULT; | ||
243 | |||
244 | /* Convert from struct tm to struct rtc_time. */ | ||
245 | tm.tm_year += 1900; | ||
246 | tm.tm_mon += 1; | ||
247 | |||
248 | /* | ||
249 | * Check if tm.tm_year is a leap year. A year is a leap | ||
250 | * year if it is divisible by 4 but not 100, except | ||
251 | * that years divisible by 400 _are_ leap years. | ||
252 | */ | ||
253 | year = tm.tm_year; | ||
254 | leap = (tm.tm_mon == 2) && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); | ||
255 | |||
256 | /* Perform some sanity checks. */ | ||
257 | if ((tm.tm_year < 1970) || | ||
258 | (tm.tm_mon > 12) || | ||
259 | (tm.tm_mday == 0) || | ||
260 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
261 | (tm.tm_wday >= 7) || | ||
262 | (tm.tm_hour >= 24) || | ||
263 | (tm.tm_min >= 60) || | ||
264 | (tm.tm_sec >= 60)) | ||
265 | return -EINVAL; | ||
266 | |||
267 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
268 | tm.tm_year = tm.tm_year % 100; | ||
269 | |||
270 | BIN_TO_BCD(tm.tm_year); | ||
271 | BIN_TO_BCD(tm.tm_mday); | ||
272 | BIN_TO_BCD(tm.tm_hour); | ||
273 | BIN_TO_BCD(tm.tm_min); | ||
274 | BIN_TO_BCD(tm.tm_sec); | ||
275 | tm.tm_mon |= century; | ||
276 | |||
277 | rtc_write(RTC_YEAR, tm.tm_year); | ||
278 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
279 | rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */ | ||
280 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
281 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
282 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
283 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
284 | |||
285 | return 0; | ||
286 | #endif /* !CONFIG_ETRAX_RTC_READONLY */ | ||
287 | } | ||
288 | 250 | ||
289 | case RTC_VLOW_RD: | 251 | if (copy_from_user(&tm, (struct rtc_time *) arg, |
290 | { | 252 | sizeof tm)) |
291 | int vl_bit = 0; | 253 | return -EFAULT; |
254 | |||
255 | /* Convert from struct tm to struct rtc_time. */ | ||
256 | tm.tm_year += 1900; | ||
257 | tm.tm_mon += 1; | ||
258 | |||
259 | /* | ||
260 | * Check if tm.tm_year is a leap year. A year is a leap | ||
261 | * year if it is divisible by 4 but not 100, except | ||
262 | * that years divisible by 400 _are_ leap years. | ||
263 | */ | ||
264 | year = tm.tm_year; | ||
265 | leap = (tm.tm_mon == 2) && | ||
266 | ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); | ||
267 | |||
268 | /* Perform some sanity checks. */ | ||
269 | if ((tm.tm_year < 1970) || | ||
270 | (tm.tm_mon > 12) || | ||
271 | (tm.tm_mday == 0) || | ||
272 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
273 | (tm.tm_wday >= 7) || | ||
274 | (tm.tm_hour >= 24) || | ||
275 | (tm.tm_min >= 60) || | ||
276 | (tm.tm_sec >= 60)) | ||
277 | return -EINVAL; | ||
278 | |||
279 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
280 | tm.tm_year = tm.tm_year % 100; | ||
281 | |||
282 | BIN_TO_BCD(tm.tm_year); | ||
283 | BIN_TO_BCD(tm.tm_mon); | ||
284 | BIN_TO_BCD(tm.tm_mday); | ||
285 | BIN_TO_BCD(tm.tm_hour); | ||
286 | BIN_TO_BCD(tm.tm_min); | ||
287 | BIN_TO_BCD(tm.tm_sec); | ||
288 | tm.tm_mon |= century; | ||
289 | |||
290 | mutex_lock(&rtc_lock); | ||
291 | |||
292 | rtc_write(RTC_YEAR, tm.tm_year); | ||
293 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
294 | rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */ | ||
295 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
296 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
297 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
298 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
299 | |||
300 | mutex_unlock(&rtc_lock); | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | case RTC_VL_READ: | ||
305 | if (voltage_low) | ||
306 | printk(KERN_ERR "%s: RTC Voltage Low - " | ||
307 | "reliable date/time information is no " | ||
308 | "longer guaranteed!\n", PCF8563_NAME); | ||
292 | 309 | ||
293 | if (rtc_read(RTC_SECONDS) & 0x80) { | 310 | if (copy_to_user((int *) arg, &voltage_low, sizeof(int))) |
294 | vl_bit = 1; | 311 | return -EFAULT; |
295 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " | 312 | return 0; |
296 | "date/time information is no longer guaranteed!\n", | ||
297 | PCF8563_NAME); | ||
298 | } | ||
299 | if (copy_to_user((int *) arg, &vl_bit, sizeof(int))) | ||
300 | return -EFAULT; | ||
301 | 313 | ||
302 | return 0; | 314 | case RTC_VL_CLR: |
303 | } | 315 | { |
316 | /* Clear the VL bit in the seconds register in case | ||
317 | * the time has not been set already (which would | ||
318 | * have cleared it). This does not really matter | ||
319 | * because of the cached voltage_low value but do it | ||
320 | * anyway for consistency. */ | ||
304 | 321 | ||
305 | case RTC_VLOW_SET: | 322 | int ret = rtc_read(RTC_SECONDS); |
306 | { | ||
307 | /* Clear the VL bit in the seconds register */ | ||
308 | int ret = rtc_read(RTC_SECONDS); | ||
309 | 323 | ||
310 | rtc_write(RTC_SECONDS, (ret & 0x7F)); | 324 | rtc_write(RTC_SECONDS, (ret & 0x7F)); |
311 | 325 | ||
312 | return 0; | 326 | /* Clear the cached value. */ |
313 | } | 327 | voltage_low = 0; |
314 | 328 | ||
315 | default: | 329 | return 0; |
316 | return -ENOTTY; | 330 | } |
331 | default: | ||
332 | return -ENOTTY; | ||
317 | } | 333 | } |
318 | 334 | ||
319 | return 0; | 335 | return 0; |
320 | } | 336 | } |
321 | 337 | ||
322 | int | 338 | static int __init pcf8563_register(void) |
323 | pcf8563_open(struct inode *inode, struct file *filp) | ||
324 | { | 339 | { |
325 | return 0; | 340 | if (pcf8563_init() < 0) { |
326 | } | 341 | printk(KERN_INFO "%s: Unable to initialize Real-Time Clock " |
342 | "Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | ||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { | ||
347 | printk(KERN_INFO "%s: Unable to get major numer %d for RTC " | ||
348 | "device.\n", PCF8563_NAME, PCF8563_MAJOR); | ||
349 | return -1; | ||
350 | } | ||
351 | |||
352 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, | ||
353 | DRIVER_VERSION); | ||
354 | |||
355 | /* Check for low voltage, and warn about it. */ | ||
356 | if (voltage_low) { | ||
357 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time " | ||
358 | "information is no longer guaranteed!\n", PCF8563_NAME); | ||
359 | } | ||
327 | 360 | ||
328 | int | ||
329 | pcf8563_release(struct inode *inode, struct file *filp) | ||
330 | { | ||
331 | return 0; | 361 | return 0; |
332 | } | 362 | } |
333 | 363 | ||
334 | module_init(pcf8563_init); | 364 | module_init(pcf8563_register); |
335 | module_exit(pcf8563_exit); | 365 | module_exit(pcf8563_exit); |
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index d581b0a92a3f..47c377df6fb3 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Simple synchronous serial port driver for ETRAX FS. | 2 | * Simple synchronous serial port driver for ETRAX FS and Artpec-3. |
3 | * | 3 | * |
4 | * Copyright (c) 2005 Axis Communications AB | 4 | * Copyright (c) 2005 Axis Communications AB |
5 | * | 5 | * |
@@ -21,17 +21,18 @@ | |||
21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
22 | 22 | ||
23 | #include <asm/io.h> | 23 | #include <asm/io.h> |
24 | #include <asm/arch/dma.h> | 24 | #include <dma.h> |
25 | #include <asm/arch/pinmux.h> | 25 | #include <pinmux.h> |
26 | #include <asm/arch/hwregs/reg_rdwr.h> | 26 | #include <hwregs/reg_rdwr.h> |
27 | #include <asm/arch/hwregs/sser_defs.h> | 27 | #include <hwregs/sser_defs.h> |
28 | #include <asm/arch/hwregs/dma_defs.h> | 28 | #include <hwregs/dma_defs.h> |
29 | #include <asm/arch/hwregs/dma.h> | 29 | #include <hwregs/dma.h> |
30 | #include <asm/arch/hwregs/intr_vect_defs.h> | 30 | #include <hwregs/intr_vect_defs.h> |
31 | #include <asm/arch/hwregs/intr_vect.h> | 31 | #include <hwregs/intr_vect.h> |
32 | #include <asm/arch/hwregs/reg_map.h> | 32 | #include <hwregs/reg_map.h> |
33 | #include <asm/sync_serial.h> | 33 | #include <asm/sync_serial.h> |
34 | 34 | ||
35 | |||
35 | /* The receiver is a bit tricky beacuse of the continuous stream of data.*/ | 36 | /* The receiver is a bit tricky beacuse of the continuous stream of data.*/ |
36 | /* */ | 37 | /* */ |
37 | /* Three DMA descriptors are linked together. Each DMA descriptor is */ | 38 | /* Three DMA descriptors are linked together. Each DMA descriptor is */ |
@@ -63,8 +64,10 @@ | |||
63 | /* words can be handled */ | 64 | /* words can be handled */ |
64 | #define IN_BUFFER_SIZE 12288 | 65 | #define IN_BUFFER_SIZE 12288 |
65 | #define IN_DESCR_SIZE 256 | 66 | #define IN_DESCR_SIZE 256 |
66 | #define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE) | 67 | #define NBR_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE) |
67 | #define OUT_BUFFER_SIZE 4096 | 68 | |
69 | #define OUT_BUFFER_SIZE 1024*8 | ||
70 | #define NBR_OUT_DESCR 8 | ||
68 | 71 | ||
69 | #define DEFAULT_FRAME_RATE 0 | 72 | #define DEFAULT_FRAME_RATE 0 |
70 | #define DEFAULT_WORD_RATE 7 | 73 | #define DEFAULT_WORD_RATE 7 |
@@ -78,6 +81,8 @@ | |||
78 | #define DEBUGPOLL(x) | 81 | #define DEBUGPOLL(x) |
79 | #define DEBUGRXINT(x) | 82 | #define DEBUGRXINT(x) |
80 | #define DEBUGTXINT(x) | 83 | #define DEBUGTXINT(x) |
84 | #define DEBUGTRDMA(x) | ||
85 | #define DEBUGOUTBUF(x) | ||
81 | 86 | ||
82 | typedef struct sync_port | 87 | typedef struct sync_port |
83 | { | 88 | { |
@@ -97,10 +102,11 @@ typedef struct sync_port | |||
97 | int output; | 102 | int output; |
98 | int input; | 103 | int input; |
99 | 104 | ||
100 | volatile unsigned int out_count; /* Remaining bytes for current transfer */ | 105 | /* Next byte to be read by application */ |
101 | unsigned char* outp; /* Current position in out_buffer */ | 106 | volatile unsigned char *volatile readp; |
102 | volatile unsigned char* volatile readp; /* Next byte to be read by application */ | 107 | /* Next byte to be written by etrax */ |
103 | volatile unsigned char* volatile writep; /* Next byte to be written by etrax */ | 108 | volatile unsigned char *volatile writep; |
109 | |||
104 | unsigned int in_buffer_size; | 110 | unsigned int in_buffer_size; |
105 | unsigned int inbufchunk; | 111 | unsigned int inbufchunk; |
106 | unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32))); | 112 | unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32))); |
@@ -108,11 +114,30 @@ typedef struct sync_port | |||
108 | unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32))); | 114 | unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32))); |
109 | struct dma_descr_data* next_rx_desc; | 115 | struct dma_descr_data* next_rx_desc; |
110 | struct dma_descr_data* prev_rx_desc; | 116 | struct dma_descr_data* prev_rx_desc; |
117 | |||
118 | /* Pointer to the first available descriptor in the ring, | ||
119 | * unless active_tr_descr == catch_tr_descr and a dma | ||
120 | * transfer is active */ | ||
121 | struct dma_descr_data *active_tr_descr; | ||
122 | |||
123 | /* Pointer to the first allocated descriptor in the ring */ | ||
124 | struct dma_descr_data *catch_tr_descr; | ||
125 | |||
126 | /* Pointer to the descriptor with the current end-of-list */ | ||
127 | struct dma_descr_data *prev_tr_descr; | ||
111 | int full; | 128 | int full; |
112 | 129 | ||
113 | dma_descr_data in_descr[NUM_IN_DESCR] __attribute__ ((__aligned__(16))); | 130 | /* Pointer to the first byte being read by DMA |
131 | * or current position in out_buffer if not using DMA. */ | ||
132 | unsigned char *out_rd_ptr; | ||
133 | |||
134 | /* Number of bytes currently locked for being read by DMA */ | ||
135 | int out_buf_count; | ||
136 | |||
137 | dma_descr_data in_descr[NBR_IN_DESCR] __attribute__ ((__aligned__(16))); | ||
114 | dma_descr_context in_context __attribute__ ((__aligned__(32))); | 138 | dma_descr_context in_context __attribute__ ((__aligned__(32))); |
115 | dma_descr_data out_descr __attribute__ ((__aligned__(16))); | 139 | dma_descr_data out_descr[NBR_OUT_DESCR] |
140 | __attribute__ ((__aligned__(16))); | ||
116 | dma_descr_context out_context __attribute__ ((__aligned__(32))); | 141 | dma_descr_context out_context __attribute__ ((__aligned__(32))); |
117 | wait_queue_head_t out_wait_q; | 142 | wait_queue_head_t out_wait_q; |
118 | wait_queue_head_t in_wait_q; | 143 | wait_queue_head_t in_wait_q; |
@@ -143,11 +168,11 @@ static ssize_t sync_serial_read(struct file *file, char *buf, | |||
143 | #endif | 168 | #endif |
144 | 169 | ||
145 | static void send_word(sync_port* port); | 170 | static void send_word(sync_port* port); |
146 | static void start_dma(struct sync_port *port, const char* data, int count); | 171 | static void start_dma_out(struct sync_port *port, const char *data, int count); |
147 | static void start_dma_in(sync_port* port); | 172 | static void start_dma_in(sync_port* port); |
148 | #ifdef SYNC_SER_DMA | 173 | #ifdef SYNC_SER_DMA |
149 | static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); | 174 | static irqreturn_t tr_interrupt(int irq, void *dev_id); |
150 | static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); | 175 | static irqreturn_t rx_interrupt(int irq, void *dev_id); |
151 | #endif | 176 | #endif |
152 | 177 | ||
153 | #if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ | 178 | #if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ |
@@ -157,22 +182,49 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); | |||
157 | #define SYNC_SER_MANUAL | 182 | #define SYNC_SER_MANUAL |
158 | #endif | 183 | #endif |
159 | #ifdef SYNC_SER_MANUAL | 184 | #ifdef SYNC_SER_MANUAL |
160 | static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); | 185 | static irqreturn_t manual_interrupt(int irq, void *dev_id); |
186 | #endif | ||
187 | |||
188 | #ifdef CONFIG_ETRAXFS /* ETRAX FS */ | ||
189 | #define OUT_DMA_NBR 4 | ||
190 | #define IN_DMA_NBR 5 | ||
191 | #define PINMUX_SSER pinmux_sser0 | ||
192 | #define SYNCSER_INST regi_sser0 | ||
193 | #define SYNCSER_INTR_VECT SSER0_INTR_VECT | ||
194 | #define OUT_DMA_INST regi_dma4 | ||
195 | #define IN_DMA_INST regi_dma5 | ||
196 | #define DMA_OUT_INTR_VECT DMA4_INTR_VECT | ||
197 | #define DMA_IN_INTR_VECT DMA5_INTR_VECT | ||
198 | #define REQ_DMA_SYNCSER dma_sser0 | ||
199 | #else /* Artpec-3 */ | ||
200 | #define OUT_DMA_NBR 6 | ||
201 | #define IN_DMA_NBR 7 | ||
202 | #define PINMUX_SSER pinmux_sser | ||
203 | #define SYNCSER_INST regi_sser | ||
204 | #define SYNCSER_INTR_VECT SSER_INTR_VECT | ||
205 | #define OUT_DMA_INST regi_dma6 | ||
206 | #define IN_DMA_INST regi_dma7 | ||
207 | #define DMA_OUT_INTR_VECT DMA6_INTR_VECT | ||
208 | #define DMA_IN_INTR_VECT DMA7_INTR_VECT | ||
209 | #define REQ_DMA_SYNCSER dma_sser | ||
161 | #endif | 210 | #endif |
162 | 211 | ||
163 | /* The ports */ | 212 | /* The ports */ |
164 | static struct sync_port ports[]= | 213 | static struct sync_port ports[]= |
165 | { | 214 | { |
166 | { | 215 | { |
167 | .regi_sser = regi_sser0, | 216 | .regi_sser = SYNCSER_INST, |
168 | .regi_dmaout = regi_dma4, | 217 | .regi_dmaout = OUT_DMA_INST, |
169 | .regi_dmain = regi_dma5, | 218 | .regi_dmain = IN_DMA_INST, |
170 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) | 219 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) |
171 | .use_dma = 1, | 220 | .use_dma = 1, |
172 | #else | 221 | #else |
173 | .use_dma = 0, | 222 | .use_dma = 0, |
174 | #endif | 223 | #endif |
175 | }, | 224 | } |
225 | #ifdef CONFIG_ETRAXFS | ||
226 | , | ||
227 | |||
176 | { | 228 | { |
177 | .regi_sser = regi_sser1, | 229 | .regi_sser = regi_sser1, |
178 | .regi_dmaout = regi_dma6, | 230 | .regi_dmaout = regi_dma6, |
@@ -183,9 +235,10 @@ static struct sync_port ports[]= | |||
183 | .use_dma = 0, | 235 | .use_dma = 0, |
184 | #endif | 236 | #endif |
185 | } | 237 | } |
238 | #endif | ||
186 | }; | 239 | }; |
187 | 240 | ||
188 | #define NUMBER_OF_PORTS ARRAY_SIZE(ports) | 241 | #define NBR_PORTS ARRAY_SIZE(ports) |
189 | 242 | ||
190 | static const struct file_operations sync_serial_fops = { | 243 | static const struct file_operations sync_serial_fops = { |
191 | .owner = THIS_MODULE, | 244 | .owner = THIS_MODULE, |
@@ -200,19 +253,21 @@ static const struct file_operations sync_serial_fops = { | |||
200 | static int __init etrax_sync_serial_init(void) | 253 | static int __init etrax_sync_serial_init(void) |
201 | { | 254 | { |
202 | ports[0].enabled = 0; | 255 | ports[0].enabled = 0; |
256 | #ifdef CONFIG_ETRAXFS | ||
203 | ports[1].enabled = 0; | 257 | ports[1].enabled = 0; |
204 | 258 | #endif | |
205 | if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) | 259 | if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial", |
206 | { | 260 | &sync_serial_fops) < 0) { |
207 | printk("unable to get major for synchronous serial port\n"); | 261 | printk(KERN_WARNING |
262 | "Unable to get major for synchronous serial port\n"); | ||
208 | return -EBUSY; | 263 | return -EBUSY; |
209 | } | 264 | } |
210 | 265 | ||
211 | /* Initialize Ports */ | 266 | /* Initialize Ports */ |
212 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) | 267 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) |
213 | if (crisv32_pinmux_alloc_fixed(pinmux_sser0)) | 268 | if (crisv32_pinmux_alloc_fixed(PINMUX_SSER)) { |
214 | { | 269 | printk(KERN_WARNING |
215 | printk("Unable to allocate pins for syncrhronous serial port 0\n"); | 270 | "Unable to alloc pins for synchronous serial port 0\n"); |
216 | return -EIO; | 271 | return -EIO; |
217 | } | 272 | } |
218 | ports[0].enabled = 1; | 273 | ports[0].enabled = 1; |
@@ -220,33 +275,40 @@ static int __init etrax_sync_serial_init(void) | |||
220 | #endif | 275 | #endif |
221 | 276 | ||
222 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) | 277 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) |
223 | if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) | 278 | if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) { |
224 | { | 279 | printk(KERN_WARNING |
225 | printk("Unable to allocate pins for syncrhronous serial port 0\n"); | 280 | "Unable to alloc pins for synchronous serial port 0\n"); |
226 | return -EIO; | 281 | return -EIO; |
227 | } | 282 | } |
228 | ports[1].enabled = 1; | 283 | ports[1].enabled = 1; |
229 | initialize_port(1); | 284 | initialize_port(1); |
230 | #endif | 285 | #endif |
231 | 286 | ||
232 | printk("ETRAX FS synchronous serial port driver\n"); | 287 | #ifdef CONFIG_ETRAXFS |
288 | printk(KERN_INFO "ETRAX FS synchronous serial port driver\n"); | ||
289 | #else | ||
290 | printk(KERN_INFO "Artpec-3 synchronous serial port driver\n"); | ||
291 | #endif | ||
233 | return 0; | 292 | return 0; |
234 | } | 293 | } |
235 | 294 | ||
236 | static void __init initialize_port(int portnbr) | 295 | static void __init initialize_port(int portnbr) |
237 | { | 296 | { |
238 | struct sync_port* port = &ports[portnbr]; | 297 | int __attribute__((unused)) i; |
298 | struct sync_port *port = &ports[portnbr]; | ||
239 | reg_sser_rw_cfg cfg = {0}; | 299 | reg_sser_rw_cfg cfg = {0}; |
240 | reg_sser_rw_frm_cfg frm_cfg = {0}; | 300 | reg_sser_rw_frm_cfg frm_cfg = {0}; |
241 | reg_sser_rw_tr_cfg tr_cfg = {0}; | 301 | reg_sser_rw_tr_cfg tr_cfg = {0}; |
242 | reg_sser_rw_rec_cfg rec_cfg = {0}; | 302 | reg_sser_rw_rec_cfg rec_cfg = {0}; |
243 | 303 | ||
244 | DEBUG(printk("Init sync serial port %d\n", portnbr)); | 304 | DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr)); |
245 | 305 | ||
246 | port->port_nbr = portnbr; | 306 | port->port_nbr = portnbr; |
247 | port->init_irqs = 1; | 307 | port->init_irqs = 1; |
248 | 308 | ||
249 | port->outp = port->out_buffer; | 309 | port->out_rd_ptr = port->out_buffer; |
310 | port->out_buf_count = 0; | ||
311 | |||
250 | port->output = 1; | 312 | port->output = 1; |
251 | port->input = 0; | 313 | port->input = 0; |
252 | 314 | ||
@@ -255,7 +317,7 @@ static void __init initialize_port(int portnbr) | |||
255 | port->in_buffer_size = IN_BUFFER_SIZE; | 317 | port->in_buffer_size = IN_BUFFER_SIZE; |
256 | port->inbufchunk = IN_DESCR_SIZE; | 318 | port->inbufchunk = IN_DESCR_SIZE; |
257 | port->next_rx_desc = &port->in_descr[0]; | 319 | port->next_rx_desc = &port->in_descr[0]; |
258 | port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR-1]; | 320 | port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR-1]; |
259 | port->prev_rx_desc->eol = 1; | 321 | port->prev_rx_desc->eol = 1; |
260 | 322 | ||
261 | init_waitqueue_head(&port->out_wait_q); | 323 | init_waitqueue_head(&port->out_wait_q); |
@@ -286,8 +348,13 @@ static void __init initialize_port(int portnbr) | |||
286 | tr_cfg.sample_size = 7; | 348 | tr_cfg.sample_size = 7; |
287 | tr_cfg.sh_dir = regk_sser_msbfirst; | 349 | tr_cfg.sh_dir = regk_sser_msbfirst; |
288 | tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; | 350 | tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; |
351 | #if 0 | ||
289 | tr_cfg.rate_ctrl = regk_sser_bulk; | 352 | tr_cfg.rate_ctrl = regk_sser_bulk; |
290 | tr_cfg.data_pin_use = regk_sser_dout; | 353 | tr_cfg.data_pin_use = regk_sser_dout; |
354 | #else | ||
355 | tr_cfg.rate_ctrl = regk_sser_iso; | ||
356 | tr_cfg.data_pin_use = regk_sser_dout; | ||
357 | #endif | ||
291 | tr_cfg.bulk_wspace = 1; | 358 | tr_cfg.bulk_wspace = 1; |
292 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | 359 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); |
293 | 360 | ||
@@ -296,6 +363,27 @@ static void __init initialize_port(int portnbr) | |||
296 | rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; | 363 | rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; |
297 | rec_cfg.fifo_thr = regk_sser_inf; | 364 | rec_cfg.fifo_thr = regk_sser_inf; |
298 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | 365 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); |
366 | |||
367 | #ifdef SYNC_SER_DMA | ||
368 | /* Setup the descriptor ring for dma out/transmit. */ | ||
369 | for (i = 0; i < NBR_OUT_DESCR; i++) { | ||
370 | port->out_descr[i].wait = 0; | ||
371 | port->out_descr[i].intr = 1; | ||
372 | port->out_descr[i].eol = 0; | ||
373 | port->out_descr[i].out_eop = 0; | ||
374 | port->out_descr[i].next = | ||
375 | (dma_descr_data *)virt_to_phys(&port->out_descr[i+1]); | ||
376 | } | ||
377 | |||
378 | /* Create a ring from the list. */ | ||
379 | port->out_descr[NBR_OUT_DESCR-1].next = | ||
380 | (dma_descr_data *)virt_to_phys(&port->out_descr[0]); | ||
381 | |||
382 | /* Setup context for traversing the ring. */ | ||
383 | port->active_tr_descr = &port->out_descr[0]; | ||
384 | port->prev_tr_descr = &port->out_descr[NBR_OUT_DESCR-1]; | ||
385 | port->catch_tr_descr = &port->out_descr[0]; | ||
386 | #endif | ||
299 | } | 387 | } |
300 | 388 | ||
301 | static inline int sync_data_avail(struct sync_port *port) | 389 | static inline int sync_data_avail(struct sync_port *port) |
@@ -311,7 +399,7 @@ static inline int sync_data_avail(struct sync_port *port) | |||
311 | * ^rp ^wp ^wp ^rp | 399 | * ^rp ^wp ^wp ^rp |
312 | */ | 400 | */ |
313 | 401 | ||
314 | if (end >= start) | 402 | if (end >= start) |
315 | avail = end - start; | 403 | avail = end - start; |
316 | else | 404 | else |
317 | avail = port->in_buffer_size - (start - end); | 405 | avail = port->in_buffer_size - (start - end); |
@@ -331,7 +419,7 @@ static inline int sync_data_avail_to_end(struct sync_port *port) | |||
331 | * ^rp ^wp ^wp ^rp | 419 | * ^rp ^wp ^wp ^rp |
332 | */ | 420 | */ |
333 | 421 | ||
334 | if (end >= start) | 422 | if (end >= start) |
335 | avail = end - start; | 423 | avail = end - start; |
336 | else | 424 | else |
337 | avail = port->flip + port->in_buffer_size - start; | 425 | avail = port->flip + port->in_buffer_size - start; |
@@ -341,66 +429,69 @@ static inline int sync_data_avail_to_end(struct sync_port *port) | |||
341 | static int sync_serial_open(struct inode *inode, struct file *file) | 429 | static int sync_serial_open(struct inode *inode, struct file *file) |
342 | { | 430 | { |
343 | int dev = iminor(inode); | 431 | int dev = iminor(inode); |
344 | sync_port* port; | 432 | sync_port *port; |
345 | reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; | 433 | reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; |
346 | reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; | 434 | reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; |
347 | 435 | ||
348 | DEBUG(printk("Open sync serial port %d\n", dev)); | 436 | DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev)); |
349 | 437 | ||
350 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | 438 | if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) |
351 | { | 439 | { |
352 | DEBUG(printk("Invalid minor %d\n", dev)); | 440 | DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev)); |
353 | return -ENODEV; | 441 | return -ENODEV; |
354 | } | 442 | } |
355 | port = &ports[dev]; | 443 | port = &ports[dev]; |
356 | /* Allow open this device twice (assuming one reader and one writer) */ | 444 | /* Allow open this device twice (assuming one reader and one writer) */ |
357 | if (port->busy == 2) | 445 | if (port->busy == 2) |
358 | { | 446 | { |
359 | DEBUG(printk("Device is busy.. \n")); | 447 | DEBUG(printk(KERN_DEBUG "Device is busy.. \n")); |
360 | return -EBUSY; | 448 | return -EBUSY; |
361 | } | 449 | } |
450 | |||
451 | |||
362 | if (port->init_irqs) { | 452 | if (port->init_irqs) { |
363 | if (port->use_dma) { | 453 | if (port->use_dma) { |
364 | if (port == &ports[0]){ | 454 | if (port == &ports[0]) { |
365 | #ifdef SYNC_SER_DMA | 455 | #ifdef SYNC_SER_DMA |
366 | if(request_irq(DMA4_INTR_VECT, | 456 | if (request_irq(DMA_OUT_INTR_VECT, |
367 | tr_interrupt, | 457 | tr_interrupt, |
368 | 0, | 458 | 0, |
369 | "synchronous serial 0 dma tr", | 459 | "synchronous serial 0 dma tr", |
370 | &ports[0])) { | 460 | &ports[0])) { |
371 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); | 461 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); |
372 | return -EBUSY; | 462 | return -EBUSY; |
373 | } else if(request_irq(DMA5_INTR_VECT, | 463 | } else if (request_irq(DMA_IN_INTR_VECT, |
374 | rx_interrupt, | 464 | rx_interrupt, |
375 | 0, | 465 | 0, |
376 | "synchronous serial 1 dma rx", | 466 | "synchronous serial 1 dma rx", |
377 | &ports[0])) { | 467 | &ports[0])) { |
378 | free_irq(DMA4_INTR_VECT, &port[0]); | 468 | free_irq(DMA_OUT_INTR_VECT, &port[0]); |
379 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); | 469 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); |
380 | return -EBUSY; | 470 | return -EBUSY; |
381 | } else if (crisv32_request_dma(SYNC_SER0_TX_DMA_NBR, | 471 | } else if (crisv32_request_dma(OUT_DMA_NBR, |
382 | "synchronous serial 0 dma tr", | 472 | "synchronous serial 0 dma tr", |
383 | DMA_VERBOSE_ON_ERROR, | 473 | DMA_VERBOSE_ON_ERROR, |
384 | 0, | 474 | 0, |
385 | dma_sser0)) { | 475 | REQ_DMA_SYNCSER)) { |
386 | free_irq(DMA4_INTR_VECT, &port[0]); | 476 | free_irq(DMA_OUT_INTR_VECT, &port[0]); |
387 | free_irq(DMA5_INTR_VECT, &port[0]); | 477 | free_irq(DMA_IN_INTR_VECT, &port[0]); |
388 | printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); | 478 | printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); |
389 | return -EBUSY; | 479 | return -EBUSY; |
390 | } else if (crisv32_request_dma(SYNC_SER0_RX_DMA_NBR, | 480 | } else if (crisv32_request_dma(IN_DMA_NBR, |
391 | "synchronous serial 0 dma rec", | 481 | "synchronous serial 0 dma rec", |
392 | DMA_VERBOSE_ON_ERROR, | 482 | DMA_VERBOSE_ON_ERROR, |
393 | 0, | 483 | 0, |
394 | dma_sser0)) { | 484 | REQ_DMA_SYNCSER)) { |
395 | crisv32_free_dma(SYNC_SER0_TX_DMA_NBR); | 485 | crisv32_free_dma(OUT_DMA_NBR); |
396 | free_irq(DMA4_INTR_VECT, &port[0]); | 486 | free_irq(DMA_OUT_INTR_VECT, &port[0]); |
397 | free_irq(DMA5_INTR_VECT, &port[0]); | 487 | free_irq(DMA_IN_INTR_VECT, &port[0]); |
398 | printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); | 488 | printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); |
399 | return -EBUSY; | 489 | return -EBUSY; |
400 | } | 490 | } |
401 | #endif | 491 | #endif |
402 | } | 492 | } |
403 | else if (port == &ports[1]){ | 493 | #ifdef CONFIG_ETRAXFS |
494 | else if (port == &ports[1]) { | ||
404 | #ifdef SYNC_SER_DMA | 495 | #ifdef SYNC_SER_DMA |
405 | if (request_irq(DMA6_INTR_VECT, | 496 | if (request_irq(DMA6_INTR_VECT, |
406 | tr_interrupt, | 497 | tr_interrupt, |
@@ -417,20 +508,22 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
417 | free_irq(DMA6_INTR_VECT, &ports[1]); | 508 | free_irq(DMA6_INTR_VECT, &ports[1]); |
418 | printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); | 509 | printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); |
419 | return -EBUSY; | 510 | return -EBUSY; |
420 | } else if (crisv32_request_dma(SYNC_SER1_TX_DMA_NBR, | 511 | } else if (crisv32_request_dma( |
421 | "synchronous serial 1 dma tr", | 512 | SYNC_SER1_TX_DMA_NBR, |
422 | DMA_VERBOSE_ON_ERROR, | 513 | "synchronous serial 1 dma tr", |
423 | 0, | 514 | DMA_VERBOSE_ON_ERROR, |
424 | dma_sser1)) { | 515 | 0, |
425 | free_irq(21, &ports[1]); | 516 | dma_sser1)) { |
426 | free_irq(20, &ports[1]); | 517 | free_irq(DMA6_INTR_VECT, &ports[1]); |
518 | free_irq(DMA7_INTR_VECT, &ports[1]); | ||
427 | printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); | 519 | printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); |
428 | return -EBUSY; | 520 | return -EBUSY; |
429 | } else if (crisv32_request_dma(SYNC_SER1_RX_DMA_NBR, | 521 | } else if (crisv32_request_dma( |
430 | "synchronous serial 3 dma rec", | 522 | SYNC_SER1_RX_DMA_NBR, |
431 | DMA_VERBOSE_ON_ERROR, | 523 | "synchronous serial 3 dma rec", |
432 | 0, | 524 | DMA_VERBOSE_ON_ERROR, |
433 | dma_sser1)) { | 525 | 0, |
526 | dma_sser1)) { | ||
434 | crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); | 527 | crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); |
435 | free_irq(DMA6_INTR_VECT, &ports[1]); | 528 | free_irq(DMA6_INTR_VECT, &ports[1]); |
436 | free_irq(DMA7_INTR_VECT, &ports[1]); | 529 | free_irq(DMA7_INTR_VECT, &ports[1]); |
@@ -439,14 +532,14 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
439 | } | 532 | } |
440 | #endif | 533 | #endif |
441 | } | 534 | } |
442 | 535 | #endif | |
443 | /* Enable DMAs */ | 536 | /* Enable DMAs */ |
444 | REG_WR(dma, port->regi_dmain, rw_cfg, cfg); | 537 | REG_WR(dma, port->regi_dmain, rw_cfg, cfg); |
445 | REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); | 538 | REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); |
446 | /* Enable DMA IRQs */ | 539 | /* Enable DMA IRQs */ |
447 | REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); | 540 | REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); |
448 | REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); | 541 | REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); |
449 | /* Set up wordsize = 2 for DMAs. */ | 542 | /* Set up wordsize = 1 for DMAs. */ |
450 | DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1); | 543 | DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1); |
451 | DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1); | 544 | DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1); |
452 | 545 | ||
@@ -455,7 +548,7 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
455 | } else { /* !port->use_dma */ | 548 | } else { /* !port->use_dma */ |
456 | #ifdef SYNC_SER_MANUAL | 549 | #ifdef SYNC_SER_MANUAL |
457 | if (port == &ports[0]) { | 550 | if (port == &ports[0]) { |
458 | if (request_irq(SSER0_INTR_VECT, | 551 | if (request_irq(SYNCSER_INTR_VECT, |
459 | manual_interrupt, | 552 | manual_interrupt, |
460 | 0, | 553 | 0, |
461 | "synchronous serial manual irq", | 554 | "synchronous serial manual irq", |
@@ -463,7 +556,9 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
463 | printk("Can't allocate sync serial manual irq"); | 556 | printk("Can't allocate sync serial manual irq"); |
464 | return -EBUSY; | 557 | return -EBUSY; |
465 | } | 558 | } |
466 | } else if (port == &ports[1]) { | 559 | } |
560 | #ifdef CONFIG_ETRAXFS | ||
561 | else if (port == &ports[1]) { | ||
467 | if (request_irq(SSER1_INTR_VECT, | 562 | if (request_irq(SSER1_INTR_VECT, |
468 | manual_interrupt, | 563 | manual_interrupt, |
469 | 0, | 564 | 0, |
@@ -473,11 +568,13 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
473 | return -EBUSY; | 568 | return -EBUSY; |
474 | } | 569 | } |
475 | } | 570 | } |
571 | #endif | ||
476 | port->init_irqs = 0; | 572 | port->init_irqs = 0; |
477 | #else | 573 | #else |
478 | panic("sync_serial: Manual mode not supported.\n"); | 574 | panic("sync_serial: Manual mode not supported.\n"); |
479 | #endif /* SYNC_SER_MANUAL */ | 575 | #endif /* SYNC_SER_MANUAL */ |
480 | } | 576 | } |
577 | |||
481 | } /* port->init_irqs */ | 578 | } /* port->init_irqs */ |
482 | 579 | ||
483 | port->busy++; | 580 | port->busy++; |
@@ -487,9 +584,9 @@ static int sync_serial_open(struct inode *inode, struct file *file) | |||
487 | static int sync_serial_release(struct inode *inode, struct file *file) | 584 | static int sync_serial_release(struct inode *inode, struct file *file) |
488 | { | 585 | { |
489 | int dev = iminor(inode); | 586 | int dev = iminor(inode); |
490 | sync_port* port; | 587 | sync_port *port; |
491 | 588 | ||
492 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | 589 | if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) |
493 | { | 590 | { |
494 | DEBUG(printk("Invalid minor %d\n", dev)); | 591 | DEBUG(printk("Invalid minor %d\n", dev)); |
495 | return -ENODEV; | 592 | return -ENODEV; |
@@ -506,17 +603,37 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) | |||
506 | { | 603 | { |
507 | int dev = iminor(file->f_path.dentry->d_inode); | 604 | int dev = iminor(file->f_path.dentry->d_inode); |
508 | unsigned int mask = 0; | 605 | unsigned int mask = 0; |
509 | sync_port* port; | 606 | sync_port *port; |
510 | DEBUGPOLL( static unsigned int prev_mask = 0; ); | 607 | DEBUGPOLL( static unsigned int prev_mask = 0; ); |
511 | 608 | ||
512 | port = &ports[dev]; | 609 | port = &ports[dev]; |
610 | |||
611 | if (!port->started) { | ||
612 | reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); | ||
613 | reg_sser_rw_rec_cfg rec_cfg = | ||
614 | REG_RD(sser, port->regi_sser, rw_rec_cfg); | ||
615 | cfg.en = regk_sser_yes; | ||
616 | rec_cfg.rec_en = port->input; | ||
617 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); | ||
618 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | ||
619 | port->started = 1; | ||
620 | } | ||
621 | |||
513 | poll_wait(file, &port->out_wait_q, wait); | 622 | poll_wait(file, &port->out_wait_q, wait); |
514 | poll_wait(file, &port->in_wait_q, wait); | 623 | poll_wait(file, &port->in_wait_q, wait); |
515 | /* Some room to write */ | 624 | |
516 | if (port->out_count < OUT_BUFFER_SIZE) | 625 | /* No active transfer, descriptors are available */ |
626 | if (port->output && !port->tr_running) | ||
627 | mask |= POLLOUT | POLLWRNORM; | ||
628 | |||
629 | /* Descriptor and buffer space available. */ | ||
630 | if (port->output && | ||
631 | port->active_tr_descr != port->catch_tr_descr && | ||
632 | port->out_buf_count < OUT_BUFFER_SIZE) | ||
517 | mask |= POLLOUT | POLLWRNORM; | 633 | mask |= POLLOUT | POLLWRNORM; |
634 | |||
518 | /* At least an inbufchunk of data */ | 635 | /* At least an inbufchunk of data */ |
519 | if (sync_data_avail(port) >= port->inbufchunk) | 636 | if (port->input && sync_data_avail(port) >= port->inbufchunk) |
520 | mask |= POLLIN | POLLRDNORM; | 637 | mask |= POLLIN | POLLRDNORM; |
521 | 638 | ||
522 | DEBUGPOLL(if (mask != prev_mask) | 639 | DEBUGPOLL(if (mask != prev_mask) |
@@ -531,15 +648,16 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
531 | unsigned int cmd, unsigned long arg) | 648 | unsigned int cmd, unsigned long arg) |
532 | { | 649 | { |
533 | int return_val = 0; | 650 | int return_val = 0; |
651 | int dma_w_size = regk_dma_set_w_size1; | ||
534 | int dev = iminor(file->f_path.dentry->d_inode); | 652 | int dev = iminor(file->f_path.dentry->d_inode); |
535 | sync_port* port; | 653 | sync_port *port; |
536 | reg_sser_rw_tr_cfg tr_cfg; | 654 | reg_sser_rw_tr_cfg tr_cfg; |
537 | reg_sser_rw_rec_cfg rec_cfg; | 655 | reg_sser_rw_rec_cfg rec_cfg; |
538 | reg_sser_rw_frm_cfg frm_cfg; | 656 | reg_sser_rw_frm_cfg frm_cfg; |
539 | reg_sser_rw_cfg gen_cfg; | 657 | reg_sser_rw_cfg gen_cfg; |
540 | reg_sser_rw_intr_mask intr_mask; | 658 | reg_sser_rw_intr_mask intr_mask; |
541 | 659 | ||
542 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | 660 | if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) |
543 | { | 661 | { |
544 | DEBUG(printk("Invalid minor %d\n", dev)); | 662 | DEBUG(printk("Invalid minor %d\n", dev)); |
545 | return -1; | 663 | return -1; |
@@ -558,61 +676,81 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
558 | case SSP_SPEED: | 676 | case SSP_SPEED: |
559 | if (GET_SPEED(arg) == CODEC) | 677 | if (GET_SPEED(arg) == CODEC) |
560 | { | 678 | { |
679 | unsigned int freq; | ||
680 | |||
561 | gen_cfg.base_freq = regk_sser_f32; | 681 | gen_cfg.base_freq = regk_sser_f32; |
562 | /* FREQ = 0 => 4 MHz => clk_div = 7*/ | 682 | |
563 | gen_cfg.clk_div = 6 + (1 << GET_FREQ(arg)); | 683 | /* Clock divider will internally be |
564 | } | 684 | * gen_cfg.clk_div + 1. |
565 | else | 685 | */ |
566 | { | 686 | |
687 | freq = GET_FREQ(arg); | ||
688 | switch (freq) { | ||
689 | case FREQ_32kHz: | ||
690 | case FREQ_64kHz: | ||
691 | case FREQ_128kHz: | ||
692 | case FREQ_256kHz: | ||
693 | gen_cfg.clk_div = 125 * | ||
694 | (1 << (freq - FREQ_256kHz)) - 1; | ||
695 | break; | ||
696 | case FREQ_512kHz: | ||
697 | gen_cfg.clk_div = 62; | ||
698 | break; | ||
699 | case FREQ_1MHz: | ||
700 | case FREQ_2MHz: | ||
701 | case FREQ_4MHz: | ||
702 | gen_cfg.clk_div = 8 * (1 << freq) - 1; | ||
703 | break; | ||
704 | } | ||
705 | } else { | ||
567 | gen_cfg.base_freq = regk_sser_f29_493; | 706 | gen_cfg.base_freq = regk_sser_f29_493; |
568 | switch (GET_SPEED(arg)) | 707 | switch (GET_SPEED(arg)) { |
569 | { | 708 | case SSP150: |
570 | case SSP150: | 709 | gen_cfg.clk_div = 29493000 / (150 * 8) - 1; |
571 | gen_cfg.clk_div = 29493000 / (150 * 8) - 1; | 710 | break; |
572 | break; | 711 | case SSP300: |
573 | case SSP300: | 712 | gen_cfg.clk_div = 29493000 / (300 * 8) - 1; |
574 | gen_cfg.clk_div = 29493000 / (300 * 8) - 1; | 713 | break; |
575 | break; | 714 | case SSP600: |
576 | case SSP600: | 715 | gen_cfg.clk_div = 29493000 / (600 * 8) - 1; |
577 | gen_cfg.clk_div = 29493000 / (600 * 8) - 1; | 716 | break; |
578 | break; | 717 | case SSP1200: |
579 | case SSP1200: | 718 | gen_cfg.clk_div = 29493000 / (1200 * 8) - 1; |
580 | gen_cfg.clk_div = 29493000 / (1200 * 8) - 1; | 719 | break; |
581 | break; | 720 | case SSP2400: |
582 | case SSP2400: | 721 | gen_cfg.clk_div = 29493000 / (2400 * 8) - 1; |
583 | gen_cfg.clk_div = 29493000 / (2400 * 8) - 1; | 722 | break; |
584 | break; | 723 | case SSP4800: |
585 | case SSP4800: | 724 | gen_cfg.clk_div = 29493000 / (4800 * 8) - 1; |
586 | gen_cfg.clk_div = 29493000 / (4800 * 8) - 1; | 725 | break; |
587 | break; | 726 | case SSP9600: |
588 | case SSP9600: | 727 | gen_cfg.clk_div = 29493000 / (9600 * 8) - 1; |
589 | gen_cfg.clk_div = 29493000 / (9600 * 8) - 1; | 728 | break; |
590 | break; | 729 | case SSP19200: |
591 | case SSP19200: | 730 | gen_cfg.clk_div = 29493000 / (19200 * 8) - 1; |
592 | gen_cfg.clk_div = 29493000 / (19200 * 8) - 1; | 731 | break; |
593 | break; | 732 | case SSP28800: |
594 | case SSP28800: | 733 | gen_cfg.clk_div = 29493000 / (28800 * 8) - 1; |
595 | gen_cfg.clk_div = 29493000 / (28800 * 8) - 1; | 734 | break; |
596 | break; | 735 | case SSP57600: |
597 | case SSP57600: | 736 | gen_cfg.clk_div = 29493000 / (57600 * 8) - 1; |
598 | gen_cfg.clk_div = 29493000 / (57600 * 8) - 1; | 737 | break; |
599 | break; | 738 | case SSP115200: |
600 | case SSP115200: | 739 | gen_cfg.clk_div = 29493000 / (115200 * 8) - 1; |
601 | gen_cfg.clk_div = 29493000 / (115200 * 8) - 1; | 740 | break; |
602 | break; | 741 | case SSP230400: |
603 | case SSP230400: | 742 | gen_cfg.clk_div = 29493000 / (230400 * 8) - 1; |
604 | gen_cfg.clk_div = 29493000 / (230400 * 8) - 1; | 743 | break; |
605 | break; | 744 | case SSP460800: |
606 | case SSP460800: | 745 | gen_cfg.clk_div = 29493000 / (460800 * 8) - 1; |
607 | gen_cfg.clk_div = 29493000 / (460800 * 8) - 1; | 746 | break; |
608 | break; | 747 | case SSP921600: |
609 | case SSP921600: | 748 | gen_cfg.clk_div = 29493000 / (921600 * 8) - 1; |
610 | gen_cfg.clk_div = 29493000 / (921600 * 8) - 1; | 749 | break; |
611 | break; | 750 | case SSP3125000: |
612 | case SSP3125000: | 751 | gen_cfg.base_freq = regk_sser_f100; |
613 | gen_cfg.base_freq = regk_sser_f100; | 752 | gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1; |
614 | gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1; | 753 | break; |
615 | break; | ||
616 | 754 | ||
617 | } | 755 | } |
618 | } | 756 | } |
@@ -625,46 +763,60 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
625 | case MASTER_OUTPUT: | 763 | case MASTER_OUTPUT: |
626 | port->output = 1; | 764 | port->output = 1; |
627 | port->input = 0; | 765 | port->input = 0; |
766 | frm_cfg.out_on = regk_sser_tr; | ||
767 | frm_cfg.frame_pin_dir = regk_sser_out; | ||
628 | gen_cfg.clk_dir = regk_sser_out; | 768 | gen_cfg.clk_dir = regk_sser_out; |
629 | break; | 769 | break; |
630 | case SLAVE_OUTPUT: | 770 | case SLAVE_OUTPUT: |
631 | port->output = 1; | 771 | port->output = 1; |
632 | port->input = 0; | 772 | port->input = 0; |
773 | frm_cfg.frame_pin_dir = regk_sser_in; | ||
633 | gen_cfg.clk_dir = regk_sser_in; | 774 | gen_cfg.clk_dir = regk_sser_in; |
634 | break; | 775 | break; |
635 | case MASTER_INPUT: | 776 | case MASTER_INPUT: |
636 | port->output = 0; | 777 | port->output = 0; |
637 | port->input = 1; | 778 | port->input = 1; |
779 | frm_cfg.frame_pin_dir = regk_sser_out; | ||
780 | frm_cfg.out_on = regk_sser_intern_tb; | ||
638 | gen_cfg.clk_dir = regk_sser_out; | 781 | gen_cfg.clk_dir = regk_sser_out; |
639 | break; | 782 | break; |
640 | case SLAVE_INPUT: | 783 | case SLAVE_INPUT: |
641 | port->output = 0; | 784 | port->output = 0; |
642 | port->input = 1; | 785 | port->input = 1; |
786 | frm_cfg.frame_pin_dir = regk_sser_in; | ||
643 | gen_cfg.clk_dir = regk_sser_in; | 787 | gen_cfg.clk_dir = regk_sser_in; |
644 | break; | 788 | break; |
645 | case MASTER_BIDIR: | 789 | case MASTER_BIDIR: |
646 | port->output = 1; | 790 | port->output = 1; |
647 | port->input = 1; | 791 | port->input = 1; |
792 | frm_cfg.frame_pin_dir = regk_sser_out; | ||
793 | frm_cfg.out_on = regk_sser_intern_tb; | ||
648 | gen_cfg.clk_dir = regk_sser_out; | 794 | gen_cfg.clk_dir = regk_sser_out; |
649 | break; | 795 | break; |
650 | case SLAVE_BIDIR: | 796 | case SLAVE_BIDIR: |
651 | port->output = 1; | 797 | port->output = 1; |
652 | port->input = 1; | 798 | port->input = 1; |
799 | frm_cfg.frame_pin_dir = regk_sser_in; | ||
653 | gen_cfg.clk_dir = regk_sser_in; | 800 | gen_cfg.clk_dir = regk_sser_in; |
654 | break; | 801 | break; |
655 | default: | 802 | default: |
656 | spin_unlock_irq(&port->lock); | 803 | spin_unlock_irq(&port->lock); |
657 | return -EINVAL; | 804 | return -EINVAL; |
658 | |||
659 | } | 805 | } |
660 | if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)) | 806 | if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)) |
661 | intr_mask.rdav = regk_sser_yes; | 807 | intr_mask.rdav = regk_sser_yes; |
662 | break; | 808 | break; |
663 | case SSP_FRAME_SYNC: | 809 | case SSP_FRAME_SYNC: |
664 | if (arg & NORMAL_SYNC) | 810 | if (arg & NORMAL_SYNC) { |
811 | frm_cfg.rec_delay = 1; | ||
665 | frm_cfg.tr_delay = 1; | 812 | frm_cfg.tr_delay = 1; |
813 | } | ||
666 | else if (arg & EARLY_SYNC) | 814 | else if (arg & EARLY_SYNC) |
667 | frm_cfg.tr_delay = 0; | 815 | frm_cfg.rec_delay = frm_cfg.tr_delay = 0; |
816 | else if (arg & SECOND_WORD_SYNC) { | ||
817 | frm_cfg.rec_delay = 7; | ||
818 | frm_cfg.tr_delay = 1; | ||
819 | } | ||
668 | 820 | ||
669 | tr_cfg.bulk_wspace = frm_cfg.tr_delay; | 821 | tr_cfg.bulk_wspace = frm_cfg.tr_delay; |
670 | frm_cfg.early_wend = regk_sser_yes; | 822 | frm_cfg.early_wend = regk_sser_yes; |
@@ -680,9 +832,11 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
680 | else if (arg & SYNC_OFF) | 832 | else if (arg & SYNC_OFF) |
681 | frm_cfg.frame_pin_use = regk_sser_gio0; | 833 | frm_cfg.frame_pin_use = regk_sser_gio0; |
682 | 834 | ||
683 | if (arg & WORD_SIZE_8) | 835 | dma_w_size = regk_dma_set_w_size2; |
836 | if (arg & WORD_SIZE_8) { | ||
684 | rec_cfg.sample_size = tr_cfg.sample_size = 7; | 837 | rec_cfg.sample_size = tr_cfg.sample_size = 7; |
685 | else if (arg & WORD_SIZE_12) | 838 | dma_w_size = regk_dma_set_w_size1; |
839 | } else if (arg & WORD_SIZE_12) | ||
686 | rec_cfg.sample_size = tr_cfg.sample_size = 11; | 840 | rec_cfg.sample_size = tr_cfg.sample_size = 11; |
687 | else if (arg & WORD_SIZE_16) | 841 | else if (arg & WORD_SIZE_16) |
688 | rec_cfg.sample_size = tr_cfg.sample_size = 15; | 842 | rec_cfg.sample_size = tr_cfg.sample_size = 15; |
@@ -696,10 +850,13 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
696 | else if (arg & BIT_ORDER_LSB) | 850 | else if (arg & BIT_ORDER_LSB) |
697 | rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst; | 851 | rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst; |
698 | 852 | ||
699 | if (arg & FLOW_CONTROL_ENABLE) | 853 | if (arg & FLOW_CONTROL_ENABLE) { |
854 | frm_cfg.status_pin_use = regk_sser_frm; | ||
700 | rec_cfg.fifo_thr = regk_sser_thr16; | 855 | rec_cfg.fifo_thr = regk_sser_thr16; |
701 | else if (arg & FLOW_CONTROL_DISABLE) | 856 | } else if (arg & FLOW_CONTROL_DISABLE) { |
857 | frm_cfg.status_pin_use = regk_sser_gio0; | ||
702 | rec_cfg.fifo_thr = regk_sser_inf; | 858 | rec_cfg.fifo_thr = regk_sser_inf; |
859 | } | ||
703 | 860 | ||
704 | if (arg & CLOCK_NOT_GATED) | 861 | if (arg & CLOCK_NOT_GATED) |
705 | gen_cfg.gate_clk = regk_sser_no; | 862 | gen_cfg.gate_clk = regk_sser_no; |
@@ -726,9 +883,9 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
726 | break; | 883 | break; |
727 | case SSP_OPOLARITY: | 884 | case SSP_OPOLARITY: |
728 | if (arg & CLOCK_NORMAL) | 885 | if (arg & CLOCK_NORMAL) |
729 | gen_cfg.out_clk_pol = regk_sser_neg; | ||
730 | else if (arg & CLOCK_INVERT) | ||
731 | gen_cfg.out_clk_pol = regk_sser_pos; | 886 | gen_cfg.out_clk_pol = regk_sser_pos; |
887 | else if (arg & CLOCK_INVERT) | ||
888 | gen_cfg.out_clk_pol = regk_sser_neg; | ||
732 | 889 | ||
733 | if (arg & FRAME_NORMAL) | 890 | if (arg & FRAME_NORMAL) |
734 | frm_cfg.level = regk_sser_pos_hi; | 891 | frm_cfg.level = regk_sser_pos_hi; |
@@ -770,10 +927,9 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
770 | } | 927 | } |
771 | 928 | ||
772 | 929 | ||
773 | if (port->started) | 930 | if (port->started) { |
774 | { | ||
775 | tr_cfg.tr_en = port->output; | ||
776 | rec_cfg.rec_en = port->input; | 931 | rec_cfg.rec_en = port->input; |
932 | gen_cfg.en = (port->output | port->input); | ||
777 | } | 933 | } |
778 | 934 | ||
779 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | 935 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); |
@@ -782,138 +938,145 @@ static int sync_serial_ioctl(struct inode *inode, struct file *file, | |||
782 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | 938 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); |
783 | REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); | 939 | REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); |
784 | 940 | ||
941 | |||
942 | if (cmd == SSP_FRAME_SYNC && (arg & (WORD_SIZE_8 | WORD_SIZE_12 | | ||
943 | WORD_SIZE_16 | WORD_SIZE_24 | WORD_SIZE_32))) { | ||
944 | int en = gen_cfg.en; | ||
945 | gen_cfg.en = 0; | ||
946 | REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); | ||
947 | /* ##### Should DMA be stoped before we change dma size? */ | ||
948 | DMA_WR_CMD(port->regi_dmain, dma_w_size); | ||
949 | DMA_WR_CMD(port->regi_dmaout, dma_w_size); | ||
950 | gen_cfg.en = en; | ||
951 | REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); | ||
952 | } | ||
953 | |||
785 | spin_unlock_irq(&port->lock); | 954 | spin_unlock_irq(&port->lock); |
786 | return return_val; | 955 | return return_val; |
787 | } | 956 | } |
788 | 957 | ||
789 | static ssize_t sync_serial_write(struct file * file, const char * buf, | 958 | /* NOTE: sync_serial_write does not support concurrency */ |
790 | size_t count, loff_t *ppos) | 959 | static ssize_t sync_serial_write(struct file *file, const char *buf, |
960 | size_t count, loff_t *ppos) | ||
791 | { | 961 | { |
792 | int dev = iminor(file->f_path.dentry->d_inode); | 962 | int dev = iminor(file->f_path.dentry->d_inode); |
793 | DECLARE_WAITQUEUE(wait, current); | 963 | DECLARE_WAITQUEUE(wait, current); |
794 | sync_port *port; | 964 | struct sync_port *port; |
795 | unsigned long c, c1; | 965 | int trunc_count; |
796 | unsigned long free_outp; | ||
797 | unsigned long outp; | ||
798 | unsigned long out_buffer; | ||
799 | unsigned long flags; | 966 | unsigned long flags; |
967 | int bytes_free; | ||
968 | int out_buf_count; | ||
800 | 969 | ||
801 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | 970 | unsigned char *rd_ptr; /* First allocated byte in the buffer */ |
802 | { | 971 | unsigned char *wr_ptr; /* First free byte in the buffer */ |
972 | unsigned char *buf_stop_ptr; /* Last byte + 1 */ | ||
973 | |||
974 | if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { | ||
803 | DEBUG(printk("Invalid minor %d\n", dev)); | 975 | DEBUG(printk("Invalid minor %d\n", dev)); |
804 | return -ENODEV; | 976 | return -ENODEV; |
805 | } | 977 | } |
806 | port = &ports[dev]; | 978 | port = &ports[dev]; |
807 | 979 | ||
808 | DEBUGWRITE(printk("W d%d c %lu (%d/%d)\n", port->port_nbr, count, port->out_count, OUT_BUFFER_SIZE)); | 980 | /* |<- OUT_BUFFER_SIZE ->| |
809 | /* Space to end of buffer */ | 981 | * |<- out_buf_count ->| |
810 | /* | 982 | * |<- trunc_count ->| ...->| |
811 | * out_buffer <c1>012345<- c ->OUT_BUFFER_SIZE | 983 | * ______________________________________________________ |
812 | * outp^ +out_count | 984 | * | free | data | free | |
813 | ^free_outp | 985 | * |_________|___________________|________________________| |
814 | * out_buffer 45<- c ->0123OUT_BUFFER_SIZE | 986 | * ^ rd_ptr ^ wr_ptr |
815 | * +out_count outp^ | ||
816 | * free_outp | ||
817 | * | ||
818 | */ | 987 | */ |
988 | DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu a: %p c: %p\n", | ||
989 | port->port_nbr, count, port->active_tr_descr, | ||
990 | port->catch_tr_descr)); | ||
819 | 991 | ||
820 | /* Read variables that may be updated by interrupts */ | 992 | /* Read variables that may be updated by interrupts */ |
821 | spin_lock_irqsave(&port->lock, flags); | 993 | spin_lock_irqsave(&port->lock, flags); |
822 | count = count > OUT_BUFFER_SIZE - port->out_count ? OUT_BUFFER_SIZE - port->out_count : count; | 994 | rd_ptr = port->out_rd_ptr; |
823 | outp = (unsigned long)port->outp; | 995 | out_buf_count = port->out_buf_count; |
824 | free_outp = outp + port->out_count; | ||
825 | spin_unlock_irqrestore(&port->lock, flags); | 996 | spin_unlock_irqrestore(&port->lock, flags); |
826 | out_buffer = (unsigned long)port->out_buffer; | ||
827 | 997 | ||
828 | /* Find out where and how much to write */ | 998 | /* Check if resources are available */ |
829 | if (free_outp >= out_buffer + OUT_BUFFER_SIZE) | 999 | if (port->tr_running && |
830 | free_outp -= OUT_BUFFER_SIZE; | 1000 | ((port->use_dma && port->active_tr_descr == port->catch_tr_descr) || |
831 | if (free_outp >= outp) | 1001 | out_buf_count >= OUT_BUFFER_SIZE)) { |
832 | c = out_buffer + OUT_BUFFER_SIZE - free_outp; | 1002 | DEBUGWRITE(printk(KERN_DEBUG "sser%d full\n", dev)); |
833 | else | 1003 | return -EAGAIN; |
834 | c = outp - free_outp; | 1004 | } |
835 | if (c > count) | 1005 | |
836 | c = count; | 1006 | buf_stop_ptr = port->out_buffer + OUT_BUFFER_SIZE; |
1007 | |||
1008 | /* Determine pointer to the first free byte, before copying. */ | ||
1009 | wr_ptr = rd_ptr + out_buf_count; | ||
1010 | if (wr_ptr >= buf_stop_ptr) | ||
1011 | wr_ptr -= OUT_BUFFER_SIZE; | ||
837 | 1012 | ||
838 | // DEBUGWRITE(printk("w op %08lX fop %08lX c %lu\n", outp, free_outp, c)); | 1013 | /* If we wrap the ring buffer, let the user space program handle it by |
839 | if (copy_from_user((void*)free_outp, buf, c)) | 1014 | * truncating the data. This could be more elegant, small buffer |
1015 | * fragments may occur. | ||
1016 | */ | ||
1017 | bytes_free = OUT_BUFFER_SIZE - out_buf_count; | ||
1018 | if (wr_ptr + bytes_free > buf_stop_ptr) | ||
1019 | bytes_free = buf_stop_ptr - wr_ptr; | ||
1020 | trunc_count = (count < bytes_free) ? count : bytes_free; | ||
1021 | |||
1022 | if (copy_from_user(wr_ptr, buf, trunc_count)) | ||
840 | return -EFAULT; | 1023 | return -EFAULT; |
841 | 1024 | ||
842 | if (c != count) { | 1025 | DEBUGOUTBUF(printk(KERN_DEBUG "%-4d + %-4d = %-4d %p %p %p\n", |
843 | buf += c; | 1026 | out_buf_count, trunc_count, |
844 | c1 = count - c; | 1027 | port->out_buf_count, port->out_buffer, |
845 | DEBUGWRITE(printk("w2 fi %lu c %lu c1 %lu\n", free_outp-out_buffer, c, c1)); | 1028 | wr_ptr, buf_stop_ptr)); |
846 | if (copy_from_user((void*)out_buffer, buf, c1)) | ||
847 | return -EFAULT; | ||
848 | } | ||
849 | spin_lock_irqsave(&port->lock, flags); | ||
850 | port->out_count += count; | ||
851 | spin_unlock_irqrestore(&port->lock, flags); | ||
852 | 1029 | ||
853 | /* Make sure transmitter/receiver is running */ | 1030 | /* Make sure transmitter/receiver is running */ |
854 | if (!port->started) | 1031 | if (!port->started) { |
855 | { | ||
856 | reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); | 1032 | reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); |
857 | reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
858 | reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); | 1033 | reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); |
859 | cfg.en = regk_sser_yes; | 1034 | cfg.en = regk_sser_yes; |
860 | tr_cfg.tr_en = port->output; | ||
861 | rec_cfg.rec_en = port->input; | 1035 | rec_cfg.rec_en = port->input; |
862 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); | 1036 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); |
863 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
864 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | 1037 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); |
865 | port->started = 1; | 1038 | port->started = 1; |
866 | } | 1039 | } |
867 | 1040 | ||
868 | if (file->f_flags & O_NONBLOCK) { | 1041 | /* Setup wait if blocking */ |
869 | spin_lock_irqsave(&port->lock, flags); | 1042 | if (!(file->f_flags & O_NONBLOCK)) { |
870 | if (!port->tr_running) { | 1043 | add_wait_queue(&port->out_wait_q, &wait); |
871 | if (!port->use_dma) { | 1044 | set_current_state(TASK_INTERRUPTIBLE); |
872 | reg_sser_rw_intr_mask intr_mask; | ||
873 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | ||
874 | /* Start sender by writing data */ | ||
875 | send_word(port); | ||
876 | /* and enable transmitter ready IRQ */ | ||
877 | intr_mask.trdy = 1; | ||
878 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | ||
879 | } else { | ||
880 | start_dma(port, (unsigned char* volatile )port->outp, c); | ||
881 | } | ||
882 | } | ||
883 | spin_unlock_irqrestore(&port->lock, flags); | ||
884 | DEBUGWRITE(printk("w d%d c %lu NB\n", | ||
885 | port->port_nbr, count)); | ||
886 | return count; | ||
887 | } | 1045 | } |
888 | 1046 | ||
889 | /* Sleep until all sent */ | ||
890 | |||
891 | add_wait_queue(&port->out_wait_q, &wait); | ||
892 | set_current_state(TASK_INTERRUPTIBLE); | ||
893 | spin_lock_irqsave(&port->lock, flags); | 1047 | spin_lock_irqsave(&port->lock, flags); |
894 | if (!port->tr_running) { | 1048 | port->out_buf_count += trunc_count; |
895 | if (!port->use_dma) { | 1049 | if (port->use_dma) { |
896 | reg_sser_rw_intr_mask intr_mask; | 1050 | start_dma_out(port, wr_ptr, trunc_count); |
897 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | 1051 | } else if (!port->tr_running) { |
898 | /* Start sender by writing data */ | 1052 | reg_sser_rw_intr_mask intr_mask; |
899 | send_word(port); | 1053 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); |
900 | /* and enable transmitter ready IRQ */ | 1054 | /* Start sender by writing data */ |
901 | intr_mask.trdy = 1; | 1055 | send_word(port); |
902 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | 1056 | /* and enable transmitter ready IRQ */ |
903 | } else { | 1057 | intr_mask.trdy = 1; |
904 | start_dma(port, port->outp, c); | 1058 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); |
905 | } | ||
906 | } | 1059 | } |
907 | spin_unlock_irqrestore(&port->lock, flags); | 1060 | spin_unlock_irqrestore(&port->lock, flags); |
1061 | |||
1062 | /* Exit if non blocking */ | ||
1063 | if (file->f_flags & O_NONBLOCK) { | ||
1064 | DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu %08x\n", | ||
1065 | port->port_nbr, trunc_count, | ||
1066 | REG_RD_INT(dma, port->regi_dmaout, r_intr))); | ||
1067 | return trunc_count; | ||
1068 | } | ||
1069 | |||
908 | schedule(); | 1070 | schedule(); |
909 | set_current_state(TASK_RUNNING); | 1071 | set_current_state(TASK_RUNNING); |
910 | remove_wait_queue(&port->out_wait_q, &wait); | 1072 | remove_wait_queue(&port->out_wait_q, &wait); |
1073 | |||
911 | if (signal_pending(current)) | 1074 | if (signal_pending(current)) |
912 | { | ||
913 | return -EINTR; | 1075 | return -EINTR; |
914 | } | 1076 | |
915 | DEBUGWRITE(printk("w d%d c %lu\n", port->port_nbr, count)); | 1077 | DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n", |
916 | return count; | 1078 | port->port_nbr, trunc_count)); |
1079 | return trunc_count; | ||
917 | } | 1080 | } |
918 | 1081 | ||
919 | static ssize_t sync_serial_read(struct file * file, char * buf, | 1082 | static ssize_t sync_serial_read(struct file * file, char * buf, |
@@ -926,7 +1089,7 @@ static ssize_t sync_serial_read(struct file * file, char * buf, | |||
926 | unsigned char* end; | 1089 | unsigned char* end; |
927 | unsigned long flags; | 1090 | unsigned long flags; |
928 | 1091 | ||
929 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | 1092 | if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) |
930 | { | 1093 | { |
931 | DEBUG(printk("Invalid minor %d\n", dev)); | 1094 | DEBUG(printk("Invalid minor %d\n", dev)); |
932 | return -ENODEV; | 1095 | return -ENODEV; |
@@ -949,7 +1112,6 @@ static ssize_t sync_serial_read(struct file * file, char * buf, | |||
949 | port->started = 1; | 1112 | port->started = 1; |
950 | } | 1113 | } |
951 | 1114 | ||
952 | |||
953 | /* Calculate number of available bytes */ | 1115 | /* Calculate number of available bytes */ |
954 | /* Save pointers to avoid that they are modified by interrupt */ | 1116 | /* Save pointers to avoid that they are modified by interrupt */ |
955 | spin_lock_irqsave(&port->lock, flags); | 1117 | spin_lock_irqsave(&port->lock, flags); |
@@ -958,16 +1120,14 @@ static ssize_t sync_serial_read(struct file * file, char * buf, | |||
958 | spin_unlock_irqrestore(&port->lock, flags); | 1120 | spin_unlock_irqrestore(&port->lock, flags); |
959 | while ((start == end) && !port->full) /* No data */ | 1121 | while ((start == end) && !port->full) /* No data */ |
960 | { | 1122 | { |
1123 | DEBUGREAD(printk(KERN_DEBUG "&")); | ||
961 | if (file->f_flags & O_NONBLOCK) | 1124 | if (file->f_flags & O_NONBLOCK) |
962 | { | ||
963 | return -EAGAIN; | 1125 | return -EAGAIN; |
964 | } | ||
965 | 1126 | ||
966 | interruptible_sleep_on(&port->in_wait_q); | 1127 | interruptible_sleep_on(&port->in_wait_q); |
967 | if (signal_pending(current)) | 1128 | if (signal_pending(current)) |
968 | { | ||
969 | return -EINTR; | 1129 | return -EINTR; |
970 | } | 1130 | |
971 | spin_lock_irqsave(&port->lock, flags); | 1131 | spin_lock_irqsave(&port->lock, flags); |
972 | start = (unsigned char*)port->readp; /* cast away volatile */ | 1132 | start = (unsigned char*)port->readp; /* cast away volatile */ |
973 | end = (unsigned char*)port->writep; /* cast away volatile */ | 1133 | end = (unsigned char*)port->writep; /* cast away volatile */ |
@@ -1004,83 +1164,105 @@ static void send_word(sync_port* port) | |||
1004 | switch(tr_cfg.sample_size) | 1164 | switch(tr_cfg.sample_size) |
1005 | { | 1165 | { |
1006 | case 8: | 1166 | case 8: |
1007 | port->out_count--; | 1167 | port->out_buf_count--; |
1008 | tr_data.data = *port->outp++; | 1168 | tr_data.data = *port->out_rd_ptr++; |
1009 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1169 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1010 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1170 | if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) |
1011 | port->outp = port->out_buffer; | 1171 | port->out_rd_ptr = port->out_buffer; |
1012 | break; | 1172 | break; |
1013 | case 12: | 1173 | case 12: |
1014 | { | 1174 | { |
1015 | int data = (*port->outp++) << 8; | 1175 | int data = (*port->out_rd_ptr++) << 8; |
1016 | data |= *port->outp++; | 1176 | data |= *port->out_rd_ptr++; |
1017 | port->out_count-=2; | 1177 | port->out_buf_count -= 2; |
1018 | tr_data.data = data; | 1178 | tr_data.data = data; |
1019 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1179 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1020 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1180 | if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) |
1021 | port->outp = port->out_buffer; | 1181 | port->out_rd_ptr = port->out_buffer; |
1022 | } | 1182 | } |
1023 | break; | 1183 | break; |
1024 | case 16: | 1184 | case 16: |
1025 | port->out_count-=2; | 1185 | port->out_buf_count -= 2; |
1026 | tr_data.data = *(unsigned short *)port->outp; | 1186 | tr_data.data = *(unsigned short *)port->out_rd_ptr; |
1027 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1187 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1028 | port->outp+=2; | 1188 | port->out_rd_ptr += 2; |
1029 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1189 | if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) |
1030 | port->outp = port->out_buffer; | 1190 | port->out_rd_ptr = port->out_buffer; |
1031 | break; | 1191 | break; |
1032 | case 24: | 1192 | case 24: |
1033 | port->out_count-=3; | 1193 | port->out_buf_count -= 3; |
1034 | tr_data.data = *(unsigned short *)port->outp; | 1194 | tr_data.data = *(unsigned short *)port->out_rd_ptr; |
1035 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1195 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1036 | port->outp+=2; | 1196 | port->out_rd_ptr += 2; |
1037 | tr_data.data = *port->outp++; | 1197 | tr_data.data = *port->out_rd_ptr++; |
1038 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1198 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1039 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1199 | if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) |
1040 | port->outp = port->out_buffer; | 1200 | port->out_rd_ptr = port->out_buffer; |
1041 | break; | 1201 | break; |
1042 | case 32: | 1202 | case 32: |
1043 | port->out_count-=4; | 1203 | port->out_buf_count -= 4; |
1044 | tr_data.data = *(unsigned short *)port->outp; | 1204 | tr_data.data = *(unsigned short *)port->out_rd_ptr; |
1045 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1205 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1046 | port->outp+=2; | 1206 | port->out_rd_ptr += 2; |
1047 | tr_data.data = *(unsigned short *)port->outp; | 1207 | tr_data.data = *(unsigned short *)port->out_rd_ptr; |
1048 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | 1208 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); |
1049 | port->outp+=2; | 1209 | port->out_rd_ptr += 2; |
1050 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1210 | if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) |
1051 | port->outp = port->out_buffer; | 1211 | port->out_rd_ptr = port->out_buffer; |
1052 | break; | 1212 | break; |
1053 | } | 1213 | } |
1054 | } | 1214 | } |
1055 | 1215 | ||
1056 | 1216 | static void start_dma_out(struct sync_port *port, | |
1057 | static void start_dma(struct sync_port* port, const char* data, int count) | 1217 | const char *data, int count) |
1058 | { | 1218 | { |
1059 | port->tr_running = 1; | 1219 | port->active_tr_descr->buf = (char *) virt_to_phys((char *) data); |
1060 | port->out_descr.buf = (char*)virt_to_phys((char*)data); | 1220 | port->active_tr_descr->after = port->active_tr_descr->buf + count; |
1061 | port->out_descr.after = port->out_descr.buf + count; | 1221 | port->active_tr_descr->intr = 1; |
1062 | port->out_descr.eol = port->out_descr.intr = 1; | 1222 | |
1223 | port->active_tr_descr->eol = 1; | ||
1224 | port->prev_tr_descr->eol = 0; | ||
1225 | |||
1226 | DEBUGTRDMA(printk(KERN_DEBUG "Inserting eolr:%p eol@:%p\n", | ||
1227 | port->prev_tr_descr, port->active_tr_descr)); | ||
1228 | port->prev_tr_descr = port->active_tr_descr; | ||
1229 | port->active_tr_descr = phys_to_virt((int) port->active_tr_descr->next); | ||
1230 | |||
1231 | if (!port->tr_running) { | ||
1232 | reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, | ||
1233 | rw_tr_cfg); | ||
1063 | 1234 | ||
1064 | port->out_context.saved_data = (dma_descr_data*)virt_to_phys(&port->out_descr); | 1235 | port->out_context.next = 0; |
1065 | port->out_context.saved_data_buf = port->out_descr.buf; | 1236 | port->out_context.saved_data = |
1237 | (dma_descr_data *)virt_to_phys(port->prev_tr_descr); | ||
1238 | port->out_context.saved_data_buf = port->prev_tr_descr->buf; | ||
1239 | |||
1240 | DMA_START_CONTEXT(port->regi_dmaout, | ||
1241 | virt_to_phys((char *)&port->out_context)); | ||
1242 | |||
1243 | tr_cfg.tr_en = regk_sser_yes; | ||
1244 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
1245 | DEBUGTRDMA(printk(KERN_DEBUG "dma s\n");); | ||
1246 | } else { | ||
1247 | DMA_CONTINUE_DATA(port->regi_dmaout); | ||
1248 | DEBUGTRDMA(printk(KERN_DEBUG "dma c\n");); | ||
1249 | } | ||
1066 | 1250 | ||
1067 | DMA_START_CONTEXT(port->regi_dmaout, virt_to_phys((char*)&port->out_context)); | 1251 | port->tr_running = 1; |
1068 | DEBUGTXINT(printk("dma %08lX c %d\n", (unsigned long)data, count)); | ||
1069 | } | 1252 | } |
1070 | 1253 | ||
1071 | static void start_dma_in(sync_port* port) | 1254 | static void start_dma_in(sync_port *port) |
1072 | { | 1255 | { |
1073 | int i; | 1256 | int i; |
1074 | char* buf; | 1257 | char *buf; |
1075 | port->writep = port->flip; | 1258 | port->writep = port->flip; |
1076 | 1259 | ||
1077 | if (port->writep > port->flip + port->in_buffer_size) | 1260 | if (port->writep > port->flip + port->in_buffer_size) { |
1078 | { | ||
1079 | panic("Offset too large in sync serial driver\n"); | 1261 | panic("Offset too large in sync serial driver\n"); |
1080 | return; | 1262 | return; |
1081 | } | 1263 | } |
1082 | buf = (char*)virt_to_phys(port->in_buffer); | 1264 | buf = (char*)virt_to_phys(port->in_buffer); |
1083 | for (i = 0; i < NUM_IN_DESCR; i++) { | 1265 | for (i = 0; i < NBR_IN_DESCR; i++) { |
1084 | port->in_descr[i].buf = buf; | 1266 | port->in_descr[i].buf = buf; |
1085 | port->in_descr[i].after = buf + port->inbufchunk; | 1267 | port->in_descr[i].after = buf + port->inbufchunk; |
1086 | port->in_descr[i].intr = 1; | 1268 | port->in_descr[i].intr = 1; |
@@ -1092,59 +1274,126 @@ static void start_dma_in(sync_port* port) | |||
1092 | port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); | 1274 | port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); |
1093 | port->in_descr[i-1].eol = regk_sser_yes; | 1275 | port->in_descr[i-1].eol = regk_sser_yes; |
1094 | port->next_rx_desc = &port->in_descr[0]; | 1276 | port->next_rx_desc = &port->in_descr[0]; |
1095 | port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR - 1]; | 1277 | port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1]; |
1096 | port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); | 1278 | port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); |
1097 | port->in_context.saved_data_buf = port->in_descr[0].buf; | 1279 | port->in_context.saved_data_buf = port->in_descr[0].buf; |
1098 | DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); | 1280 | DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); |
1099 | } | 1281 | } |
1100 | 1282 | ||
1101 | #ifdef SYNC_SER_DMA | 1283 | #ifdef SYNC_SER_DMA |
1102 | static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) | 1284 | static irqreturn_t tr_interrupt(int irq, void *dev_id) |
1103 | { | 1285 | { |
1104 | reg_dma_r_masked_intr masked; | 1286 | reg_dma_r_masked_intr masked; |
1105 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; | 1287 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; |
1288 | reg_dma_rw_stat stat; | ||
1106 | int i; | 1289 | int i; |
1107 | struct dma_descr_data *descr; | ||
1108 | unsigned int sentl; | ||
1109 | int found = 0; | 1290 | int found = 0; |
1291 | int stop_sser = 0; | ||
1110 | 1292 | ||
1111 | for (i = 0; i < NUMBER_OF_PORTS; i++) | 1293 | for (i = 0; i < NBR_PORTS; i++) { |
1112 | { | ||
1113 | sync_port *port = &ports[i]; | 1294 | sync_port *port = &ports[i]; |
1114 | if (!port->enabled || !port->use_dma ) | 1295 | if (!port->enabled || !port->use_dma) |
1115 | continue; | 1296 | continue; |
1116 | 1297 | ||
1298 | /* IRQ active for the port? */ | ||
1117 | masked = REG_RD(dma, port->regi_dmaout, r_masked_intr); | 1299 | masked = REG_RD(dma, port->regi_dmaout, r_masked_intr); |
1300 | if (!masked.data) | ||
1301 | continue; | ||
1118 | 1302 | ||
1119 | if (masked.data) /* IRQ active for the port? */ | 1303 | found = 1; |
1120 | { | 1304 | |
1121 | found = 1; | 1305 | /* Check if we should stop the DMA transfer */ |
1122 | /* Clear IRQ */ | 1306 | stat = REG_RD(dma, port->regi_dmaout, rw_stat); |
1123 | REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr); | 1307 | if (stat.list_state == regk_dma_data_at_eol) |
1124 | descr = &port->out_descr; | 1308 | stop_sser = 1; |
1125 | sentl = descr->after - descr->buf; | 1309 | |
1126 | port->out_count -= sentl; | 1310 | /* Clear IRQ */ |
1127 | port->outp += sentl; | 1311 | REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr); |
1128 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | 1312 | |
1129 | port->outp = port->out_buffer; | 1313 | if (!stop_sser) { |
1130 | if (port->out_count) { | 1314 | /* The DMA has completed a descriptor, EOL was not |
1131 | int c; | 1315 | * encountered, so step relevant descriptor and |
1132 | c = port->out_buffer + OUT_BUFFER_SIZE - port->outp; | 1316 | * datapointers forward. */ |
1133 | if (c > port->out_count) | 1317 | int sent; |
1134 | c = port->out_count; | 1318 | sent = port->catch_tr_descr->after - |
1135 | DEBUGTXINT(printk("tx_int DMAWRITE %i %i\n", sentl, c)); | 1319 | port->catch_tr_descr->buf; |
1136 | start_dma(port, port->outp, c); | 1320 | DEBUGTXINT(printk(KERN_DEBUG "%-4d - %-4d = %-4d\t" |
1137 | } else { | 1321 | "in descr %p (ac: %p)\n", |
1138 | DEBUGTXINT(printk("tx_int DMA stop %i\n", sentl)); | 1322 | port->out_buf_count, sent, |
1139 | port->tr_running = 0; | 1323 | port->out_buf_count - sent, |
1324 | port->catch_tr_descr, | ||
1325 | port->active_tr_descr);); | ||
1326 | port->out_buf_count -= sent; | ||
1327 | port->catch_tr_descr = | ||
1328 | phys_to_virt((int) port->catch_tr_descr->next); | ||
1329 | port->out_rd_ptr = | ||
1330 | phys_to_virt((int) port->catch_tr_descr->buf); | ||
1331 | } else { | ||
1332 | int i, sent; | ||
1333 | /* EOL handler. | ||
1334 | * Note that if an EOL was encountered during the irq | ||
1335 | * locked section of sync_ser_write the DMA will be | ||
1336 | * restarted and the eol flag will be cleared. | ||
1337 | * The remaining descriptors will be traversed by | ||
1338 | * the descriptor interrupts as usual. | ||
1339 | */ | ||
1340 | i = 0; | ||
1341 | while (!port->catch_tr_descr->eol) { | ||
1342 | sent = port->catch_tr_descr->after - | ||
1343 | port->catch_tr_descr->buf; | ||
1344 | DEBUGOUTBUF(printk(KERN_DEBUG | ||
1345 | "traversing descr %p -%d (%d)\n", | ||
1346 | port->catch_tr_descr, | ||
1347 | sent, | ||
1348 | port->out_buf_count)); | ||
1349 | port->out_buf_count -= sent; | ||
1350 | port->catch_tr_descr = phys_to_virt( | ||
1351 | (int)port->catch_tr_descr->next); | ||
1352 | i++; | ||
1353 | if (i >= NBR_OUT_DESCR) { | ||
1354 | /* TODO: Reset and recover */ | ||
1355 | panic("sync_serial: missing eol"); | ||
1356 | } | ||
1140 | } | 1357 | } |
1141 | wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ | 1358 | sent = port->catch_tr_descr->after - |
1359 | port->catch_tr_descr->buf; | ||
1360 | DEBUGOUTBUF(printk(KERN_DEBUG | ||
1361 | "eol at descr %p -%d (%d)\n", | ||
1362 | port->catch_tr_descr, | ||
1363 | sent, | ||
1364 | port->out_buf_count)); | ||
1365 | |||
1366 | port->out_buf_count -= sent; | ||
1367 | |||
1368 | /* Update read pointer to first free byte, we | ||
1369 | * may already be writing data there. */ | ||
1370 | port->out_rd_ptr = | ||
1371 | phys_to_virt((int) port->catch_tr_descr->after); | ||
1372 | if (port->out_rd_ptr > port->out_buffer + | ||
1373 | OUT_BUFFER_SIZE) | ||
1374 | port->out_rd_ptr = port->out_buffer; | ||
1375 | |||
1376 | reg_sser_rw_tr_cfg tr_cfg = | ||
1377 | REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
1378 | DEBUGTXINT(printk(KERN_DEBUG | ||
1379 | "tr_int DMA stop %d, set catch @ %p\n", | ||
1380 | port->out_buf_count, | ||
1381 | port->active_tr_descr)); | ||
1382 | if (port->out_buf_count != 0) | ||
1383 | printk(KERN_CRIT "sync_ser: buffer not " | ||
1384 | "empty after eol.\n"); | ||
1385 | port->catch_tr_descr = port->active_tr_descr; | ||
1386 | port->tr_running = 0; | ||
1387 | tr_cfg.tr_en = regk_sser_no; | ||
1388 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
1142 | } | 1389 | } |
1390 | /* wake up the waiting process */ | ||
1391 | wake_up_interruptible(&port->out_wait_q); | ||
1143 | } | 1392 | } |
1144 | return IRQ_RETVAL(found); | 1393 | return IRQ_RETVAL(found); |
1145 | } /* tr_interrupt */ | 1394 | } /* tr_interrupt */ |
1146 | 1395 | ||
1147 | static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | 1396 | static irqreturn_t rx_interrupt(int irq, void *dev_id) |
1148 | { | 1397 | { |
1149 | reg_dma_r_masked_intr masked; | 1398 | reg_dma_r_masked_intr masked; |
1150 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; | 1399 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; |
@@ -1152,7 +1401,7 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
1152 | int i; | 1401 | int i; |
1153 | int found = 0; | 1402 | int found = 0; |
1154 | 1403 | ||
1155 | for (i = 0; i < NUMBER_OF_PORTS; i++) | 1404 | for (i = 0; i < NBR_PORTS; i++) |
1156 | { | 1405 | { |
1157 | sync_port *port = &ports[i]; | 1406 | sync_port *port = &ports[i]; |
1158 | 1407 | ||
@@ -1166,7 +1415,7 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
1166 | found = 1; | 1415 | found = 1; |
1167 | while (REG_RD(dma, port->regi_dmain, rw_data) != | 1416 | while (REG_RD(dma, port->regi_dmain, rw_data) != |
1168 | virt_to_phys(port->next_rx_desc)) { | 1417 | virt_to_phys(port->next_rx_desc)) { |
1169 | 1418 | DEBUGRXINT(printk(KERN_DEBUG "!")); | |
1170 | if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) { | 1419 | if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) { |
1171 | int first_size = port->flip + port->in_buffer_size - port->writep; | 1420 | int first_size = port->flip + port->in_buffer_size - port->writep; |
1172 | memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size); | 1421 | memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size); |
@@ -1185,11 +1434,16 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
1185 | port->full = 1; | 1434 | port->full = 1; |
1186 | } | 1435 | } |
1187 | 1436 | ||
1188 | port->next_rx_desc->eol = 0; | 1437 | port->next_rx_desc->eol = 1; |
1189 | port->prev_rx_desc->eol = 1; | 1438 | port->prev_rx_desc->eol = 0; |
1190 | port->prev_rx_desc = phys_to_virt((unsigned)port->next_rx_desc); | 1439 | /* Cache bug workaround */ |
1440 | flush_dma_descr(port->prev_rx_desc, 0); | ||
1441 | port->prev_rx_desc = port->next_rx_desc; | ||
1191 | port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); | 1442 | port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); |
1192 | wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ | 1443 | /* Cache bug workaround */ |
1444 | flush_dma_descr(port->prev_rx_desc, 1); | ||
1445 | /* wake up the waiting process */ | ||
1446 | wake_up_interruptible(&port->in_wait_q); | ||
1193 | DMA_CONTINUE(port->regi_dmain); | 1447 | DMA_CONTINUE(port->regi_dmain); |
1194 | REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); | 1448 | REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); |
1195 | 1449 | ||
@@ -1201,15 +1455,15 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | |||
1201 | #endif /* SYNC_SER_DMA */ | 1455 | #endif /* SYNC_SER_DMA */ |
1202 | 1456 | ||
1203 | #ifdef SYNC_SER_MANUAL | 1457 | #ifdef SYNC_SER_MANUAL |
1204 | static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) | 1458 | static irqreturn_t manual_interrupt(int irq, void *dev_id) |
1205 | { | 1459 | { |
1206 | int i; | 1460 | int i; |
1207 | int found = 0; | 1461 | int found = 0; |
1208 | reg_sser_r_masked_intr masked; | 1462 | reg_sser_r_masked_intr masked; |
1209 | 1463 | ||
1210 | for (i = 0; i < NUMBER_OF_PORTS; i++) | 1464 | for (i = 0; i < NBR_PORTS; i++) |
1211 | { | 1465 | { |
1212 | sync_port* port = &ports[i]; | 1466 | sync_port *port = &ports[i]; |
1213 | 1467 | ||
1214 | if (!port->enabled || port->use_dma) | 1468 | if (!port->enabled || port->use_dma) |
1215 | { | 1469 | { |
@@ -1263,7 +1517,7 @@ static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs | |||
1263 | if (masked.trdy) /* Transmitter ready? */ | 1517 | if (masked.trdy) /* Transmitter ready? */ |
1264 | { | 1518 | { |
1265 | found = 1; | 1519 | found = 1; |
1266 | if (port->out_count > 0) /* More data to send */ | 1520 | if (port->out_buf_count > 0) /* More data to send */ |
1267 | send_word(port); | 1521 | send_word(port); |
1268 | else /* transmission finished */ | 1522 | else /* transmission finished */ |
1269 | { | 1523 | { |
diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile index 5d5b613cde8c..993d987b0078 100644 --- a/arch/cris/arch-v32/kernel/Makefile +++ b/arch/cris/arch-v32/kernel/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | # $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $ | ||
2 | # | 1 | # |
3 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
4 | # | 3 | # |
@@ -6,9 +5,9 @@ | |||
6 | extra-y := head.o | 5 | extra-y := head.o |
7 | 6 | ||
8 | 7 | ||
9 | obj-y := entry.o traps.o irq.o debugport.o dma.o pinmux.o \ | 8 | obj-y := entry.o traps.o irq.o debugport.o \ |
10 | process.o ptrace.o setup.o signal.o traps.o time.o \ | 9 | process.o ptrace.o setup.o signal.o traps.o time.o \ |
11 | arbiter.o io.o | 10 | cache.o cacheflush.o |
12 | 11 | ||
13 | obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o | 12 | obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o |
14 | 13 | ||
diff --git a/arch/cris/arch-v32/kernel/arbiter.c b/arch/cris/arch-v32/kernel/arbiter.c deleted file mode 100644 index 420a5312ed03..000000000000 --- a/arch/cris/arch-v32/kernel/arbiter.c +++ /dev/null | |||
@@ -1,296 +0,0 @@ | |||
1 | /* | ||
2 | * Memory arbiter functions. Allocates bandwidth through the | ||
3 | * arbiter and sets up arbiter breakpoints. | ||
4 | * | ||
5 | * The algorithm first assigns slots to the clients that has specified | ||
6 | * bandwidth (e.g. ethernet) and then the remaining slots are divided | ||
7 | * on all the active clients. | ||
8 | * | ||
9 | * Copyright (c) 2004, 2005 Axis Communications AB. | ||
10 | */ | ||
11 | |||
12 | #include <asm/arch/hwregs/reg_map.h> | ||
13 | #include <asm/arch/hwregs/reg_rdwr.h> | ||
14 | #include <asm/arch/hwregs/marb_defs.h> | ||
15 | #include <asm/arch/arbiter.h> | ||
16 | #include <asm/arch/hwregs/intr_vect.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | struct crisv32_watch_entry | ||
24 | { | ||
25 | unsigned long instance; | ||
26 | watch_callback* cb; | ||
27 | unsigned long start; | ||
28 | unsigned long end; | ||
29 | int used; | ||
30 | }; | ||
31 | |||
32 | #define NUMBER_OF_BP 4 | ||
33 | #define NBR_OF_CLIENTS 14 | ||
34 | #define NBR_OF_SLOTS 64 | ||
35 | #define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ | ||
36 | #define INTMEM_BANDWIDTH 400000000 | ||
37 | #define NBR_OF_REGIONS 2 | ||
38 | |||
39 | static struct crisv32_watch_entry watches[NUMBER_OF_BP] = | ||
40 | { | ||
41 | {regi_marb_bp0}, | ||
42 | {regi_marb_bp1}, | ||
43 | {regi_marb_bp2}, | ||
44 | {regi_marb_bp3} | ||
45 | }; | ||
46 | |||
47 | static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
48 | static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
49 | static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH}; | ||
50 | |||
51 | DEFINE_SPINLOCK(arbiter_lock); | ||
52 | |||
53 | static irqreturn_t | ||
54 | crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs); | ||
55 | |||
56 | static void crisv32_arbiter_config(int region) | ||
57 | { | ||
58 | int slot; | ||
59 | int client; | ||
60 | int interval = 0; | ||
61 | int val[NBR_OF_SLOTS]; | ||
62 | |||
63 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | ||
64 | val[slot] = NBR_OF_CLIENTS + 1; | ||
65 | |||
66 | for (client = 0; client < NBR_OF_CLIENTS; client++) | ||
67 | { | ||
68 | int pos; | ||
69 | if (!requested_slots[region][client]) | ||
70 | continue; | ||
71 | interval = NBR_OF_SLOTS / requested_slots[region][client]; | ||
72 | pos = 0; | ||
73 | while (pos < NBR_OF_SLOTS) | ||
74 | { | ||
75 | if (val[pos] != NBR_OF_CLIENTS + 1) | ||
76 | pos++; | ||
77 | else | ||
78 | { | ||
79 | val[pos] = client; | ||
80 | pos += interval; | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | client = 0; | ||
86 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | ||
87 | { | ||
88 | if (val[slot] == NBR_OF_CLIENTS + 1) | ||
89 | { | ||
90 | int first = client; | ||
91 | while(!active_clients[region][client]) { | ||
92 | client = (client + 1) % NBR_OF_CLIENTS; | ||
93 | if (client == first) | ||
94 | break; | ||
95 | } | ||
96 | val[slot] = client; | ||
97 | client = (client + 1) % NBR_OF_CLIENTS; | ||
98 | } | ||
99 | if (region == EXT_REGION) | ||
100 | REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, val[slot]); | ||
101 | else if (region == INT_REGION) | ||
102 | REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, val[slot]); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | extern char _stext, _etext; | ||
107 | |||
108 | static void crisv32_arbiter_init(void) | ||
109 | { | ||
110 | static int initialized = 0; | ||
111 | |||
112 | if (initialized) | ||
113 | return; | ||
114 | |||
115 | initialized = 1; | ||
116 | |||
117 | /* CPU caches are active. */ | ||
118 | active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; | ||
119 | crisv32_arbiter_config(EXT_REGION); | ||
120 | crisv32_arbiter_config(INT_REGION); | ||
121 | |||
122 | if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, | ||
123 | "arbiter", NULL)) | ||
124 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | ||
125 | |||
126 | #ifndef CONFIG_ETRAX_KGDB | ||
127 | /* Global watch for writes to kernel text segment. */ | ||
128 | crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext, | ||
129 | arbiter_all_clients, arbiter_all_write, NULL); | ||
130 | #endif | ||
131 | } | ||
132 | |||
133 | |||
134 | |||
135 | int crisv32_arbiter_allocate_bandwidth(int client, int region, | ||
136 | unsigned long bandwidth) | ||
137 | { | ||
138 | int i; | ||
139 | int total_assigned = 0; | ||
140 | int total_clients = 0; | ||
141 | int req; | ||
142 | |||
143 | crisv32_arbiter_init(); | ||
144 | |||
145 | for (i = 0; i < NBR_OF_CLIENTS; i++) | ||
146 | { | ||
147 | total_assigned += requested_slots[region][i]; | ||
148 | total_clients += active_clients[region][i]; | ||
149 | } | ||
150 | req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); | ||
151 | |||
152 | if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS) | ||
153 | return -ENOMEM; | ||
154 | |||
155 | active_clients[region][client] = 1; | ||
156 | requested_slots[region][client] = req; | ||
157 | crisv32_arbiter_config(region); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | int crisv32_arbiter_watch(unsigned long start, unsigned long size, | ||
163 | unsigned long clients, unsigned long accesses, | ||
164 | watch_callback* cb) | ||
165 | { | ||
166 | int i; | ||
167 | |||
168 | crisv32_arbiter_init(); | ||
169 | |||
170 | if (start > 0x80000000) { | ||
171 | printk("Arbiter: %lX doesn't look like a physical address", start); | ||
172 | return -EFAULT; | ||
173 | } | ||
174 | |||
175 | spin_lock(&arbiter_lock); | ||
176 | |||
177 | for (i = 0; i < NUMBER_OF_BP; i++) { | ||
178 | if (!watches[i].used) { | ||
179 | reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); | ||
180 | |||
181 | watches[i].used = 1; | ||
182 | watches[i].start = start; | ||
183 | watches[i].end = start + size; | ||
184 | watches[i].cb = cb; | ||
185 | |||
186 | REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, watches[i].start); | ||
187 | REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, watches[i].end); | ||
188 | REG_WR_INT(marb_bp, watches[i].instance, rw_op, accesses); | ||
189 | REG_WR_INT(marb_bp, watches[i].instance, rw_clients, clients); | ||
190 | |||
191 | if (i == 0) | ||
192 | intr_mask.bp0 = regk_marb_yes; | ||
193 | else if (i == 1) | ||
194 | intr_mask.bp1 = regk_marb_yes; | ||
195 | else if (i == 2) | ||
196 | intr_mask.bp2 = regk_marb_yes; | ||
197 | else if (i == 3) | ||
198 | intr_mask.bp3 = regk_marb_yes; | ||
199 | |||
200 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
201 | spin_unlock(&arbiter_lock); | ||
202 | |||
203 | return i; | ||
204 | } | ||
205 | } | ||
206 | spin_unlock(&arbiter_lock); | ||
207 | return -ENOMEM; | ||
208 | } | ||
209 | |||
210 | int crisv32_arbiter_unwatch(int id) | ||
211 | { | ||
212 | reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); | ||
213 | |||
214 | crisv32_arbiter_init(); | ||
215 | |||
216 | spin_lock(&arbiter_lock); | ||
217 | |||
218 | if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { | ||
219 | spin_unlock(&arbiter_lock); | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | |||
223 | memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); | ||
224 | |||
225 | if (id == 0) | ||
226 | intr_mask.bp0 = regk_marb_no; | ||
227 | else if (id == 1) | ||
228 | intr_mask.bp2 = regk_marb_no; | ||
229 | else if (id == 2) | ||
230 | intr_mask.bp2 = regk_marb_no; | ||
231 | else if (id == 3) | ||
232 | intr_mask.bp3 = regk_marb_no; | ||
233 | |||
234 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
235 | |||
236 | spin_unlock(&arbiter_lock); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | extern void show_registers(struct pt_regs *regs); | ||
241 | |||
242 | static irqreturn_t | ||
243 | crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs) | ||
244 | { | ||
245 | reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, r_masked_intr); | ||
246 | reg_marb_bp_r_brk_clients r_clients; | ||
247 | reg_marb_bp_r_brk_addr r_addr; | ||
248 | reg_marb_bp_r_brk_op r_op; | ||
249 | reg_marb_bp_r_brk_first_client r_first; | ||
250 | reg_marb_bp_r_brk_size r_size; | ||
251 | reg_marb_bp_rw_ack ack = {0}; | ||
252 | reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1}; | ||
253 | struct crisv32_watch_entry* watch; | ||
254 | |||
255 | if (masked_intr.bp0) { | ||
256 | watch = &watches[0]; | ||
257 | ack_intr.bp0 = regk_marb_yes; | ||
258 | } else if (masked_intr.bp1) { | ||
259 | watch = &watches[1]; | ||
260 | ack_intr.bp1 = regk_marb_yes; | ||
261 | } else if (masked_intr.bp2) { | ||
262 | watch = &watches[2]; | ||
263 | ack_intr.bp2 = regk_marb_yes; | ||
264 | } else if (masked_intr.bp3) { | ||
265 | watch = &watches[3]; | ||
266 | ack_intr.bp3 = regk_marb_yes; | ||
267 | } else { | ||
268 | return IRQ_NONE; | ||
269 | } | ||
270 | |||
271 | /* Retrieve all useful information and print it. */ | ||
272 | r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); | ||
273 | r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); | ||
274 | r_op = REG_RD(marb_bp, watch->instance, r_brk_op); | ||
275 | r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); | ||
276 | r_size = REG_RD(marb_bp, watch->instance, r_brk_size); | ||
277 | |||
278 | printk("Arbiter IRQ\n"); | ||
279 | printk("Clients %X addr %X op %X first %X size %X\n", | ||
280 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), | ||
281 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), | ||
282 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), | ||
283 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), | ||
284 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); | ||
285 | |||
286 | REG_WR(marb_bp, watch->instance, rw_ack, ack); | ||
287 | REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); | ||
288 | |||
289 | printk("IRQ occured at %lX\n", regs->erp); | ||
290 | |||
291 | if (watch->cb) | ||
292 | watch->cb(); | ||
293 | |||
294 | |||
295 | return IRQ_HANDLED; | ||
296 | } | ||
diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c index e513da711245..77d02c15a7fc 100644 --- a/arch/cris/arch-v32/kernel/crisksyms.c +++ b/arch/cris/arch-v32/kernel/crisksyms.c | |||
@@ -2,7 +2,8 @@ | |||
2 | #include <linux/irq.h> | 2 | #include <linux/irq.h> |
3 | #include <asm/arch/dma.h> | 3 | #include <asm/arch/dma.h> |
4 | #include <asm/arch/intmem.h> | 4 | #include <asm/arch/intmem.h> |
5 | #include <asm/arch/pinmux.h> | 5 | #include <asm/arch/mach/pinmux.h> |
6 | #include <asm/arch/io.h> | ||
6 | 7 | ||
7 | /* Functions for allocating DMA channels */ | 8 | /* Functions for allocating DMA channels */ |
8 | EXPORT_SYMBOL(crisv32_request_dma); | 9 | EXPORT_SYMBOL(crisv32_request_dma); |
@@ -16,7 +17,11 @@ EXPORT_SYMBOL(crisv32_intmem_virt_to_phys); | |||
16 | 17 | ||
17 | /* Functions for handling pinmux */ | 18 | /* Functions for handling pinmux */ |
18 | EXPORT_SYMBOL(crisv32_pinmux_alloc); | 19 | EXPORT_SYMBOL(crisv32_pinmux_alloc); |
20 | EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed); | ||
19 | EXPORT_SYMBOL(crisv32_pinmux_dealloc); | 21 | EXPORT_SYMBOL(crisv32_pinmux_dealloc); |
22 | EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed); | ||
23 | EXPORT_SYMBOL(crisv32_io_get_name); | ||
24 | EXPORT_SYMBOL(crisv32_io_get); | ||
20 | 25 | ||
21 | /* Functions masking/unmasking interrupts */ | 26 | /* Functions masking/unmasking interrupts */ |
22 | EXPORT_SYMBOL(mask_irq); | 27 | EXPORT_SYMBOL(mask_irq); |
diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c index d1272ad92153..15af4c293157 100644 --- a/arch/cris/arch-v32/kernel/debugport.c +++ b/arch/cris/arch-v32/kernel/debugport.c | |||
@@ -4,17 +4,12 @@ | |||
4 | 4 | ||
5 | #include <linux/console.h> | 5 | #include <linux/console.h> |
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/major.h> | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/tty.h> | ||
10 | #include <asm/system.h> | 7 | #include <asm/system.h> |
11 | #include <asm/io.h> | 8 | #include <hwregs/reg_rdwr.h> |
12 | #include <asm/arch/hwregs/ser_defs.h> | 9 | #include <hwregs/reg_map.h> |
13 | #include <asm/arch/hwregs/dma_defs.h> | 10 | #include <hwregs/ser_defs.h> |
14 | #include <asm/arch/pinmux.h> | 11 | #include <hwregs/dma_defs.h> |
15 | 12 | #include <asm/arch/mach/pinmux.h> | |
16 | #include <asm/irq.h> | ||
17 | #include <asm/arch/hwregs/intr_vect_defs.h> | ||
18 | 13 | ||
19 | struct dbg_port | 14 | struct dbg_port |
20 | { | 15 | { |
@@ -59,45 +54,50 @@ struct dbg_port ports[] = | |||
59 | 115200, | 54 | 115200, |
60 | 'N', | 55 | 'N', |
61 | 8 | 56 | 8 |
62 | } | 57 | }, |
58 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 | ||
59 | { | ||
60 | 4, | ||
61 | regi_ser4, | ||
62 | 0, | ||
63 | 115200, | ||
64 | 'N', | ||
65 | 8 | ||
66 | }, | ||
67 | #endif | ||
63 | }; | 68 | }; |
64 | static struct dbg_port *port = | 69 | static struct dbg_port *port = |
65 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) | 70 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) |
66 | &ports[0]; | 71 | &ports[0]; |
67 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | 72 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) |
68 | &ports[1]; | 73 | &ports[1]; |
69 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | 74 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) |
70 | &ports[2]; | 75 | &ports[2]; |
71 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | 76 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) |
72 | &ports[3]; | 77 | &ports[3]; |
78 | #elif defined(CONFIG_ETRAX_DEBUG_PORT4) | ||
79 | &ports[4]; | ||
73 | #else | 80 | #else |
74 | NULL; | 81 | NULL; |
75 | #endif | 82 | #endif |
76 | 83 | ||
77 | #ifdef CONFIG_ETRAX_KGDB | 84 | #ifdef CONFIG_ETRAX_KGDB |
78 | static struct dbg_port *kgdb_port = | 85 | static struct dbg_port *kgdb_port = |
79 | #if defined(CONFIG_ETRAX_KGDB_PORT0) | 86 | #if defined(CONFIG_ETRAX_KGDB_PORT0) |
80 | &ports[0]; | 87 | &ports[0]; |
81 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) | 88 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) |
82 | &ports[1]; | 89 | &ports[1]; |
83 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) | 90 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) |
84 | &ports[2]; | 91 | &ports[2]; |
85 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) | 92 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) |
86 | &ports[3]; | 93 | &ports[3]; |
94 | #elif defined(CONFIG_ETRAX_KGDB_PORT4) | ||
95 | &ports[4]; | ||
87 | #else | 96 | #else |
88 | NULL; | 97 | NULL; |
89 | #endif | 98 | #endif |
90 | #endif | 99 | #endif |
91 | 100 | ||
92 | #ifdef CONFIG_ETRAXFS_SIM | ||
93 | extern void print_str( const char *str ); | ||
94 | static char buffer[1024]; | ||
95 | static char msg[] = "Debug: "; | ||
96 | static int buffer_pos = sizeof(msg) - 1; | ||
97 | #endif | ||
98 | |||
99 | extern struct tty_driver *serial_driver; | ||
100 | |||
101 | static void | 101 | static void |
102 | start_port(struct dbg_port* p) | 102 | start_port(struct dbg_port* p) |
103 | { | 103 | { |
@@ -114,6 +114,10 @@ start_port(struct dbg_port* p) | |||
114 | crisv32_pinmux_alloc_fixed(pinmux_ser2); | 114 | crisv32_pinmux_alloc_fixed(pinmux_ser2); |
115 | else if (p->nbr == 3) | 115 | else if (p->nbr == 3) |
116 | crisv32_pinmux_alloc_fixed(pinmux_ser3); | 116 | crisv32_pinmux_alloc_fixed(pinmux_ser3); |
117 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 | ||
118 | else if (p->nbr == 4) | ||
119 | crisv32_pinmux_alloc_fixed(pinmux_ser4); | ||
120 | #endif | ||
117 | 121 | ||
118 | /* Set up serial port registers */ | 122 | /* Set up serial port registers */ |
119 | reg_ser_rw_tr_ctrl tr_ctrl = {0}; | 123 | reg_ser_rw_tr_ctrl tr_ctrl = {0}; |
@@ -156,124 +160,21 @@ start_port(struct dbg_port* p) | |||
156 | REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); | 160 | REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); |
157 | } | 161 | } |
158 | 162 | ||
159 | /* No debug */ | ||
160 | #ifdef CONFIG_ETRAX_DEBUG_PORT_NULL | ||
161 | |||
162 | static void | ||
163 | console_write(struct console *co, const char *buf, unsigned int len) | ||
164 | { | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | /* Target debug */ | ||
169 | #elif !defined(CONFIG_ETRAXFS_SIM) | ||
170 | |||
171 | static void | ||
172 | console_write_direct(struct console *co, const char *buf, unsigned int len) | ||
173 | { | ||
174 | int i; | ||
175 | reg_ser_r_stat_din stat; | ||
176 | reg_ser_rw_tr_dma_en tr_dma_en, old; | ||
177 | |||
178 | /* Switch to manual mode */ | ||
179 | tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en); | ||
180 | if (tr_dma_en.en == regk_ser_yes) { | ||
181 | tr_dma_en.en = regk_ser_no; | ||
182 | REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en); | ||
183 | } | ||
184 | |||
185 | /* Send data */ | ||
186 | for (i = 0; i < len; i++) { | ||
187 | /* LF -> CRLF */ | ||
188 | if (buf[i] == '\n') { | ||
189 | do { | ||
190 | stat = REG_RD (ser, port->instance, r_stat_din); | ||
191 | } while (!stat.tr_rdy); | ||
192 | REG_WR_INT (ser, port->instance, rw_dout, '\r'); | ||
193 | } | ||
194 | /* Wait until transmitter is ready and send.*/ | ||
195 | do { | ||
196 | stat = REG_RD (ser, port->instance, r_stat_din); | ||
197 | } while (!stat.tr_rdy); | ||
198 | REG_WR_INT (ser, port->instance, rw_dout, buf[i]); | ||
199 | } | ||
200 | |||
201 | /* Restore mode */ | ||
202 | if (tr_dma_en.en != old.en) | ||
203 | REG_WR(ser, port->instance, rw_tr_dma_en, old); | ||
204 | } | ||
205 | |||
206 | static void | ||
207 | console_write(struct console *co, const char *buf, unsigned int len) | ||
208 | { | ||
209 | if (!port) | ||
210 | return; | ||
211 | console_write_direct(co, buf, len); | ||
212 | } | ||
213 | |||
214 | |||
215 | |||
216 | #else | ||
217 | |||
218 | /* VCS debug */ | ||
219 | |||
220 | static void | ||
221 | console_write(struct console *co, const char *buf, unsigned int len) | ||
222 | { | ||
223 | char* pos; | ||
224 | pos = memchr(buf, '\n', len); | ||
225 | if (pos) { | ||
226 | int l = ++pos - buf; | ||
227 | memcpy(buffer + buffer_pos, buf, l); | ||
228 | memcpy(buffer, msg, sizeof(msg) - 1); | ||
229 | buffer[buffer_pos + l] = '\0'; | ||
230 | print_str(buffer); | ||
231 | buffer_pos = sizeof(msg) - 1; | ||
232 | if (pos - buf != len) { | ||
233 | memcpy(buffer + buffer_pos, pos, len - l); | ||
234 | buffer_pos += len - l; | ||
235 | } | ||
236 | } else { | ||
237 | memcpy(buffer + buffer_pos, buf, len); | ||
238 | buffer_pos += len; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | #endif | ||
243 | |||
244 | int raw_printk(const char *fmt, ...) | ||
245 | { | ||
246 | static char buf[1024]; | ||
247 | int printed_len; | ||
248 | va_list args; | ||
249 | va_start(args, fmt); | ||
250 | printed_len = vsnprintf(buf, sizeof(buf), fmt, args); | ||
251 | va_end(args); | ||
252 | console_write(NULL, buf, strlen(buf)); | ||
253 | return printed_len; | ||
254 | } | ||
255 | |||
256 | void | ||
257 | stupid_debug(char* buf) | ||
258 | { | ||
259 | console_write(NULL, buf, strlen(buf)); | ||
260 | } | ||
261 | |||
262 | #ifdef CONFIG_ETRAX_KGDB | 163 | #ifdef CONFIG_ETRAX_KGDB |
263 | /* Use polling to get a single character from the kernel debug port */ | 164 | /* Use polling to get a single character from the kernel debug port */ |
264 | int | 165 | int |
265 | getDebugChar(void) | 166 | getDebugChar(void) |
266 | { | 167 | { |
267 | reg_ser_rs_status_data stat; | 168 | reg_ser_rs_stat_din stat; |
268 | reg_ser_rw_ack_intr ack_intr = { 0 }; | 169 | reg_ser_rw_ack_intr ack_intr = { 0 }; |
269 | 170 | ||
270 | do { | 171 | do { |
271 | stat = REG_RD(ser, kgdb_instance, rs_status_data); | 172 | stat = REG_RD(ser, kgdb_port->instance, rs_stat_din); |
272 | } while (!stat.data_avail); | 173 | } while (!stat.dav); |
273 | 174 | ||
274 | /* Ack the data_avail interrupt. */ | 175 | /* Ack the data_avail interrupt. */ |
275 | ack_intr.data_avail = 1; | 176 | ack_intr.dav = 1; |
276 | REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr); | 177 | REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr); |
277 | 178 | ||
278 | return stat.data; | 179 | return stat.data; |
279 | } | 180 | } |
@@ -282,173 +183,18 @@ getDebugChar(void) | |||
282 | void | 183 | void |
283 | putDebugChar(int val) | 184 | putDebugChar(int val) |
284 | { | 185 | { |
285 | reg_ser_r_status_data stat; | 186 | reg_ser_r_stat_din stat; |
286 | do { | 187 | do { |
287 | stat = REG_RD (ser, kgdb_instance, r_status_data); | 188 | stat = REG_RD(ser, kgdb_port->instance, r_stat_din); |
288 | } while (!stat.tr_ready); | 189 | } while (!stat.tr_rdy); |
289 | REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val)); | 190 | REG_WR_INT(ser, kgdb_port->instance, rw_dout, val); |
290 | } | 191 | } |
291 | #endif /* CONFIG_ETRAX_KGDB */ | 192 | #endif /* CONFIG_ETRAX_KGDB */ |
292 | 193 | ||
293 | static int __init | ||
294 | console_setup(struct console *co, char *options) | ||
295 | { | ||
296 | char* s; | ||
297 | |||
298 | if (options) { | ||
299 | port = &ports[co->index]; | ||
300 | port->baudrate = 115200; | ||
301 | port->parity = 'N'; | ||
302 | port->bits = 8; | ||
303 | port->baudrate = simple_strtoul(options, NULL, 10); | ||
304 | s = options; | ||
305 | while(*s >= '0' && *s <= '9') | ||
306 | s++; | ||
307 | if (*s) port->parity = *s++; | ||
308 | if (*s) port->bits = *s++ - '0'; | ||
309 | port->started = 0; | ||
310 | start_port(port); | ||
311 | } | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* This is a dummy serial device that throws away anything written to it. | ||
316 | * This is used when no debug output is wanted. | ||
317 | */ | ||
318 | static struct tty_driver dummy_driver; | ||
319 | |||
320 | static int dummy_open(struct tty_struct *tty, struct file * filp) | ||
321 | { | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void dummy_close(struct tty_struct *tty, struct file * filp) | ||
326 | { | ||
327 | } | ||
328 | |||
329 | static int dummy_write(struct tty_struct * tty, | ||
330 | const unsigned char *buf, int count) | ||
331 | { | ||
332 | return count; | ||
333 | } | ||
334 | |||
335 | static int | ||
336 | dummy_write_room(struct tty_struct *tty) | ||
337 | { | ||
338 | return 8192; | ||
339 | } | ||
340 | |||
341 | void __init | ||
342 | init_dummy_console(void) | ||
343 | { | ||
344 | memset(&dummy_driver, 0, sizeof(struct tty_driver)); | ||
345 | dummy_driver.driver_name = "serial"; | ||
346 | dummy_driver.name = "ttyS"; | ||
347 | dummy_driver.major = TTY_MAJOR; | ||
348 | dummy_driver.minor_start = 68; | ||
349 | dummy_driver.num = 1; /* etrax100 has 4 serial ports */ | ||
350 | dummy_driver.type = TTY_DRIVER_TYPE_SERIAL; | ||
351 | dummy_driver.subtype = SERIAL_TYPE_NORMAL; | ||
352 | dummy_driver.init_termios = tty_std_termios; | ||
353 | dummy_driver.init_termios.c_cflag = | ||
354 | B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ | ||
355 | dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
356 | |||
357 | dummy_driver.open = dummy_open; | ||
358 | dummy_driver.close = dummy_close; | ||
359 | dummy_driver.write = dummy_write; | ||
360 | dummy_driver.write_room = dummy_write_room; | ||
361 | if (tty_register_driver(&dummy_driver)) | ||
362 | panic("Couldn't register dummy serial driver\n"); | ||
363 | } | ||
364 | |||
365 | static struct tty_driver* | ||
366 | crisv32_console_device(struct console* co, int *index) | ||
367 | { | ||
368 | if (port) | ||
369 | *index = port->nbr; | ||
370 | return port ? serial_driver : &dummy_driver; | ||
371 | } | ||
372 | |||
373 | static struct console sercons = { | ||
374 | name : "ttyS", | ||
375 | write: console_write, | ||
376 | read : NULL, | ||
377 | device : crisv32_console_device, | ||
378 | unblank : NULL, | ||
379 | setup : console_setup, | ||
380 | flags : CON_PRINTBUFFER, | ||
381 | index : -1, | ||
382 | cflag : 0, | ||
383 | next : NULL | ||
384 | }; | ||
385 | static struct console sercons0 = { | ||
386 | name : "ttyS", | ||
387 | write: console_write, | ||
388 | read : NULL, | ||
389 | device : crisv32_console_device, | ||
390 | unblank : NULL, | ||
391 | setup : console_setup, | ||
392 | flags : CON_PRINTBUFFER, | ||
393 | index : 0, | ||
394 | cflag : 0, | ||
395 | next : NULL | ||
396 | }; | ||
397 | |||
398 | static struct console sercons1 = { | ||
399 | name : "ttyS", | ||
400 | write: console_write, | ||
401 | read : NULL, | ||
402 | device : crisv32_console_device, | ||
403 | unblank : NULL, | ||
404 | setup : console_setup, | ||
405 | flags : CON_PRINTBUFFER, | ||
406 | index : 1, | ||
407 | cflag : 0, | ||
408 | next : NULL | ||
409 | }; | ||
410 | static struct console sercons2 = { | ||
411 | name : "ttyS", | ||
412 | write: console_write, | ||
413 | read : NULL, | ||
414 | device : crisv32_console_device, | ||
415 | unblank : NULL, | ||
416 | setup : console_setup, | ||
417 | flags : CON_PRINTBUFFER, | ||
418 | index : 2, | ||
419 | cflag : 0, | ||
420 | next : NULL | ||
421 | }; | ||
422 | static struct console sercons3 = { | ||
423 | name : "ttyS", | ||
424 | write: console_write, | ||
425 | read : NULL, | ||
426 | device : crisv32_console_device, | ||
427 | unblank : NULL, | ||
428 | setup : console_setup, | ||
429 | flags : CON_PRINTBUFFER, | ||
430 | index : 3, | ||
431 | cflag : 0, | ||
432 | next : NULL | ||
433 | }; | ||
434 | |||
435 | /* Register console for printk's, etc. */ | 194 | /* Register console for printk's, etc. */ |
436 | int __init | 195 | int __init |
437 | init_etrax_debug(void) | 196 | init_etrax_debug(void) |
438 | { | 197 | { |
439 | static int first = 1; | ||
440 | |||
441 | if (!first) { | ||
442 | unregister_console(&sercons); | ||
443 | register_console(&sercons0); | ||
444 | register_console(&sercons1); | ||
445 | register_console(&sercons2); | ||
446 | register_console(&sercons3); | ||
447 | init_dummy_console(); | ||
448 | return 0; | ||
449 | } | ||
450 | first = 0; | ||
451 | register_console(&sercons); | ||
452 | start_port(port); | 198 | start_port(port); |
453 | 199 | ||
454 | #ifdef CONFIG_ETRAX_KGDB | 200 | #ifdef CONFIG_ETRAX_KGDB |
@@ -456,5 +202,3 @@ init_etrax_debug(void) | |||
456 | #endif /* CONFIG_ETRAX_KGDB */ | 202 | #endif /* CONFIG_ETRAX_KGDB */ |
457 | return 0; | 203 | return 0; |
458 | } | 204 | } |
459 | |||
460 | __initcall(init_etrax_debug); | ||
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index f9d27807b914..eebbaba45430 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S | |||
@@ -10,7 +10,7 @@ | |||
10 | * after a timer-interrupt and after each system call. | 10 | * after a timer-interrupt and after each system call. |
11 | * | 11 | * |
12 | * Stack layout in 'ret_from_system_call': | 12 | * Stack layout in 'ret_from_system_call': |
13 | * ptrace needs to have all regs on the stack. | 13 | * ptrace needs to have all regs on the stack. |
14 | * if the order here is changed, it needs to be | 14 | * if the order here is changed, it needs to be |
15 | * updated in fork.c:copy_process, signal.c:do_signal, | 15 | * updated in fork.c:copy_process, signal.c:do_signal, |
16 | * ptrace.c and ptrace.h | 16 | * ptrace.c and ptrace.h |
@@ -281,12 +281,10 @@ _work_notifysig: | |||
281 | ;; Deal with pending signals and notify-resume requests. | 281 | ;; Deal with pending signals and notify-resume requests. |
282 | 282 | ||
283 | addoq +TI_flags, $r0, $acr | 283 | addoq +TI_flags, $r0, $acr |
284 | move.d [$acr], $r13 ; The thread_info_flags parameter. | 284 | move.d [$acr], $r12 ; The thread_info_flags parameter. |
285 | move.d $r9, $r10 ; do_notify_resume syscall/irq param. | 285 | move.d $sp, $r11 ; The regs param. |
286 | moveq 0, $r11 ; oldset param - 0 in this case. | ||
287 | move.d $sp, $r12 ; The regs param. | ||
288 | jsr do_notify_resume | 286 | jsr do_notify_resume |
289 | nop | 287 | move.d $r9, $r10 ; do_notify_resume syscall/irq param. |
290 | 288 | ||
291 | ba _Rexit | 289 | ba _Rexit |
292 | nop | 290 | nop |
@@ -396,7 +394,7 @@ nmi_interrupt: | |||
396 | btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0 | 394 | btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0 |
397 | bpl 1f | 395 | bpl 1f |
398 | nop | 396 | nop |
399 | jsr handle_watchdog_bite ; In time.c. | 397 | jsr handle_watchdog_bite ; In time.c. |
400 | move.d $sp, $r10 ; Pointer to registers | 398 | move.d $sp, $r10 ; Pointer to registers |
401 | 1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 | 399 | 1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 |
402 | bpl 1f | 400 | bpl 1f |
@@ -515,6 +513,13 @@ _ugdb_handle_exception: | |||
515 | ba do_sigtrap ; SIGTRAP the offending process. | 513 | ba do_sigtrap ; SIGTRAP the offending process. |
516 | move.d [$sp+], $r0 ; Restore R0 in delay slot. | 514 | move.d [$sp+], $r0 ; Restore R0 in delay slot. |
517 | 515 | ||
516 | .global kernel_execve | ||
517 | kernel_execve: | ||
518 | move.d __NR_execve, $r9 | ||
519 | break 13 | ||
520 | ret | ||
521 | nop | ||
522 | |||
518 | .data | 523 | .data |
519 | 524 | ||
520 | .section .rodata,"a" | 525 | .section .rodata,"a" |
@@ -778,21 +783,21 @@ sys_call_table: | |||
778 | .long sys_epoll_ctl /* 255 */ | 783 | .long sys_epoll_ctl /* 255 */ |
779 | .long sys_epoll_wait | 784 | .long sys_epoll_wait |
780 | .long sys_remap_file_pages | 785 | .long sys_remap_file_pages |
781 | .long sys_set_tid_address | 786 | .long sys_set_tid_address |
782 | .long sys_timer_create | 787 | .long sys_timer_create |
783 | .long sys_timer_settime /* 260 */ | 788 | .long sys_timer_settime /* 260 */ |
784 | .long sys_timer_gettime | 789 | .long sys_timer_gettime |
785 | .long sys_timer_getoverrun | 790 | .long sys_timer_getoverrun |
786 | .long sys_timer_delete | 791 | .long sys_timer_delete |
787 | .long sys_clock_settime | 792 | .long sys_clock_settime |
788 | .long sys_clock_gettime /* 265 */ | 793 | .long sys_clock_gettime /* 265 */ |
789 | .long sys_clock_getres | 794 | .long sys_clock_getres |
790 | .long sys_clock_nanosleep | 795 | .long sys_clock_nanosleep |
791 | .long sys_statfs64 | 796 | .long sys_statfs64 |
792 | .long sys_fstatfs64 | 797 | .long sys_fstatfs64 |
793 | .long sys_tgkill /* 270 */ | 798 | .long sys_tgkill /* 270 */ |
794 | .long sys_utimes | 799 | .long sys_utimes |
795 | .long sys_fadvise64_64 | 800 | .long sys_fadvise64_64 |
796 | .long sys_ni_syscall /* sys_vserver */ | 801 | .long sys_ni_syscall /* sys_vserver */ |
797 | .long sys_ni_syscall /* sys_mbind */ | 802 | .long sys_ni_syscall /* sys_mbind */ |
798 | .long sys_ni_syscall /* 275 sys_get_mempolicy */ | 803 | .long sys_ni_syscall /* 275 sys_get_mempolicy */ |
@@ -805,6 +810,48 @@ sys_call_table: | |||
805 | .long sys_mq_getsetattr | 810 | .long sys_mq_getsetattr |
806 | .long sys_ni_syscall /* reserved for kexec */ | 811 | .long sys_ni_syscall /* reserved for kexec */ |
807 | .long sys_waitid | 812 | .long sys_waitid |
813 | .long sys_ni_syscall /* 285 */ /* available */ | ||
814 | .long sys_add_key | ||
815 | .long sys_request_key | ||
816 | .long sys_keyctl | ||
817 | .long sys_ioprio_set | ||
818 | .long sys_ioprio_get /* 290 */ | ||
819 | .long sys_inotify_init | ||
820 | .long sys_inotify_add_watch | ||
821 | .long sys_inotify_rm_watch | ||
822 | .long sys_migrate_pages | ||
823 | .long sys_openat /* 295 */ | ||
824 | .long sys_mkdirat | ||
825 | .long sys_mknodat | ||
826 | .long sys_fchownat | ||
827 | .long sys_futimesat | ||
828 | .long sys_fstatat64 /* 300 */ | ||
829 | .long sys_unlinkat | ||
830 | .long sys_renameat | ||
831 | .long sys_linkat | ||
832 | .long sys_symlinkat | ||
833 | .long sys_readlinkat /* 305 */ | ||
834 | .long sys_fchmodat | ||
835 | .long sys_faccessat | ||
836 | .long sys_pselect6 | ||
837 | .long sys_ppoll | ||
838 | .long sys_unshare /* 310 */ | ||
839 | .long sys_set_robust_list | ||
840 | .long sys_get_robust_list | ||
841 | .long sys_splice | ||
842 | .long sys_sync_file_range | ||
843 | .long sys_tee /* 315 */ | ||
844 | .long sys_vmsplice | ||
845 | .long sys_move_pages | ||
846 | .long sys_getcpu | ||
847 | .long sys_epoll_pwait | ||
848 | .long sys_utimensat /* 320 */ | ||
849 | .long sys_signalfd | ||
850 | .long sys_timerfd_create | ||
851 | .long sys_eventfd | ||
852 | .long sys_fallocate | ||
853 | .long sys_timerfd_settime /* 325 */ | ||
854 | .long sys_timerfd_gettime | ||
808 | 855 | ||
809 | /* | 856 | /* |
810 | * NOTE!! This doesn't have to be exact - we just have | 857 | * NOTE!! This doesn't have to be exact - we just have |
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c index b40551f9f40d..2de9d5849ef0 100644 --- a/arch/cris/arch-v32/kernel/fasttimer.c +++ b/arch/cris/arch-v32/kernel/fasttimer.c | |||
@@ -1,110 +1,9 @@ | |||
1 | /* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $ | 1 | /* |
2 | * linux/arch/cris/kernel/fasttimer.c | 2 | * linux/arch/cris/kernel/fasttimer.c |
3 | * | 3 | * |
4 | * Fast timers for ETRAX FS | 4 | * Fast timers for ETRAX FS |
5 | * This may be useful in other OS than Linux so use 2 space indentation... | ||
6 | * | ||
7 | * $Log: fasttimer.c,v $ | ||
8 | * Revision 1.11 2005/01/04 11:15:46 starvik | ||
9 | * Don't share timer IRQ. | ||
10 | * | ||
11 | * Revision 1.10 2004/12/07 09:19:38 starvik | ||
12 | * Corrected includes. | ||
13 | * Use correct interrupt macros. | ||
14 | * | ||
15 | * Revision 1.9 2004/05/14 10:18:58 starvik | ||
16 | * Export fast_timer_list | ||
17 | * | ||
18 | * Revision 1.8 2004/05/14 07:58:03 starvik | ||
19 | * Merge of changes from 2.4 | ||
20 | * | ||
21 | * Revision 1.7 2003/07/10 12:06:14 starvik | ||
22 | * Return IRQ_NONE if irq wasn't handled | ||
23 | * | ||
24 | * Revision 1.6 2003/07/04 08:27:49 starvik | ||
25 | * Merge of Linux 2.5.74 | ||
26 | * | ||
27 | * Revision 1.5 2003/06/05 10:16:22 johana | ||
28 | * New INTR_VECT macros. | ||
29 | * | ||
30 | * Revision 1.4 2003/06/03 08:49:45 johana | ||
31 | * Fixed typo. | ||
32 | * | ||
33 | * Revision 1.3 2003/06/02 12:51:27 johana | ||
34 | * Now compiles. | ||
35 | * Commented some include files that probably can be removed. | ||
36 | * | ||
37 | * Revision 1.2 2003/06/02 12:09:41 johana | ||
38 | * Ported to ETRAX FS using the trig interrupt instead of timer1. | ||
39 | * | ||
40 | * Revision 1.3 2002/12/12 08:26:32 starvik | ||
41 | * Don't use C-comments inside CVS comments | ||
42 | * | ||
43 | * Revision 1.2 2002/12/11 15:42:02 starvik | ||
44 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
45 | * | ||
46 | * Revision 1.1 2002/11/18 07:58:06 starvik | ||
47 | * Fast timers (from Linux 2.4) | ||
48 | * | ||
49 | * Revision 1.5 2002/10/15 06:21:39 starvik | ||
50 | * Added call to init_waitqueue_head | ||
51 | * | 5 | * |
52 | * Revision 1.4 2002/05/28 17:47:59 johana | 6 | * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden |
53 | * Added del_fast_timer() | ||
54 | * | ||
55 | * Revision 1.3 2002/05/28 16:16:07 johana | ||
56 | * Handle empty fast_timer_list | ||
57 | * | ||
58 | * Revision 1.2 2002/05/27 15:38:42 johana | ||
59 | * Made it compile without warnings on Linux 2.4. | ||
60 | * (includes, wait_queue, PROC_FS and snprintf) | ||
61 | * | ||
62 | * Revision 1.1 2002/05/27 15:32:25 johana | ||
63 | * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. | ||
64 | * | ||
65 | * Revision 1.8 2001/11/27 13:50:40 pkj | ||
66 | * Disable interrupts while stopping the timer and while modifying the | ||
67 | * list of active timers in timer1_handler() as it may be interrupted | ||
68 | * by other interrupts (e.g., the serial interrupt) which may add fast | ||
69 | * timers. | ||
70 | * | ||
71 | * Revision 1.7 2001/11/22 11:50:32 pkj | ||
72 | * * Only store information about the last 16 timers. | ||
73 | * * proc_fasttimer_read() now uses an allocated buffer, since it | ||
74 | * requires more space than just a page even for only writing the | ||
75 | * last 16 timers. The buffer is only allocated on request, so | ||
76 | * unless /proc/fasttimer is read, it is never allocated. | ||
77 | * * Renamed fast_timer_started to fast_timers_started to match | ||
78 | * fast_timers_added and fast_timers_expired. | ||
79 | * * Some clean-up. | ||
80 | * | ||
81 | * Revision 1.6 2000/12/13 14:02:08 johana | ||
82 | * Removed volatile for fast_timer_list | ||
83 | * | ||
84 | * Revision 1.5 2000/12/13 13:55:35 johana | ||
85 | * Added DEBUG_LOG, added som cli() and cleanup | ||
86 | * | ||
87 | * Revision 1.4 2000/12/05 13:48:50 johana | ||
88 | * Added range check when writing proc file, modified timer int handling | ||
89 | * | ||
90 | * Revision 1.3 2000/11/23 10:10:20 johana | ||
91 | * More debug/logging possibilities. | ||
92 | * Moved GET_JIFFIES_USEC() to timex.h and time.c | ||
93 | * | ||
94 | * Revision 1.2 2000/11/01 13:41:04 johana | ||
95 | * Clean up and bugfixes. | ||
96 | * Created new do_gettimeofday_fast() that gets a timeval struct | ||
97 | * with time based on jiffies and *R_TIMER0_DATA, uses a table | ||
98 | * for fast conversion of timer value to microseconds. | ||
99 | * (Much faster the standard do_gettimeofday() and we don't really | ||
100 | * want to use the true time - we want the "uptime" so timers don't screw up | ||
101 | * when we change the time. | ||
102 | * TODO: Add efficient support for continuous timers as well. | ||
103 | * | ||
104 | * Revision 1.1 2000/10/26 15:49:16 johana | ||
105 | * Added fasttimer, highresolution timers. | ||
106 | * | ||
107 | * Copyright (C) 2000,2001 2002, 2003 Axis Communications AB, Lund, Sweden | ||
108 | */ | 7 | */ |
109 | 8 | ||
110 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
@@ -122,9 +21,9 @@ | |||
122 | 21 | ||
123 | #include <linux/version.h> | 22 | #include <linux/version.h> |
124 | 23 | ||
125 | #include <asm/arch/hwregs/reg_map.h> | 24 | #include <hwregs/reg_map.h> |
126 | #include <asm/arch/hwregs/reg_rdwr.h> | 25 | #include <hwregs/reg_rdwr.h> |
127 | #include <asm/arch/hwregs/timer_defs.h> | 26 | #include <hwregs/timer_defs.h> |
128 | #include <asm/fasttimer.h> | 27 | #include <asm/fasttimer.h> |
129 | #include <linux/proc_fs.h> | 28 | #include <linux/proc_fs.h> |
130 | 29 | ||
@@ -140,30 +39,25 @@ | |||
140 | 39 | ||
141 | #define DEBUG_LOG_INCLUDED | 40 | #define DEBUG_LOG_INCLUDED |
142 | #define FAST_TIMER_LOG | 41 | #define FAST_TIMER_LOG |
143 | //#define FAST_TIMER_TEST | 42 | /* #define FAST_TIMER_TEST */ |
144 | 43 | ||
145 | #define FAST_TIMER_SANITY_CHECKS | 44 | #define FAST_TIMER_SANITY_CHECKS |
146 | 45 | ||
147 | #ifdef FAST_TIMER_SANITY_CHECKS | 46 | #ifdef FAST_TIMER_SANITY_CHECKS |
148 | #define SANITYCHECK(x) x | 47 | static int sanity_failed; |
149 | static int sanity_failed = 0; | ||
150 | #else | ||
151 | #define SANITYCHECK(x) | ||
152 | #endif | 48 | #endif |
153 | 49 | ||
154 | #define D1(x) | 50 | #define D1(x) |
155 | #define D2(x) | 51 | #define D2(x) |
156 | #define DP(x) | 52 | #define DP(x) |
157 | 53 | ||
158 | #define __INLINE__ inline | 54 | static unsigned int fast_timer_running; |
159 | 55 | static unsigned int fast_timers_added; | |
160 | static int fast_timer_running = 0; | 56 | static unsigned int fast_timers_started; |
161 | static int fast_timers_added = 0; | 57 | static unsigned int fast_timers_expired; |
162 | static int fast_timers_started = 0; | 58 | static unsigned int fast_timers_deleted; |
163 | static int fast_timers_expired = 0; | 59 | static unsigned int fast_timer_is_init; |
164 | static int fast_timers_deleted = 0; | 60 | static unsigned int fast_timer_ints; |
165 | static int fast_timer_is_init = 0; | ||
166 | static int fast_timer_ints = 0; | ||
167 | 61 | ||
168 | struct fast_timer *fast_timer_list = NULL; | 62 | struct fast_timer *fast_timer_list = NULL; |
169 | 63 | ||
@@ -171,8 +65,8 @@ struct fast_timer *fast_timer_list = NULL; | |||
171 | #define DEBUG_LOG_MAX 128 | 65 | #define DEBUG_LOG_MAX 128 |
172 | static const char * debug_log_string[DEBUG_LOG_MAX]; | 66 | static const char * debug_log_string[DEBUG_LOG_MAX]; |
173 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; | 67 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; |
174 | static int debug_log_cnt = 0; | 68 | static unsigned int debug_log_cnt; |
175 | static int debug_log_cnt_wrapped = 0; | 69 | static unsigned int debug_log_cnt_wrapped; |
176 | 70 | ||
177 | #define DEBUG_LOG(string, value) \ | 71 | #define DEBUG_LOG(string, value) \ |
178 | { \ | 72 | { \ |
@@ -202,103 +96,92 @@ struct fast_timer timer_expired_log[NUM_TIMER_STATS]; | |||
202 | int timer_div_settings[NUM_TIMER_STATS]; | 96 | int timer_div_settings[NUM_TIMER_STATS]; |
203 | int timer_delay_settings[NUM_TIMER_STATS]; | 97 | int timer_delay_settings[NUM_TIMER_STATS]; |
204 | 98 | ||
99 | struct work_struct fast_work; | ||
205 | 100 | ||
206 | static void | 101 | static void |
207 | timer_trig_handler(void); | 102 | timer_trig_handler(struct work_struct *work); |
208 | 103 | ||
209 | 104 | ||
210 | 105 | ||
211 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ | 106 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ |
212 | void __INLINE__ do_gettimeofday_fast(struct timeval *tv) | 107 | inline void do_gettimeofday_fast(struct fasttime_t *tv) |
213 | { | 108 | { |
214 | unsigned long sec = jiffies; | 109 | tv->tv_jiff = jiffies; |
215 | unsigned long usec = GET_JIFFIES_USEC(); | 110 | tv->tv_usec = GET_JIFFIES_USEC(); |
216 | |||
217 | usec += (sec % HZ) * (1000000 / HZ); | ||
218 | sec = sec / HZ; | ||
219 | |||
220 | if (usec > 1000000) | ||
221 | { | ||
222 | usec -= 1000000; | ||
223 | sec++; | ||
224 | } | ||
225 | tv->tv_sec = sec; | ||
226 | tv->tv_usec = usec; | ||
227 | } | 111 | } |
228 | 112 | ||
229 | int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) | 113 | inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1) |
230 | { | 114 | { |
231 | if (t0->tv_sec < t1->tv_sec) | 115 | /* Compare jiffies. Takes care of wrapping */ |
232 | { | 116 | if (time_before(t0->tv_jiff, t1->tv_jiff)) |
233 | return -1; | 117 | return -1; |
234 | } | 118 | else if (time_after(t0->tv_jiff, t1->tv_jiff)) |
235 | else if (t0->tv_sec > t1->tv_sec) | 119 | return 1; |
236 | { | 120 | |
237 | return 1; | 121 | /* Compare us */ |
238 | } | 122 | if (t0->tv_usec < t1->tv_usec) |
239 | if (t0->tv_usec < t1->tv_usec) | 123 | return -1; |
240 | { | 124 | else if (t0->tv_usec > t1->tv_usec) |
241 | return -1; | 125 | return 1; |
242 | } | 126 | return 0; |
243 | else if (t0->tv_usec > t1->tv_usec) | ||
244 | { | ||
245 | return 1; | ||
246 | } | ||
247 | return 0; | ||
248 | } | 127 | } |
249 | 128 | ||
250 | /* Called with ints off */ | 129 | /* Called with ints off */ |
251 | void __INLINE__ start_timer_trig(unsigned long delay_us) | 130 | inline void start_timer_trig(unsigned long delay_us) |
252 | { | 131 | { |
253 | reg_timer_rw_ack_intr ack_intr = { 0 }; | 132 | reg_timer_rw_ack_intr ack_intr = { 0 }; |
254 | reg_timer_rw_intr_mask intr_mask; | 133 | reg_timer_rw_intr_mask intr_mask; |
255 | reg_timer_rw_trig trig; | 134 | reg_timer_rw_trig trig; |
256 | reg_timer_rw_trig_cfg trig_cfg = { 0 }; | 135 | reg_timer_rw_trig_cfg trig_cfg = { 0 }; |
257 | reg_timer_r_time r_time; | 136 | reg_timer_r_time r_time0; |
137 | reg_timer_r_time r_time1; | ||
138 | unsigned char trig_wrap; | ||
139 | unsigned char time_wrap; | ||
258 | 140 | ||
259 | r_time = REG_RD(timer, regi_timer, r_time); | 141 | r_time0 = REG_RD(timer, regi_timer0, r_time); |
260 | 142 | ||
261 | D1(printk("start_timer_trig : %d us freq: %i div: %i\n", | 143 | D1(printk("start_timer_trig : %d us freq: %i div: %i\n", |
262 | delay_us, freq_index, div)); | 144 | delay_us, freq_index, div)); |
263 | /* Clear trig irq */ | 145 | /* Clear trig irq */ |
264 | intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); | 146 | intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); |
265 | intr_mask.trig = 0; | 147 | intr_mask.trig = 0; |
266 | REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); | 148 | REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); |
267 | 149 | ||
268 | /* Set timer values */ | 150 | /* Set timer values and check if trigger wraps. */ |
269 | /* r_time is 100MHz (10 ns resolution) */ | 151 | /* r_time is 100MHz (10 ns resolution) */ |
270 | trig = r_time + delay_us*(1000/10); | 152 | trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0; |
271 | 153 | ||
272 | timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig; | 154 | timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig; |
273 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; | 155 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; |
274 | 156 | ||
275 | /* Ack interrupt */ | 157 | /* Ack interrupt */ |
276 | ack_intr.trig = 1; | 158 | ack_intr.trig = 1; |
277 | REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); | 159 | REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); |
278 | 160 | ||
279 | /* Start timer */ | 161 | /* Start timer */ |
280 | REG_WR(timer, regi_timer, rw_trig, trig); | 162 | REG_WR(timer, regi_timer0, rw_trig, trig); |
281 | trig_cfg.tmr = regk_timer_time; | 163 | trig_cfg.tmr = regk_timer_time; |
282 | REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); | 164 | REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); |
283 | 165 | ||
284 | /* Check if we have already passed the trig time */ | 166 | /* Check if we have already passed the trig time */ |
285 | r_time = REG_RD(timer, regi_timer, r_time); | 167 | r_time1 = REG_RD(timer, regi_timer0, r_time); |
286 | if (r_time < trig) { | 168 | time_wrap = r_time1 < r_time0; |
169 | |||
170 | if ((trig_wrap && !time_wrap) || (r_time1 < trig)) { | ||
287 | /* No, Enable trig irq */ | 171 | /* No, Enable trig irq */ |
288 | intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); | 172 | intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); |
289 | intr_mask.trig = 1; | 173 | intr_mask.trig = 1; |
290 | REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); | 174 | REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); |
291 | fast_timers_started++; | 175 | fast_timers_started++; |
292 | fast_timer_running = 1; | 176 | fast_timer_running = 1; |
293 | } | 177 | } else { |
294 | else | ||
295 | { | ||
296 | /* We have passed the time, disable trig point, ack intr */ | 178 | /* We have passed the time, disable trig point, ack intr */ |
297 | trig_cfg.tmr = regk_timer_off; | 179 | trig_cfg.tmr = regk_timer_off; |
298 | REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); | 180 | REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); |
299 | REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); | 181 | REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); |
300 | /* call the int routine directly */ | 182 | /* call the int routine */ |
301 | timer_trig_handler(); | 183 | INIT_WORK(&fast_work, timer_trig_handler); |
184 | schedule_work(&fast_work); | ||
302 | } | 185 | } |
303 | 186 | ||
304 | } | 187 | } |
@@ -320,22 +203,20 @@ void start_one_shot_timer(struct fast_timer *t, | |||
320 | do_gettimeofday_fast(&t->tv_set); | 203 | do_gettimeofday_fast(&t->tv_set); |
321 | tmp = fast_timer_list; | 204 | tmp = fast_timer_list; |
322 | 205 | ||
323 | SANITYCHECK({ /* Check so this is not in the list already... */ | 206 | #ifdef FAST_TIMER_SANITY_CHECKS |
324 | while (tmp != NULL) | 207 | /* Check so this is not in the list already... */ |
325 | { | 208 | while (tmp != NULL) { |
326 | if (tmp == t) | 209 | if (tmp == t) { |
327 | { | 210 | printk(KERN_DEBUG |
328 | printk("timer name: %s data: 0x%08lX already in list!\n", name, data); | 211 | "timer name: %s data: 0x%08lX already " |
329 | sanity_failed++; | 212 | "in list!\n", name, data); |
330 | return; | 213 | sanity_failed++; |
331 | } | 214 | goto done; |
332 | else | 215 | } else |
333 | { | 216 | tmp = tmp->next; |
334 | tmp = tmp->next; | 217 | } |
335 | } | 218 | tmp = fast_timer_list; |
336 | } | 219 | #endif |
337 | tmp = fast_timer_list; | ||
338 | }); | ||
339 | 220 | ||
340 | t->delay_us = delay_us; | 221 | t->delay_us = delay_us; |
341 | t->function = function; | 222 | t->function = function; |
@@ -343,11 +224,10 @@ void start_one_shot_timer(struct fast_timer *t, | |||
343 | t->name = name; | 224 | t->name = name; |
344 | 225 | ||
345 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; | 226 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; |
346 | t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; | 227 | t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ; |
347 | if (t->tv_expires.tv_usec > 1000000) | 228 | if (t->tv_expires.tv_usec > 1000000) { |
348 | { | ||
349 | t->tv_expires.tv_usec -= 1000000; | 229 | t->tv_expires.tv_usec -= 1000000; |
350 | t->tv_expires.tv_sec++; | 230 | t->tv_expires.tv_jiff += HZ; |
351 | } | 231 | } |
352 | #ifdef FAST_TIMER_LOG | 232 | #ifdef FAST_TIMER_LOG |
353 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; | 233 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; |
@@ -355,15 +235,12 @@ void start_one_shot_timer(struct fast_timer *t, | |||
355 | fast_timers_added++; | 235 | fast_timers_added++; |
356 | 236 | ||
357 | /* Check if this should timeout before anything else */ | 237 | /* Check if this should timeout before anything else */ |
358 | if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) | 238 | if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) { |
359 | { | ||
360 | /* Put first in list and modify the timer value */ | 239 | /* Put first in list and modify the timer value */ |
361 | t->prev = NULL; | 240 | t->prev = NULL; |
362 | t->next = fast_timer_list; | 241 | t->next = fast_timer_list; |
363 | if (fast_timer_list) | 242 | if (fast_timer_list) |
364 | { | ||
365 | fast_timer_list->prev = t; | 243 | fast_timer_list->prev = t; |
366 | } | ||
367 | fast_timer_list = t; | 244 | fast_timer_list = t; |
368 | #ifdef FAST_TIMER_LOG | 245 | #ifdef FAST_TIMER_LOG |
369 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | 246 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; |
@@ -372,10 +249,8 @@ void start_one_shot_timer(struct fast_timer *t, | |||
372 | } else { | 249 | } else { |
373 | /* Put in correct place in list */ | 250 | /* Put in correct place in list */ |
374 | while (tmp->next && | 251 | while (tmp->next && |
375 | timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) | 252 | fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) |
376 | { | ||
377 | tmp = tmp->next; | 253 | tmp = tmp->next; |
378 | } | ||
379 | /* Insert t after tmp */ | 254 | /* Insert t after tmp */ |
380 | t->prev = tmp; | 255 | t->prev = tmp; |
381 | t->next = tmp->next; | 256 | t->next = tmp->next; |
@@ -388,6 +263,7 @@ void start_one_shot_timer(struct fast_timer *t, | |||
388 | 263 | ||
389 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); | 264 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); |
390 | 265 | ||
266 | done: | ||
391 | local_irq_restore(flags); | 267 | local_irq_restore(flags); |
392 | } /* start_one_shot_timer */ | 268 | } /* start_one_shot_timer */ |
393 | 269 | ||
@@ -431,19 +307,18 @@ int del_fast_timer(struct fast_timer * t) | |||
431 | /* Timer interrupt handler for trig interrupts */ | 307 | /* Timer interrupt handler for trig interrupts */ |
432 | 308 | ||
433 | static irqreturn_t | 309 | static irqreturn_t |
434 | timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 310 | timer_trig_interrupt(int irq, void *dev_id) |
435 | { | 311 | { |
436 | reg_timer_r_masked_intr masked_intr; | 312 | reg_timer_r_masked_intr masked_intr; |
437 | |||
438 | /* Check if the timer interrupt is for us (a trig int) */ | 313 | /* Check if the timer interrupt is for us (a trig int) */ |
439 | masked_intr = REG_RD(timer, regi_timer, r_masked_intr); | 314 | masked_intr = REG_RD(timer, regi_timer0, r_masked_intr); |
440 | if (!masked_intr.trig) | 315 | if (!masked_intr.trig) |
441 | return IRQ_NONE; | 316 | return IRQ_NONE; |
442 | timer_trig_handler(); | 317 | timer_trig_handler(NULL); |
443 | return IRQ_HANDLED; | 318 | return IRQ_HANDLED; |
444 | } | 319 | } |
445 | 320 | ||
446 | static void timer_trig_handler(void) | 321 | static void timer_trig_handler(struct work_struct *work) |
447 | { | 322 | { |
448 | reg_timer_rw_ack_intr ack_intr = { 0 }; | 323 | reg_timer_rw_ack_intr ack_intr = { 0 }; |
449 | reg_timer_rw_intr_mask intr_mask; | 324 | reg_timer_rw_intr_mask intr_mask; |
@@ -451,38 +326,45 @@ static void timer_trig_handler(void) | |||
451 | struct fast_timer *t; | 326 | struct fast_timer *t; |
452 | unsigned long flags; | 327 | unsigned long flags; |
453 | 328 | ||
329 | /* We keep interrupts disabled not only when we modify the | ||
330 | * fast timer list, but any time we hold a reference to a | ||
331 | * timer in the list, since del_fast_timer may be called | ||
332 | * from (another) interrupt context. Thus, the only time | ||
333 | * when interrupts are enabled is when calling the timer | ||
334 | * callback function. | ||
335 | */ | ||
454 | local_irq_save(flags); | 336 | local_irq_save(flags); |
455 | 337 | ||
456 | /* Clear timer trig interrupt */ | 338 | /* Clear timer trig interrupt */ |
457 | intr_mask = REG_RD(timer, regi_timer, rw_intr_mask); | 339 | intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); |
458 | intr_mask.trig = 0; | 340 | intr_mask.trig = 0; |
459 | REG_WR(timer, regi_timer, rw_intr_mask, intr_mask); | 341 | REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); |
460 | 342 | ||
461 | /* First stop timer, then ack interrupt */ | 343 | /* First stop timer, then ack interrupt */ |
462 | /* Stop timer */ | 344 | /* Stop timer */ |
463 | trig_cfg.tmr = regk_timer_off; | 345 | trig_cfg.tmr = regk_timer_off; |
464 | REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg); | 346 | REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); |
465 | 347 | ||
466 | /* Ack interrupt */ | 348 | /* Ack interrupt */ |
467 | ack_intr.trig = 1; | 349 | ack_intr.trig = 1; |
468 | REG_WR(timer, regi_timer, rw_ack_intr, ack_intr); | 350 | REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); |
469 | 351 | ||
470 | fast_timer_running = 0; | 352 | fast_timer_running = 0; |
471 | fast_timer_ints++; | 353 | fast_timer_ints++; |
472 | 354 | ||
473 | local_irq_restore(flags); | 355 | fast_timer_function_type *f; |
356 | unsigned long d; | ||
474 | 357 | ||
475 | t = fast_timer_list; | 358 | t = fast_timer_list; |
476 | while (t) | 359 | while (t) { |
477 | { | 360 | struct fasttime_t tv; |
478 | struct timeval tv; | ||
479 | 361 | ||
480 | /* Has it really expired? */ | 362 | /* Has it really expired? */ |
481 | do_gettimeofday_fast(&tv); | 363 | do_gettimeofday_fast(&tv); |
482 | D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); | 364 | D1(printk(KERN_DEBUG |
365 | "t: %is %06ius\n", tv.tv_jiff, tv.tv_usec)); | ||
483 | 366 | ||
484 | if (timeval_cmp(&t->tv_expires, &tv) <= 0) | 367 | if (fasttime_cmp(&t->tv_expires, &tv) <= 0) { |
485 | { | ||
486 | /* Yes it has expired */ | 368 | /* Yes it has expired */ |
487 | #ifdef FAST_TIMER_LOG | 369 | #ifdef FAST_TIMER_LOG |
488 | timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; | 370 | timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; |
@@ -490,84 +372,77 @@ static void timer_trig_handler(void) | |||
490 | fast_timers_expired++; | 372 | fast_timers_expired++; |
491 | 373 | ||
492 | /* Remove this timer before call, since it may reuse the timer */ | 374 | /* Remove this timer before call, since it may reuse the timer */ |
493 | local_irq_save(flags); | ||
494 | if (t->prev) | 375 | if (t->prev) |
495 | { | ||
496 | t->prev->next = t->next; | 376 | t->prev->next = t->next; |
497 | } | ||
498 | else | 377 | else |
499 | { | ||
500 | fast_timer_list = t->next; | 378 | fast_timer_list = t->next; |
501 | } | ||
502 | if (t->next) | 379 | if (t->next) |
503 | { | ||
504 | t->next->prev = t->prev; | 380 | t->next->prev = t->prev; |
505 | } | ||
506 | t->prev = NULL; | 381 | t->prev = NULL; |
507 | t->next = NULL; | 382 | t->next = NULL; |
508 | local_irq_restore(flags); | ||
509 | 383 | ||
510 | if (t->function != NULL) | 384 | /* Save function callback data before enabling |
511 | { | 385 | * interrupts, since the timer may be removed and we |
512 | t->function(t->data); | 386 | * don't know how it was allocated (e.g. ->function |
513 | } | 387 | * and ->data may become overwritten after deletion |
514 | else | 388 | * if the timer was stack-allocated). |
515 | { | 389 | */ |
390 | f = t->function; | ||
391 | d = t->data; | ||
392 | |||
393 | if (f != NULL) { | ||
394 | /* Run the callback function with interrupts | ||
395 | * enabled. */ | ||
396 | local_irq_restore(flags); | ||
397 | f(d); | ||
398 | local_irq_save(flags); | ||
399 | } else | ||
516 | DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints); | 400 | DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints); |
517 | } | 401 | } else { |
518 | } | ||
519 | else | ||
520 | { | ||
521 | /* Timer is to early, let's set it again using the normal routines */ | 402 | /* Timer is to early, let's set it again using the normal routines */ |
522 | D1(printk(".\n")); | 403 | D1(printk(".\n")); |
523 | } | 404 | } |
524 | 405 | ||
525 | local_irq_save(flags); | 406 | t = fast_timer_list; |
526 | if ((t = fast_timer_list) != NULL) | 407 | if (t != NULL) { |
527 | { | ||
528 | /* Start next timer.. */ | 408 | /* Start next timer.. */ |
529 | long us; | 409 | long us = 0; |
530 | struct timeval tv; | 410 | struct fasttime_t tv; |
531 | 411 | ||
532 | do_gettimeofday_fast(&tv); | 412 | do_gettimeofday_fast(&tv); |
533 | us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + | 413 | |
534 | t->tv_expires.tv_usec - tv.tv_usec); | 414 | /* time_after_eq takes care of wrapping */ |
535 | if (us > 0) | 415 | if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff)) |
536 | { | 416 | us = ((t->tv_expires.tv_jiff - tv.tv_jiff) * |
537 | if (!fast_timer_running) | 417 | 1000000 / HZ + t->tv_expires.tv_usec - |
538 | { | 418 | tv.tv_usec); |
419 | |||
420 | if (us > 0) { | ||
421 | if (!fast_timer_running) { | ||
539 | #ifdef FAST_TIMER_LOG | 422 | #ifdef FAST_TIMER_LOG |
540 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | 423 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; |
541 | #endif | 424 | #endif |
542 | start_timer_trig(us); | 425 | start_timer_trig(us); |
543 | } | 426 | } |
544 | local_irq_restore(flags); | ||
545 | break; | 427 | break; |
546 | } | 428 | } else { |
547 | else | ||
548 | { | ||
549 | /* Timer already expired, let's handle it better late than never. | 429 | /* Timer already expired, let's handle it better late than never. |
550 | * The normal loop handles it | 430 | * The normal loop handles it |
551 | */ | 431 | */ |
552 | D1(printk("e! %d\n", us)); | 432 | D1(printk("e! %d\n", us)); |
553 | } | 433 | } |
554 | } | 434 | } |
555 | local_irq_restore(flags); | ||
556 | } | 435 | } |
557 | 436 | ||
558 | if (!t) | 437 | local_irq_restore(flags); |
559 | { | 438 | |
439 | if (!t) | ||
560 | D1(printk("ttrig stop!\n")); | 440 | D1(printk("ttrig stop!\n")); |
561 | } | ||
562 | } | 441 | } |
563 | 442 | ||
564 | static void wake_up_func(unsigned long data) | 443 | static void wake_up_func(unsigned long data) |
565 | { | 444 | { |
566 | #ifdef DECLARE_WAITQUEUE | ||
567 | wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; | 445 | wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; |
568 | #else | ||
569 | struct wait_queue **sleep_wait_p = (struct wait_queue **)data; | ||
570 | #endif | ||
571 | wake_up(sleep_wait_p); | 446 | wake_up(sleep_wait_p); |
572 | } | 447 | } |
573 | 448 | ||
@@ -577,28 +452,17 @@ static void wake_up_func(unsigned long data) | |||
577 | void schedule_usleep(unsigned long us) | 452 | void schedule_usleep(unsigned long us) |
578 | { | 453 | { |
579 | struct fast_timer t; | 454 | struct fast_timer t; |
580 | #ifdef DECLARE_WAITQUEUE | ||
581 | wait_queue_head_t sleep_wait; | 455 | wait_queue_head_t sleep_wait; |
582 | init_waitqueue_head(&sleep_wait); | 456 | init_waitqueue_head(&sleep_wait); |
583 | { | ||
584 | DECLARE_WAITQUEUE(wait, current); | ||
585 | #else | ||
586 | struct wait_queue *sleep_wait = NULL; | ||
587 | struct wait_queue wait = { current, NULL }; | ||
588 | #endif | ||
589 | 457 | ||
590 | D1(printk("schedule_usleep(%d)\n", us)); | 458 | D1(printk("schedule_usleep(%d)\n", us)); |
591 | add_wait_queue(&sleep_wait, &wait); | ||
592 | set_current_state(TASK_INTERRUPTIBLE); | ||
593 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, | 459 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, |
594 | "usleep"); | 460 | "usleep"); |
595 | schedule(); | 461 | /* Uninterruptible sleep on the fast timer. (The condition is |
596 | set_current_state(TASK_RUNNING); | 462 | * somewhat redundant since the timer is what wakes us up.) */ |
597 | remove_wait_queue(&sleep_wait, &wait); | 463 | wait_event(sleep_wait, !fast_timer_pending(&t)); |
464 | |||
598 | D1(printk("done schedule_usleep(%d)\n", us)); | 465 | D1(printk("done schedule_usleep(%d)\n", us)); |
599 | #ifdef DECLARE_WAITQUEUE | ||
600 | } | ||
601 | #endif | ||
602 | } | 466 | } |
603 | 467 | ||
604 | #ifdef CONFIG_PROC_FS | 468 | #ifdef CONFIG_PROC_FS |
@@ -618,20 +482,22 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
618 | unsigned long flags; | 482 | unsigned long flags; |
619 | int i = 0; | 483 | int i = 0; |
620 | int num_to_show; | 484 | int num_to_show; |
621 | struct timeval tv; | 485 | struct fasttime_t tv; |
622 | struct fast_timer *t, *nextt; | 486 | struct fast_timer *t, *nextt; |
623 | static char *bigbuf = NULL; | 487 | static char *bigbuf = NULL; |
624 | static unsigned long used; | 488 | static unsigned long used; |
625 | 489 | ||
626 | if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) | 490 | if (!bigbuf) { |
627 | { | 491 | bigbuf = vmalloc(BIG_BUF_SIZE); |
628 | used = 0; | 492 | if (!bigbuf) { |
629 | bigbuf[0] = '\0'; | 493 | used = 0; |
630 | return 0; | 494 | if (buf) |
631 | } | 495 | buf[0] = '\0'; |
632 | 496 | return 0; | |
633 | if (!offset || !used) | 497 | } |
634 | { | 498 | } |
499 | |||
500 | if (!offset || !used) { | ||
635 | do_gettimeofday_fast(&tv); | 501 | do_gettimeofday_fast(&tv); |
636 | 502 | ||
637 | used = 0; | 503 | used = 0; |
@@ -648,7 +514,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
648 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", | 514 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", |
649 | fast_timer_running ? "yes" : "no"); | 515 | fast_timer_running ? "yes" : "no"); |
650 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", | 516 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", |
651 | (unsigned long)tv.tv_sec, | 517 | (unsigned long)tv.tv_jiff, |
652 | (unsigned long)tv.tv_usec); | 518 | (unsigned long)tv.tv_usec); |
653 | #ifdef FAST_TIMER_SANITY_CHECKS | 519 | #ifdef FAST_TIMER_SANITY_CHECKS |
654 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", | 520 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", |
@@ -661,10 +527,8 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
661 | int end_i = debug_log_cnt; | 527 | int end_i = debug_log_cnt; |
662 | i = 0; | 528 | i = 0; |
663 | 529 | ||
664 | if (debug_log_cnt_wrapped) | 530 | if (debug_log_cnt_wrapped) |
665 | { | ||
666 | i = debug_log_cnt; | 531 | i = debug_log_cnt; |
667 | } | ||
668 | 532 | ||
669 | while ((i != end_i || (debug_log_cnt_wrapped && !used)) && | 533 | while ((i != end_i || (debug_log_cnt_wrapped && !used)) && |
670 | used+100 < BIG_BUF_SIZE) | 534 | used+100 < BIG_BUF_SIZE) |
@@ -697,9 +561,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
697 | "d: %6li us data: 0x%08lX" | 561 | "d: %6li us data: 0x%08lX" |
698 | "\n", | 562 | "\n", |
699 | t->name, | 563 | t->name, |
700 | (unsigned long)t->tv_set.tv_sec, | 564 | (unsigned long)t->tv_set.tv_jiff, |
701 | (unsigned long)t->tv_set.tv_usec, | 565 | (unsigned long)t->tv_set.tv_usec, |
702 | (unsigned long)t->tv_expires.tv_sec, | 566 | (unsigned long)t->tv_expires.tv_jiff, |
703 | (unsigned long)t->tv_expires.tv_usec, | 567 | (unsigned long)t->tv_expires.tv_usec, |
704 | t->delay_us, | 568 | t->delay_us, |
705 | t->data | 569 | t->data |
@@ -719,9 +583,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
719 | "d: %6li us data: 0x%08lX" | 583 | "d: %6li us data: 0x%08lX" |
720 | "\n", | 584 | "\n", |
721 | t->name, | 585 | t->name, |
722 | (unsigned long)t->tv_set.tv_sec, | 586 | (unsigned long)t->tv_set.tv_jiff, |
723 | (unsigned long)t->tv_set.tv_usec, | 587 | (unsigned long)t->tv_set.tv_usec, |
724 | (unsigned long)t->tv_expires.tv_sec, | 588 | (unsigned long)t->tv_expires.tv_jiff, |
725 | (unsigned long)t->tv_expires.tv_usec, | 589 | (unsigned long)t->tv_expires.tv_usec, |
726 | t->delay_us, | 590 | t->delay_us, |
727 | t->data | 591 | t->data |
@@ -739,9 +603,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
739 | "d: %6li us data: 0x%08lX" | 603 | "d: %6li us data: 0x%08lX" |
740 | "\n", | 604 | "\n", |
741 | t->name, | 605 | t->name, |
742 | (unsigned long)t->tv_set.tv_sec, | 606 | (unsigned long)t->tv_set.tv_jiff, |
743 | (unsigned long)t->tv_set.tv_usec, | 607 | (unsigned long)t->tv_set.tv_usec, |
744 | (unsigned long)t->tv_expires.tv_sec, | 608 | (unsigned long)t->tv_expires.tv_jiff, |
745 | (unsigned long)t->tv_expires.tv_usec, | 609 | (unsigned long)t->tv_expires.tv_usec, |
746 | t->delay_us, | 610 | t->delay_us, |
747 | t->data | 611 | t->data |
@@ -752,26 +616,25 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | |||
752 | 616 | ||
753 | used += sprintf(bigbuf + used, "Active timers:\n"); | 617 | used += sprintf(bigbuf + used, "Active timers:\n"); |
754 | local_irq_save(flags); | 618 | local_irq_save(flags); |
755 | local_irq_save(flags); | ||
756 | t = fast_timer_list; | 619 | t = fast_timer_list; |
757 | while (t != NULL && (used+100 < BIG_BUF_SIZE)) | 620 | while (t != NULL && (used+100 < BIG_BUF_SIZE)) |
758 | { | 621 | { |
759 | nextt = t->next; | 622 | nextt = t->next; |
760 | local_irq_restore(flags); | 623 | local_irq_restore(flags); |
761 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | 624 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " |
762 | "d: %6li us data: 0x%08lX" | 625 | "d: %6li us data: 0x%08lX" |
763 | /* " func: 0x%08lX" */ | 626 | /* " func: 0x%08lX" */ |
764 | "\n", | 627 | "\n", |
765 | t->name, | 628 | t->name, |
766 | (unsigned long)t->tv_set.tv_sec, | 629 | (unsigned long)t->tv_set.tv_jiff, |
767 | (unsigned long)t->tv_set.tv_usec, | 630 | (unsigned long)t->tv_set.tv_usec, |
768 | (unsigned long)t->tv_expires.tv_sec, | 631 | (unsigned long)t->tv_expires.tv_jiff, |
769 | (unsigned long)t->tv_expires.tv_usec, | 632 | (unsigned long)t->tv_expires.tv_usec, |
770 | t->delay_us, | 633 | t->delay_us, |
771 | t->data | 634 | t->data |
772 | /* , t->function */ | 635 | /* , t->function */ |
773 | ); | 636 | ); |
774 | local_irq_disable(); | 637 | local_irq_save(flags); |
775 | if (t->next != nextt) | 638 | if (t->next != nextt) |
776 | { | 639 | { |
777 | printk("timer removed!\n"); | 640 | printk("timer removed!\n"); |
@@ -800,7 +663,7 @@ static volatile int num_test_timeout = 0; | |||
800 | static struct fast_timer tr[10]; | 663 | static struct fast_timer tr[10]; |
801 | static int exp_num[10]; | 664 | static int exp_num[10]; |
802 | 665 | ||
803 | static struct timeval tv_exp[100]; | 666 | static struct fasttime_t tv_exp[100]; |
804 | 667 | ||
805 | static void test_timeout(unsigned long data) | 668 | static void test_timeout(unsigned long data) |
806 | { | 669 | { |
@@ -838,7 +701,7 @@ static void fast_timer_test(void) | |||
838 | int prev_num; | 701 | int prev_num; |
839 | int j; | 702 | int j; |
840 | 703 | ||
841 | struct timeval tv, tv0, tv1, tv2; | 704 | struct fasttime_t tv, tv0, tv1, tv2; |
842 | 705 | ||
843 | printk("fast_timer_test() start\n"); | 706 | printk("fast_timer_test() start\n"); |
844 | do_gettimeofday_fast(&tv); | 707 | do_gettimeofday_fast(&tv); |
@@ -851,21 +714,22 @@ static void fast_timer_test(void) | |||
851 | { | 714 | { |
852 | do_gettimeofday_fast(&tv_exp[j]); | 715 | do_gettimeofday_fast(&tv_exp[j]); |
853 | } | 716 | } |
854 | printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); | 717 | printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec); |
855 | 718 | ||
856 | for (j = 0; j < 1000; j++) | 719 | for (j = 0; j < 1000; j++) |
857 | { | 720 | { |
858 | printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); | 721 | printk(KERN_DEBUG "%i %i %i %i %i\n", |
722 | j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); | ||
859 | j += 4; | 723 | j += 4; |
860 | } | 724 | } |
861 | for (j = 0; j < 100; j++) | 725 | for (j = 0; j < 100; j++) |
862 | { | 726 | { |
863 | printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", | 727 | printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n", |
864 | tv_exp[j].tv_sec,tv_exp[j].tv_usec, | 728 | tv_exp[j].tv_jiff, tv_exp[j].tv_usec, |
865 | tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, | 729 | tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec, |
866 | tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, | 730 | tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec, |
867 | tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, | 731 | tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec, |
868 | tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); | 732 | tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec); |
869 | j += 4; | 733 | j += 4; |
870 | } | 734 | } |
871 | do_gettimeofday_fast(&tv0); | 735 | do_gettimeofday_fast(&tv0); |
@@ -892,14 +756,15 @@ static void fast_timer_test(void) | |||
892 | while (num_test_timeout < i) | 756 | while (num_test_timeout < i) |
893 | { | 757 | { |
894 | if (num_test_timeout != prev_num) | 758 | if (num_test_timeout != prev_num) |
895 | { | ||
896 | prev_num = num_test_timeout; | 759 | prev_num = num_test_timeout; |
897 | } | ||
898 | } | 760 | } |
899 | do_gettimeofday_fast(&tv2); | 761 | do_gettimeofday_fast(&tv2); |
900 | printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); | 762 | printk(KERN_INFO "Timers started %is %06i\n", |
901 | printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); | 763 | tv0.tv_jiff, tv0.tv_usec); |
902 | printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); | 764 | printk(KERN_INFO "Timers started at %is %06i\n", |
765 | tv1.tv_jiff, tv1.tv_usec); | ||
766 | printk(KERN_INFO "Timers done %is %06i\n", | ||
767 | tv2.tv_jiff, tv2.tv_usec); | ||
903 | DP(printk("buf0:\n"); | 768 | DP(printk("buf0:\n"); |
904 | printk(buf0); | 769 | printk(buf0); |
905 | printk("buf1:\n"); | 770 | printk("buf1:\n"); |
@@ -921,9 +786,9 @@ static void fast_timer_test(void) | |||
921 | printk("%-10s set: %6is %06ius exp: %6is %06ius " | 786 | printk("%-10s set: %6is %06ius exp: %6is %06ius " |
922 | "data: 0x%08X func: 0x%08X\n", | 787 | "data: 0x%08X func: 0x%08X\n", |
923 | t->name, | 788 | t->name, |
924 | t->tv_set.tv_sec, | 789 | t->tv_set.tv_jiff, |
925 | t->tv_set.tv_usec, | 790 | t->tv_set.tv_usec, |
926 | t->tv_expires.tv_sec, | 791 | t->tv_expires.tv_jiff, |
927 | t->tv_expires.tv_usec, | 792 | t->tv_expires.tv_usec, |
928 | t->data, | 793 | t->data, |
929 | t->function | 794 | t->function |
@@ -931,10 +796,12 @@ static void fast_timer_test(void) | |||
931 | 796 | ||
932 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", | 797 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", |
933 | t->delay_us, | 798 | t->delay_us, |
934 | tv_exp[j].tv_sec, | 799 | tv_exp[j].tv_jiff, |
935 | tv_exp[j].tv_usec, | 800 | tv_exp[j].tv_usec, |
936 | exp_num[j], | 801 | exp_num[j], |
937 | (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); | 802 | (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) * |
803 | 1000000 + tv_exp[j].tv_usec - | ||
804 | t->tv_expires.tv_usec); | ||
938 | } | 805 | } |
939 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | 806 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); |
940 | printk("buf5 after all done:\n"); | 807 | printk("buf5 after all done:\n"); |
@@ -944,7 +811,7 @@ static void fast_timer_test(void) | |||
944 | #endif | 811 | #endif |
945 | 812 | ||
946 | 813 | ||
947 | void fast_timer_init(void) | 814 | int fast_timer_init(void) |
948 | { | 815 | { |
949 | /* For some reason, request_irq() hangs when called froom time_init() */ | 816 | /* For some reason, request_irq() hangs when called froom time_init() */ |
950 | if (!fast_timer_is_init) | 817 | if (!fast_timer_is_init) |
@@ -952,18 +819,20 @@ void fast_timer_init(void) | |||
952 | printk("fast_timer_init()\n"); | 819 | printk("fast_timer_init()\n"); |
953 | 820 | ||
954 | #ifdef CONFIG_PROC_FS | 821 | #ifdef CONFIG_PROC_FS |
955 | if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) | 822 | fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0); |
956 | fasttimer_proc_entry->read_proc = proc_fasttimer_read; | 823 | if (fasttimer_proc_entry) |
824 | fasttimer_proc_entry->read_proc = proc_fasttimer_read; | ||
957 | #endif /* PROC_FS */ | 825 | #endif /* PROC_FS */ |
958 | if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED, | 826 | if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt, |
959 | "fast timer int", NULL)) | 827 | IRQF_SHARED | IRQF_DISABLED, |
960 | { | 828 | "fast timer int", &fast_timer_list)) |
961 | printk("err: timer1 irq\n"); | 829 | printk(KERN_ERR "err: fasttimer irq\n"); |
962 | } | ||
963 | fast_timer_is_init = 1; | 830 | fast_timer_is_init = 1; |
964 | #ifdef FAST_TIMER_TEST | 831 | #ifdef FAST_TIMER_TEST |
965 | printk("do test\n"); | 832 | printk("do test\n"); |
966 | fast_timer_test(); | 833 | fast_timer_test(); |
967 | #endif | 834 | #endif |
968 | } | 835 | } |
836 | return 0; | ||
969 | } | 837 | } |
838 | __initcall(fast_timer_init); | ||
diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S index 20bd80a84e48..2d66a7c320e1 100644 --- a/arch/cris/arch-v32/kernel/head.S +++ b/arch/cris/arch-v32/kernel/head.S | |||
@@ -4,22 +4,25 @@ | |||
4 | * Copyright (C) 2003, Axis Communications AB | 4 | * Copyright (C) 2003, Axis Communications AB |
5 | */ | 5 | */ |
6 | 6 | ||
7 | |||
8 | #define ASSEMBLER_MACROS_ONLY | 7 | #define ASSEMBLER_MACROS_ONLY |
9 | 8 | ||
10 | /* | 9 | /* |
11 | * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so | 10 | * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so |
12 | * -traditional must not be used when assembling this file. | 11 | * -traditional must not be used when assembling this file. |
13 | */ | 12 | */ |
14 | #include <asm/arch/hwregs/reg_rdwr.h> | 13 | #include <hwregs/reg_rdwr.h> |
15 | #include <asm/arch/hwregs/asm/mmu_defs_asm.h> | 14 | #include <asm/arch/memmap.h> |
16 | #include <asm/arch/hwregs/asm/reg_map_asm.h> | 15 | #include <hwregs/intr_vect.h> |
17 | #include <asm/arch/hwregs/asm/config_defs_asm.h> | 16 | #include <hwregs/asm/mmu_defs_asm.h> |
18 | #include <asm/arch/hwregs/asm/bif_core_defs_asm.h> | 17 | #include <hwregs/asm/reg_map_asm.h> |
18 | #include <asm/arch/mach/startup.inc> | ||
19 | 19 | ||
20 | #define CRAMFS_MAGIC 0x28cd3d45 | 20 | #define CRAMFS_MAGIC 0x28cd3d45 |
21 | #define JHEAD_MAGIC 0x1FF528A6 | ||
22 | #define JHEAD_SIZE 8 | ||
21 | #define RAM_INIT_MAGIC 0x56902387 | 23 | #define RAM_INIT_MAGIC 0x56902387 |
22 | #define COMMAND_LINE_MAGIC 0x87109563 | 24 | #define COMMAND_LINE_MAGIC 0x87109563 |
25 | #define NAND_BOOT_MAGIC 0x9a9db001 | ||
23 | 26 | ||
24 | ;; NOTE: R8 and R9 carry information from the decompressor (if the | 27 | ;; NOTE: R8 and R9 carry information from the decompressor (if the |
25 | ;; kernel was compressed). They must not be used in the code below | 28 | ;; kernel was compressed). They must not be used in the code below |
@@ -30,12 +33,11 @@ | |||
30 | .global romfs_start | 33 | .global romfs_start |
31 | .global romfs_length | 34 | .global romfs_length |
32 | .global romfs_in_flash | 35 | .global romfs_in_flash |
36 | .global nand_boot | ||
33 | .global swapper_pg_dir | 37 | .global swapper_pg_dir |
34 | .global crisv32_nand_boot | ||
35 | .global crisv32_nand_cramfs_offset | ||
36 | 38 | ||
37 | ;; Dummy section to make it bootable with current VCS simulator | 39 | ;; Dummy section to make it bootable with current VCS simulator |
38 | #ifdef CONFIG_ETRAXFS_SIM | 40 | #ifdef CONFIG_ETRAX_VCS_SIM |
39 | .section ".boot", "ax" | 41 | .section ".boot", "ax" |
40 | ba tstart | 42 | ba tstart |
41 | nop | 43 | nop |
@@ -51,33 +53,15 @@ tstart: | |||
51 | ;; | 53 | ;; |
52 | di | 54 | di |
53 | 55 | ||
54 | ;; Start clocks for used blocks. | 56 | START_CLOCKS |
55 | move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1 | 57 | |
56 | move.d [$r1], $r0 | 58 | SETUP_WAIT_STATES |
57 | or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \ | 59 | |
58 | REG_STATE(config, rw_clk_ctrl, bif, yes) | \ | 60 | GIO_INIT |
59 | REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0 | 61 | |
60 | move.d $r0, [$r1] | 62 | #ifdef CONFIG_SMP |
61 | 63 | secondary_cpu_entry: /* Entry point for secondary CPUs */ | |
62 | ;; Set up waitstates etc | 64 | di |
63 | move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0 | ||
64 | move.d CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1 | ||
65 | move.d $r1, [$r0] | ||
66 | move.d REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0 | ||
67 | move.d CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1 | ||
68 | move.d $r1, [$r0] | ||
69 | move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0 | ||
70 | move.d CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1 | ||
71 | move.d $r1, [$r0] | ||
72 | move.d REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0 | ||
73 | move.d CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1 | ||
74 | move.d $r1, [$r0] | ||
75 | |||
76 | #ifdef CONFIG_ETRAXFS_SIM | ||
77 | ;; Set up minimal flash waitstates | ||
78 | move.d 0, $r10 | ||
79 | move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11 | ||
80 | move.d $r10, [$r11] | ||
81 | #endif | 65 | #endif |
82 | 66 | ||
83 | ;; Setup and enable the MMU. Use same configuration for both the data | 67 | ;; Setup and enable the MMU. Use same configuration for both the data |
@@ -85,7 +69,7 @@ tstart: | |||
85 | ;; | 69 | ;; |
86 | ;; Note; 3 cycles is needed for a bank-select to take effect. Further; | 70 | ;; Note; 3 cycles is needed for a bank-select to take effect. Further; |
87 | ;; bank 1 is the instruction MMU, bank 2 is the data MMU. | 71 | ;; bank 1 is the instruction MMU, bank 2 is the data MMU. |
88 | #ifndef CONFIG_ETRAXFS_SIM | 72 | #ifndef CONFIG_ETRAX_VCS_SIM |
89 | move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ | 73 | move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ |
90 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ | 74 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ |
91 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 | 75 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 |
@@ -93,7 +77,7 @@ tstart: | |||
93 | ;; Map the virtual DRAM to the RW eprom area at address 0. | 77 | ;; Map the virtual DRAM to the RW eprom area at address 0. |
94 | ;; Also map 0xa for the hook calls, | 78 | ;; Also map 0xa for the hook calls, |
95 | move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ | 79 | move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ |
96 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0) \ | 80 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ |
97 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \ | 81 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \ |
98 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0 | 82 | | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0 |
99 | #endif | 83 | #endif |
@@ -104,7 +88,7 @@ tstart: | |||
104 | 88 | ||
105 | ;; Enable certain page protections and setup linear mapping | 89 | ;; Enable certain page protections and setup linear mapping |
106 | ;; for f,e,c,b,4,0. | 90 | ;; for f,e,c,b,4,0. |
107 | #ifndef CONFIG_ETRAXFS_SIM | 91 | #ifndef CONFIG_ETRAX_VCS_SIM |
108 | move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ | 92 | move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ |
109 | | REG_STATE(mmu, rw_mm_cfg, acc, on) \ | 93 | | REG_STATE(mmu, rw_mm_cfg, acc, on) \ |
110 | | REG_STATE(mmu, rw_mm_cfg, ex, on) \ | 94 | | REG_STATE(mmu, rw_mm_cfg, ex, on) \ |
@@ -183,17 +167,11 @@ tstart: | |||
183 | nop | 167 | nop |
184 | nop | 168 | nop |
185 | nop | 169 | nop |
186 | move $s10, $r0 | 170 | move $s12, $r0 |
187 | cmpq 0, $r0 | 171 | cmpq 0, $r0 |
188 | beq master_cpu | 172 | beq master_cpu |
189 | nop | 173 | nop |
190 | slave_cpu: | 174 | slave_cpu: |
191 | ; A slave waits for cpu_now_booting to be equal to CPU ID. | ||
192 | move.d cpu_now_booting, $r1 | ||
193 | slave_wait: | ||
194 | cmp.d [$r1], $r0 | ||
195 | bne slave_wait | ||
196 | nop | ||
197 | ; Time to boot-up. Get stack location provided by master CPU. | 175 | ; Time to boot-up. Get stack location provided by master CPU. |
198 | move.d smp_init_current_idle_thread, $r1 | 176 | move.d smp_init_current_idle_thread, $r1 |
199 | move.d [$r1], $sp | 177 | move.d [$r1], $sp |
@@ -203,9 +181,16 @@ slave_wait: | |||
203 | jsr smp_callin | 181 | jsr smp_callin |
204 | nop | 182 | nop |
205 | master_cpu: | 183 | master_cpu: |
184 | /* Set up entry point for secondary CPUs. The boot ROM has set up | ||
185 | * EBP at start of internal memory. The CPU will get there | ||
186 | * later when we issue an IPI to them... */ | ||
187 | move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0 | ||
188 | move.d secondary_cpu_entry, $r1 | ||
189 | move.d $r1, [$r0] | ||
206 | #endif | 190 | #endif |
207 | #ifndef CONFIG_ETRAXFS_SIM | 191 | #ifndef CONFIG_ETRAX_VCS_SIM |
208 | ;; Check if starting from DRAM or flash. | 192 | ; Check if starting from DRAM (network->RAM boot or unpacked |
193 | ; compressed kernel), or directly from flash. | ||
209 | lapcq ., $r0 | 194 | lapcq ., $r0 |
210 | and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. | 195 | and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. |
211 | cmp.d 0x10000, $r0 ; Arbitrary, something above this code. | 196 | cmp.d 0x10000, $r0 ; Arbitrary, something above this code. |
@@ -232,12 +217,13 @@ _inflash: | |||
232 | beq _dram_initialized | 217 | beq _dram_initialized |
233 | nop | 218 | nop |
234 | 219 | ||
235 | #include "../lib/dram_init.S" | 220 | #include "../mach/dram_init.S" |
236 | 221 | ||
237 | _dram_initialized: | 222 | _dram_initialized: |
238 | ;; Copy the text and data section to DRAM. This depends on that the | 223 | ;; Copy the text and data section to DRAM. This depends on that the |
239 | ;; variables used below are correctly set up by the linker script. | 224 | ;; variables used below are correctly set up by the linker script. |
240 | ;; The calculated value stored in R4 is used below. | 225 | ;; The calculated value stored in R4 is used below. |
226 | ;; Leave the cramfs file system (piggybacked after the kernel) in flash. | ||
241 | moveq 0, $r0 ; Source. | 227 | moveq 0, $r0 ; Source. |
242 | move.d text_start, $r1 ; Destination. | 228 | move.d text_start, $r1 ; Destination. |
243 | move.d __vmlinux_end, $r2 | 229 | move.d __vmlinux_end, $r2 |
@@ -249,7 +235,7 @@ _dram_initialized: | |||
249 | blo 1b | 235 | blo 1b |
250 | nop | 236 | nop |
251 | 237 | ||
252 | ;; Keep CRAMFS in flash. | 238 | ;; Check for cramfs. |
253 | moveq 0, $r0 | 239 | moveq 0, $r0 |
254 | move.d romfs_length, $r1 | 240 | move.d romfs_length, $r1 |
255 | move.d $r0, [$r1] | 241 | move.d $r0, [$r1] |
@@ -258,6 +244,7 @@ _dram_initialized: | |||
258 | bne 1f | 244 | bne 1f |
259 | nop | 245 | nop |
260 | 246 | ||
247 | ;; Set length and start of cramfs, set romfs_in_flash flag | ||
261 | addoq +4, $r4, $acr | 248 | addoq +4, $r4, $acr |
262 | move.d [$acr], $r0 | 249 | move.d [$acr], $r0 |
263 | move.d romfs_length, $r1 | 250 | move.d romfs_length, $r1 |
@@ -273,35 +260,32 @@ _dram_initialized: | |||
273 | nop | 260 | nop |
274 | 261 | ||
275 | _inram: | 262 | _inram: |
276 | ;; Check if booting from NAND flash (in that case we just remember the offset | 263 | ;; Check if booting from NAND flash; if so, set appropriate flags |
277 | ;; into the flash where cramfs should be). | 264 | ;; and move on. |
278 | move.d REG_ADDR(config, regi_config, r_bootsel), $r0 | 265 | cmp.d NAND_BOOT_MAGIC, $r12 |
279 | move.d [$r0], $r0 | 266 | bne move_cramfs ; not nand, jump |
280 | and.d REG_MASK(config, r_bootsel, boot_mode), $r0 | ||
281 | cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0 | ||
282 | bne move_cramfs | ||
283 | moveq 1,$r0 | ||
284 | move.d crisv32_nand_boot, $r1 | ||
285 | move.d $r0, [$r1] | ||
286 | move.d crisv32_nand_cramfs_offset, $r1 | ||
287 | move.d $r9, [$r1] | ||
288 | moveq 1, $r0 | 267 | moveq 1, $r0 |
289 | move.d romfs_in_flash, $r1 | 268 | move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND |
269 | move.d $r0, [$r1] | ||
270 | moveq 0, $r0 ; tell axisflashmap romfs is not in | ||
271 | move.d romfs_in_flash, $r1 ; (directly accessed) flash | ||
290 | move.d $r0, [$r1] | 272 | move.d $r0, [$r1] |
291 | jump _start_it | 273 | jump _start_it ; continue with boot |
292 | nop | 274 | nop |
293 | 275 | ||
294 | move_cramfs: | 276 | move_cramfs: |
295 | ;; Move the cramfs after BSS. | 277 | ;; kernel is in DRAM. |
278 | ;; Must figure out if there is a piggybacked rootfs image or not. | ||
279 | ;; Set romfs_length to 0 => no rootfs image available by default. | ||
296 | moveq 0, $r0 | 280 | moveq 0, $r0 |
297 | move.d romfs_length, $r1 | 281 | move.d romfs_length, $r1 |
298 | move.d $r0, [$r1] | 282 | move.d $r0, [$r1] |
299 | 283 | ||
300 | #ifndef CONFIG_ETRAXFS_SIM | 284 | #ifndef CONFIG_ETRAX_VCS_SIM |
301 | ;; The kernel could have been unpacked to DRAM by the loader, but | 285 | ;; The kernel could have been unpacked to DRAM by the loader, but |
302 | ;; the cramfs image could still be inte the flash immediately | 286 | ;; the cramfs image could still be in the flash immediately |
303 | ;; following the compressed kernel image. The loaded passes the address | 287 | ;; following the compressed kernel image. The loader passes the address |
304 | ;; of the bute succeeding the last compressed byte in the flash in | 288 | ;; of the byte succeeding the last compressed byte in the flash in |
305 | ;; register R9 when starting the kernel. | 289 | ;; register R9 when starting the kernel. |
306 | cmp.d 0x0ffffff8, $r9 | 290 | cmp.d 0x0ffffff8, $r9 |
307 | bhs _no_romfs_in_flash ; R9 points outside the flash area. | 291 | bhs _no_romfs_in_flash ; R9 points outside the flash area. |
@@ -310,11 +294,13 @@ move_cramfs: | |||
310 | ba _no_romfs_in_flash | 294 | ba _no_romfs_in_flash |
311 | nop | 295 | nop |
312 | #endif | 296 | #endif |
297 | ;; cramfs rootfs might to be in flash. Check for it. | ||
313 | move.d [$r9], $r0 ; cramfs_super.magic | 298 | move.d [$r9], $r0 ; cramfs_super.magic |
314 | cmp.d CRAMFS_MAGIC, $r0 | 299 | cmp.d CRAMFS_MAGIC, $r0 |
315 | bne _no_romfs_in_flash | 300 | bne _no_romfs_in_flash |
316 | nop | 301 | nop |
317 | 302 | ||
303 | ;; found cramfs in flash. set address and size, and romfs_in_flash flag. | ||
318 | addoq +4, $r9, $acr | 304 | addoq +4, $r9, $acr |
319 | move.d [$acr], $r0 | 305 | move.d [$acr], $r0 |
320 | move.d romfs_length, $r1 | 306 | move.d romfs_length, $r1 |
@@ -330,27 +316,43 @@ move_cramfs: | |||
330 | nop | 316 | nop |
331 | 317 | ||
332 | _no_romfs_in_flash: | 318 | _no_romfs_in_flash: |
333 | ;; Look for cramfs. | 319 | ;; No romfs in flash, so look for cramfs, or jffs2 with jhead, |
320 | ;; after kernel in RAM, as is the case with network->RAM boot. | ||
321 | ;; For cramfs, partition starts with magic and length. | ||
322 | ;; For jffs2, a jhead is prepended which contains with magic and length. | ||
323 | ;; The jhead is not part of the jffs2 partition however. | ||
334 | #ifndef CONFIG_ETRAXFS_SIM | 324 | #ifndef CONFIG_ETRAXFS_SIM |
335 | move.d __vmlinux_end, $r0 | 325 | move.d __vmlinux_end, $r0 |
336 | #else | 326 | #else |
337 | move.d __end, $r0 | 327 | move.d __end, $r0 |
338 | #endif | 328 | #endif |
339 | move.d [$r0], $r1 | 329 | move.d [$r0], $r1 |
340 | cmp.d CRAMFS_MAGIC, $r1 | 330 | cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic? |
341 | bne 2f | 331 | beq 2f ; yes, jump |
332 | nop | ||
333 | cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic? | ||
334 | bne 4f ; no, skip copy | ||
342 | nop | 335 | nop |
336 | addq 4, $r0 ; location of jffs2 size | ||
337 | move.d [$r0+], $r2 ; fetch jffs2 size -> r2 | ||
338 | ; r0 now points to start of jffs2 | ||
339 | ba 3f | ||
340 | nop | ||
341 | 2: | ||
342 | addoq +4, $r0, $acr ; location of cramfs size | ||
343 | move.d [$acr], $r2 ; fetch cramfs size -> r2 | ||
344 | ; r0 still points to start of cramfs | ||
345 | 3: | ||
346 | ;; Now, move the root fs to after kernel's BSS | ||
343 | 347 | ||
344 | addoq +4, $r0, $acr | 348 | move.d _end, $r1 ; start of cramfs -> r1 |
345 | move.d [$acr], $r2 | ||
346 | move.d _end, $r1 | ||
347 | move.d romfs_start, $r3 | 349 | move.d romfs_start, $r3 |
348 | move.d $r1, [$r3] | 350 | move.d $r1, [$r3] ; store at romfs_start (for axisflashmap) |
349 | move.d romfs_length, $r3 | 351 | move.d romfs_length, $r3 |
350 | move.d $r2, [$r3] | 352 | move.d $r2, [$r3] ; store size at romfs_length |
351 | 353 | ||
352 | #ifndef CONFIG_ETRAXFS_SIM | 354 | #ifndef CONFIG_ETRAX_VCS_SIM |
353 | add.d $r2, $r0 | 355 | add.d $r2, $r0 ; copy from end and downwards |
354 | add.d $r2, $r1 | 356 | add.d $r2, $r1 |
355 | 357 | ||
356 | lsrq 1, $r2 ; Size is in bytes, we copy words. | 358 | lsrq 1, $r2 ; Size is in bytes, we copy words. |
@@ -365,10 +367,17 @@ _no_romfs_in_flash: | |||
365 | nop | 367 | nop |
366 | #endif | 368 | #endif |
367 | 369 | ||
368 | 2: | 370 | 4: |
371 | ;; BSS move done. | ||
372 | ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM | ||
373 | ;; Also clear nand_boot flag; if we got here, we know we've not | ||
374 | ;; booted from NAND flash. | ||
369 | moveq 0, $r0 | 375 | moveq 0, $r0 |
370 | move.d romfs_in_flash, $r1 | 376 | move.d romfs_in_flash, $r1 |
371 | move.d $r0, [$r1] | 377 | move.d $r0, [$r1] |
378 | moveq 0, $r0 | ||
379 | move.d nand_boot, $r1 | ||
380 | move.d $r0, [$r1] | ||
372 | 381 | ||
373 | jump _start_it ; Jump to cached code. | 382 | jump _start_it ; Jump to cached code. |
374 | nop | 383 | nop |
@@ -384,8 +393,8 @@ _start_it: | |||
384 | move.d cris_command_line, $r10 | 393 | move.d cris_command_line, $r10 |
385 | or.d 0x80000000, $r11 ; Make it virtual | 394 | or.d 0x80000000, $r11 ; Make it virtual |
386 | 1: | 395 | 1: |
387 | move.b [$r11+], $r12 | 396 | move.b [$r11+], $r1 |
388 | move.b $r12, [$r10+] | 397 | move.b $r1, [$r10+] |
389 | subq 1, $r13 | 398 | subq 1, $r13 |
390 | bne 1b | 399 | bne 1b |
391 | nop | 400 | nop |
@@ -401,7 +410,7 @@ no_command_line: | |||
401 | move.d etrax_irv, $r1 ; Set the exception base register and pointer. | 410 | move.d etrax_irv, $r1 ; Set the exception base register and pointer. |
402 | move.d $r0, [$r1] | 411 | move.d $r0, [$r1] |
403 | 412 | ||
404 | #ifndef CONFIG_ETRAXFS_SIM | 413 | #ifndef CONFIG_ETRAX_VCS_SIM |
405 | ;; Clear the BSS region from _bss_start to _end. | 414 | ;; Clear the BSS region from _bss_start to _end. |
406 | move.d __bss_start, $r0 | 415 | move.d __bss_start, $r0 |
407 | move.d _end, $r1 | 416 | move.d _end, $r1 |
@@ -411,7 +420,7 @@ no_command_line: | |||
411 | nop | 420 | nop |
412 | #endif | 421 | #endif |
413 | 422 | ||
414 | #ifdef CONFIG_ETRAXFS_SIM | 423 | #ifdef CONFIG_ETRAX_VCS_SIM |
415 | /* Set the watchdog timeout to something big. Will be removed when */ | 424 | /* Set the watchdog timeout to something big. Will be removed when */ |
416 | /* watchdog can be disabled with command line option */ | 425 | /* watchdog can be disabled with command line option */ |
417 | move.d 0x7fffffff, $r10 | 426 | move.d 0x7fffffff, $r10 |
@@ -423,25 +432,44 @@ no_command_line: | |||
423 | move.d __bss_start, $r0 | 432 | move.d __bss_start, $r0 |
424 | movem [$r0], $r13 | 433 | movem [$r0], $r13 |
425 | 434 | ||
435 | #ifdef CONFIG_ETRAX_L2CACHE | ||
436 | jsr l2cache_init | ||
437 | nop | ||
438 | #endif | ||
439 | |||
426 | jump start_kernel ; Jump to start_kernel() in init/main.c. | 440 | jump start_kernel ; Jump to start_kernel() in init/main.c. |
427 | nop | 441 | nop |
428 | 442 | ||
429 | .data | 443 | .data |
430 | etrax_irv: | 444 | etrax_irv: |
431 | .dword 0 | 445 | .dword 0 |
446 | |||
447 | ; Variables for communication with the Axis flash map driver (axisflashmap), | ||
448 | ; and for setting up memory in arch/cris/kernel/setup.c . | ||
449 | |||
450 | ; romfs_start is set to the start of the root file system, if it exists | ||
451 | ; in directly accessible memory (i.e. NOR Flash when booting from Flash, | ||
452 | ; or RAM when booting directly from a network-downloaded RAM image) | ||
432 | romfs_start: | 453 | romfs_start: |
433 | .dword 0 | 454 | .dword 0 |
455 | |||
456 | ; romfs_length is set to the size of the root file system image, if it exists | ||
457 | ; in directly accessible memory (see romfs_start). Otherwise it is set to 0. | ||
434 | romfs_length: | 458 | romfs_length: |
435 | .dword 0 | 459 | .dword 0 |
460 | |||
461 | ; romfs_in_flash is set to 1 if the root file system resides in directly | ||
462 | ; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot | ||
463 | ; or NAND flash boot. | ||
436 | romfs_in_flash: | 464 | romfs_in_flash: |
437 | .dword 0 | 465 | .dword 0 |
438 | crisv32_nand_boot: | 466 | |
439 | .dword 0 | 467 | ; nand_boot is set to 1 when the kernel has been booted from NAND flash |
440 | crisv32_nand_cramfs_offset: | 468 | nand_boot: |
441 | .dword 0 | 469 | .dword 0 |
442 | 470 | ||
443 | swapper_pg_dir = 0xc0002000 | 471 | swapper_pg_dir = 0xc0002000 |
444 | 472 | ||
445 | .section ".init.data", "aw" | 473 | .section ".init.data", "aw" |
446 | 474 | ||
447 | #include "../lib/hw_settings.S" | 475 | #include "../mach/hw_settings.S" |
diff --git a/arch/cris/arch-v32/kernel/io.c b/arch/cris/arch-v32/kernel/io.c deleted file mode 100644 index a22a9e02e093..000000000000 --- a/arch/cris/arch-v32/kernel/io.c +++ /dev/null | |||
@@ -1,153 +0,0 @@ | |||
1 | /* | ||
2 | * Helper functions for I/O pins. | ||
3 | * | ||
4 | * Copyright (c) 2004 Axis Communications AB. | ||
5 | */ | ||
6 | |||
7 | #include <linux/types.h> | ||
8 | #include <linux/errno.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/arch/pinmux.h> | ||
16 | #include <asm/arch/hwregs/gio_defs.h> | ||
17 | |||
18 | struct crisv32_ioport crisv32_ioports[] = | ||
19 | { | ||
20 | { | ||
21 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe), | ||
22 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout), | ||
23 | (unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din), | ||
24 | 8 | ||
25 | }, | ||
26 | { | ||
27 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe), | ||
28 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout), | ||
29 | (unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din), | ||
30 | 18 | ||
31 | }, | ||
32 | { | ||
33 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe), | ||
34 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout), | ||
35 | (unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din), | ||
36 | 18 | ||
37 | }, | ||
38 | { | ||
39 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe), | ||
40 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout), | ||
41 | (unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din), | ||
42 | 18 | ||
43 | }, | ||
44 | { | ||
45 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe), | ||
46 | (unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout), | ||
47 | (unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din), | ||
48 | 18 | ||
49 | } | ||
50 | }; | ||
51 | |||
52 | #define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports) | ||
53 | |||
54 | struct crisv32_iopin crisv32_led1_green; | ||
55 | struct crisv32_iopin crisv32_led1_red; | ||
56 | struct crisv32_iopin crisv32_led2_green; | ||
57 | struct crisv32_iopin crisv32_led2_red; | ||
58 | struct crisv32_iopin crisv32_led3_green; | ||
59 | struct crisv32_iopin crisv32_led3_red; | ||
60 | |||
61 | /* Dummy port used when green LED and red LED is on the same bit */ | ||
62 | static unsigned long io_dummy; | ||
63 | static struct crisv32_ioport dummy_port = | ||
64 | { | ||
65 | &io_dummy, | ||
66 | &io_dummy, | ||
67 | &io_dummy, | ||
68 | 18 | ||
69 | }; | ||
70 | static struct crisv32_iopin dummy_led = | ||
71 | { | ||
72 | &dummy_port, | ||
73 | 0 | ||
74 | }; | ||
75 | |||
76 | static int __init crisv32_io_init(void) | ||
77 | { | ||
78 | int ret = 0; | ||
79 | /* Initialize LEDs */ | ||
80 | ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G); | ||
81 | ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R); | ||
82 | ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G); | ||
83 | ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R); | ||
84 | ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G); | ||
85 | ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R); | ||
86 | crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out); | ||
87 | crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out); | ||
88 | crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); | ||
89 | crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); | ||
90 | crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); | ||
91 | crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); | ||
92 | |||
93 | if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R)) | ||
94 | crisv32_led1_red = dummy_led; | ||
95 | if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R)) | ||
96 | crisv32_led2_red = dummy_led; | ||
97 | |||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | __initcall(crisv32_io_init); | ||
102 | |||
103 | int crisv32_io_get(struct crisv32_iopin* iopin, | ||
104 | unsigned int port, unsigned int pin) | ||
105 | { | ||
106 | if (port > NBR_OF_PORTS) | ||
107 | return -EINVAL; | ||
108 | if (port > crisv32_ioports[port].pin_count) | ||
109 | return -EINVAL; | ||
110 | |||
111 | iopin->bit = 1 << pin; | ||
112 | iopin->port = &crisv32_ioports[port]; | ||
113 | |||
114 | if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) | ||
115 | return -EIO; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int crisv32_io_get_name(struct crisv32_iopin* iopin, | ||
121 | char* name) | ||
122 | { | ||
123 | int port; | ||
124 | int pin; | ||
125 | |||
126 | if (toupper(*name) == 'P') | ||
127 | name++; | ||
128 | |||
129 | if (toupper(*name) < 'A' || toupper(*name) > 'E') | ||
130 | return -EINVAL; | ||
131 | |||
132 | port = toupper(*name) - 'A'; | ||
133 | name++; | ||
134 | pin = simple_strtoul(name, NULL, 10); | ||
135 | |||
136 | if (pin < 0 || pin > crisv32_ioports[port].pin_count) | ||
137 | return -EINVAL; | ||
138 | |||
139 | iopin->bit = 1 << pin; | ||
140 | iopin->port = &crisv32_ioports[port]; | ||
141 | |||
142 | if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) | ||
143 | return -EIO; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | #ifdef CONFIG_PCI | ||
149 | /* PCI I/O access stuff */ | ||
150 | struct cris_io_operations* cris_iops = NULL; | ||
151 | EXPORT_SYMBOL(cris_iops); | ||
152 | #endif | ||
153 | |||
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c index a9acaa270243..173c141ac9ba 100644 --- a/arch/cris/arch-v32/kernel/irq.c +++ b/arch/cris/arch-v32/kernel/irq.c | |||
@@ -15,15 +15,21 @@ | |||
15 | #include <linux/threads.h> | 15 | #include <linux/threads.h> |
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/kernel_stat.h> | 17 | #include <linux/kernel_stat.h> |
18 | #include <asm/arch/hwregs/reg_map.h> | 18 | #include <hwregs/reg_map.h> |
19 | #include <asm/arch/hwregs/reg_rdwr.h> | 19 | #include <hwregs/reg_rdwr.h> |
20 | #include <asm/arch/hwregs/intr_vect.h> | 20 | #include <hwregs/intr_vect.h> |
21 | #include <asm/arch/hwregs/intr_vect_defs.h> | 21 | #include <hwregs/intr_vect_defs.h> |
22 | 22 | ||
23 | #define CPU_FIXED -1 | 23 | #define CPU_FIXED -1 |
24 | 24 | ||
25 | /* IRQ masks (refer to comment for crisv32_do_multiple) */ | 25 | /* IRQ masks (refer to comment for crisv32_do_multiple) */ |
26 | #define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ)) | 26 | #if TIMER0_INTR_VECT - FIRST_IRQ < 32 |
27 | #define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ)) | ||
28 | #undef TIMER_VECT1 | ||
29 | #else | ||
30 | #define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32)) | ||
31 | #define TIMER_VECT1 | ||
32 | #endif | ||
27 | #ifdef CONFIG_ETRAX_KGDB | 33 | #ifdef CONFIG_ETRAX_KGDB |
28 | #if defined(CONFIG_ETRAX_KGDB_PORT0) | 34 | #if defined(CONFIG_ETRAX_KGDB_PORT0) |
29 | #define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ)) | 35 | #define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ)) |
@@ -44,8 +50,8 @@ struct cris_irq_allocation | |||
44 | cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */ | 50 | cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */ |
45 | }; | 51 | }; |
46 | 52 | ||
47 | struct cris_irq_allocation irq_allocations[NR_IRQS] = | 53 | struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] = |
48 | {[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}}; | 54 | { [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} }; |
49 | 55 | ||
50 | static unsigned long irq_regs[NR_CPUS] = | 56 | static unsigned long irq_regs[NR_CPUS] = |
51 | { | 57 | { |
@@ -55,6 +61,12 @@ static unsigned long irq_regs[NR_CPUS] = | |||
55 | #endif | 61 | #endif |
56 | }; | 62 | }; |
57 | 63 | ||
64 | #if NR_REAL_IRQS > 32 | ||
65 | #define NBR_REGS 2 | ||
66 | #else | ||
67 | #define NBR_REGS 1 | ||
68 | #endif | ||
69 | |||
58 | unsigned long cpu_irq_counters[NR_CPUS]; | 70 | unsigned long cpu_irq_counters[NR_CPUS]; |
59 | unsigned long irq_counters[NR_REAL_IRQS]; | 71 | unsigned long irq_counters[NR_REAL_IRQS]; |
60 | 72 | ||
@@ -79,45 +91,81 @@ extern void d_mmu_write(void); | |||
79 | extern void kgdb_init(void); | 91 | extern void kgdb_init(void); |
80 | extern void breakpoint(void); | 92 | extern void breakpoint(void); |
81 | 93 | ||
94 | /* From traps.c. */ | ||
95 | extern void breakh_BUG(void); | ||
96 | |||
82 | /* | 97 | /* |
83 | * Build the IRQ handler stubs using macros from irq.h. First argument is the | 98 | * Build the IRQ handler stubs using macros from irq.h. |
84 | * IRQ number, the second argument is the corresponding bit in | ||
85 | * intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h. | ||
86 | */ | 99 | */ |
87 | BUILD_IRQ(0x31, (1 << 0)) /* memarb */ | 100 | BUILD_IRQ(0x31) |
88 | BUILD_IRQ(0x32, (1 << 1)) /* gen_io */ | 101 | BUILD_IRQ(0x32) |
89 | BUILD_IRQ(0x33, (1 << 2)) /* iop0 */ | 102 | BUILD_IRQ(0x33) |
90 | BUILD_IRQ(0x34, (1 << 3)) /* iop1 */ | 103 | BUILD_IRQ(0x34) |
91 | BUILD_IRQ(0x35, (1 << 4)) /* iop2 */ | 104 | BUILD_IRQ(0x35) |
92 | BUILD_IRQ(0x36, (1 << 5)) /* iop3 */ | 105 | BUILD_IRQ(0x36) |
93 | BUILD_IRQ(0x37, (1 << 6)) /* dma0 */ | 106 | BUILD_IRQ(0x37) |
94 | BUILD_IRQ(0x38, (1 << 7)) /* dma1 */ | 107 | BUILD_IRQ(0x38) |
95 | BUILD_IRQ(0x39, (1 << 8)) /* dma2 */ | 108 | BUILD_IRQ(0x39) |
96 | BUILD_IRQ(0x3a, (1 << 9)) /* dma3 */ | 109 | BUILD_IRQ(0x3a) |
97 | BUILD_IRQ(0x3b, (1 << 10)) /* dma4 */ | 110 | BUILD_IRQ(0x3b) |
98 | BUILD_IRQ(0x3c, (1 << 11)) /* dma5 */ | 111 | BUILD_IRQ(0x3c) |
99 | BUILD_IRQ(0x3d, (1 << 12)) /* dma6 */ | 112 | BUILD_IRQ(0x3d) |
100 | BUILD_IRQ(0x3e, (1 << 13)) /* dma7 */ | 113 | BUILD_IRQ(0x3e) |
101 | BUILD_IRQ(0x3f, (1 << 14)) /* dma8 */ | 114 | BUILD_IRQ(0x3f) |
102 | BUILD_IRQ(0x40, (1 << 15)) /* dma9 */ | 115 | BUILD_IRQ(0x40) |
103 | BUILD_IRQ(0x41, (1 << 16)) /* ata */ | 116 | BUILD_IRQ(0x41) |
104 | BUILD_IRQ(0x42, (1 << 17)) /* sser0 */ | 117 | BUILD_IRQ(0x42) |
105 | BUILD_IRQ(0x43, (1 << 18)) /* sser1 */ | 118 | BUILD_IRQ(0x43) |
106 | BUILD_IRQ(0x44, (1 << 19)) /* ser0 */ | 119 | BUILD_IRQ(0x44) |
107 | BUILD_IRQ(0x45, (1 << 20)) /* ser1 */ | 120 | BUILD_IRQ(0x45) |
108 | BUILD_IRQ(0x46, (1 << 21)) /* ser2 */ | 121 | BUILD_IRQ(0x46) |
109 | BUILD_IRQ(0x47, (1 << 22)) /* ser3 */ | 122 | BUILD_IRQ(0x47) |
110 | BUILD_IRQ(0x48, (1 << 23)) | 123 | BUILD_IRQ(0x48) |
111 | BUILD_IRQ(0x49, (1 << 24)) /* eth0 */ | 124 | BUILD_IRQ(0x49) |
112 | BUILD_IRQ(0x4a, (1 << 25)) /* eth1 */ | 125 | BUILD_IRQ(0x4a) |
113 | BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */ | 126 | BUILD_IRQ(0x4b) |
114 | BUILD_IRQ(0x4c, (1 << 27)) /* bif_arb */ | 127 | BUILD_IRQ(0x4c) |
115 | BUILD_IRQ(0x4d, (1 << 28)) /* bif_dma */ | 128 | BUILD_IRQ(0x4d) |
116 | BUILD_IRQ(0x4e, (1 << 29)) /* ext */ | 129 | BUILD_IRQ(0x4e) |
117 | BUILD_IRQ(0x4f, (1 << 29)) /* ipi */ | 130 | BUILD_IRQ(0x4f) |
131 | BUILD_IRQ(0x50) | ||
132 | #if MACH_IRQS > 32 | ||
133 | BUILD_IRQ(0x51) | ||
134 | BUILD_IRQ(0x52) | ||
135 | BUILD_IRQ(0x53) | ||
136 | BUILD_IRQ(0x54) | ||
137 | BUILD_IRQ(0x55) | ||
138 | BUILD_IRQ(0x56) | ||
139 | BUILD_IRQ(0x57) | ||
140 | BUILD_IRQ(0x58) | ||
141 | BUILD_IRQ(0x59) | ||
142 | BUILD_IRQ(0x5a) | ||
143 | BUILD_IRQ(0x5b) | ||
144 | BUILD_IRQ(0x5c) | ||
145 | BUILD_IRQ(0x5d) | ||
146 | BUILD_IRQ(0x5e) | ||
147 | BUILD_IRQ(0x5f) | ||
148 | BUILD_IRQ(0x60) | ||
149 | BUILD_IRQ(0x61) | ||
150 | BUILD_IRQ(0x62) | ||
151 | BUILD_IRQ(0x63) | ||
152 | BUILD_IRQ(0x64) | ||
153 | BUILD_IRQ(0x65) | ||
154 | BUILD_IRQ(0x66) | ||
155 | BUILD_IRQ(0x67) | ||
156 | BUILD_IRQ(0x68) | ||
157 | BUILD_IRQ(0x69) | ||
158 | BUILD_IRQ(0x6a) | ||
159 | BUILD_IRQ(0x6b) | ||
160 | BUILD_IRQ(0x6c) | ||
161 | BUILD_IRQ(0x6d) | ||
162 | BUILD_IRQ(0x6e) | ||
163 | BUILD_IRQ(0x6f) | ||
164 | BUILD_IRQ(0x70) | ||
165 | #endif | ||
118 | 166 | ||
119 | /* Pointers to the low-level handlers. */ | 167 | /* Pointers to the low-level handlers. */ |
120 | static void (*interrupt[NR_IRQS])(void) = { | 168 | static void (*interrupt[MACH_IRQS])(void) = { |
121 | IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt, | 169 | IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt, |
122 | IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt, | 170 | IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt, |
123 | IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt, | 171 | IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt, |
@@ -128,7 +176,20 @@ static void (*interrupt[NR_IRQS])(void) = { | |||
128 | IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt, | 176 | IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt, |
129 | IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt, | 177 | IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt, |
130 | IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt, | 178 | IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt, |
131 | IRQ0x4f_interrupt | 179 | IRQ0x4f_interrupt, IRQ0x50_interrupt, |
180 | #if MACH_IRQS > 32 | ||
181 | IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt, | ||
182 | IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt, | ||
183 | IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt, | ||
184 | IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt, | ||
185 | IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt, | ||
186 | IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt, | ||
187 | IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt, | ||
188 | IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt, | ||
189 | IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt, | ||
190 | IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt, | ||
191 | IRQ0x6f_interrupt, IRQ0x70_interrupt, | ||
192 | #endif | ||
132 | }; | 193 | }; |
133 | 194 | ||
134 | void | 195 | void |
@@ -137,13 +198,26 @@ block_irq(int irq, int cpu) | |||
137 | int intr_mask; | 198 | int intr_mask; |
138 | unsigned long flags; | 199 | unsigned long flags; |
139 | 200 | ||
140 | spin_lock_irqsave(&irq_lock, flags); | 201 | spin_lock_irqsave(&irq_lock, flags); |
141 | intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); | 202 | if (irq - FIRST_IRQ < 32) |
142 | 203 | intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], | |
143 | /* Remember; 1 let through, 0 block. */ | 204 | rw_mask, 0); |
144 | intr_mask &= ~(1 << (irq - FIRST_IRQ)); | 205 | else |
145 | 206 | intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], | |
146 | REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask); | 207 | rw_mask, 1); |
208 | |||
209 | /* Remember; 1 let thru, 0 block. */ | ||
210 | if (irq - FIRST_IRQ < 32) | ||
211 | intr_mask &= ~(1 << (irq - FIRST_IRQ)); | ||
212 | else | ||
213 | intr_mask &= ~(1 << (irq - FIRST_IRQ - 32)); | ||
214 | |||
215 | if (irq - FIRST_IRQ < 32) | ||
216 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, | ||
217 | 0, intr_mask); | ||
218 | else | ||
219 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, | ||
220 | 1, intr_mask); | ||
147 | spin_unlock_irqrestore(&irq_lock, flags); | 221 | spin_unlock_irqrestore(&irq_lock, flags); |
148 | } | 222 | } |
149 | 223 | ||
@@ -154,12 +228,26 @@ unblock_irq(int irq, int cpu) | |||
154 | unsigned long flags; | 228 | unsigned long flags; |
155 | 229 | ||
156 | spin_lock_irqsave(&irq_lock, flags); | 230 | spin_lock_irqsave(&irq_lock, flags); |
157 | intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); | 231 | if (irq - FIRST_IRQ < 32) |
158 | 232 | intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], | |
159 | /* Remember; 1 let through, 0 block. */ | 233 | rw_mask, 0); |
160 | intr_mask |= (1 << (irq - FIRST_IRQ)); | 234 | else |
235 | intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], | ||
236 | rw_mask, 1); | ||
237 | |||
238 | /* Remember; 1 let thru, 0 block. */ | ||
239 | if (irq - FIRST_IRQ < 32) | ||
240 | intr_mask |= (1 << (irq - FIRST_IRQ)); | ||
241 | else | ||
242 | intr_mask |= (1 << (irq - FIRST_IRQ - 32)); | ||
243 | |||
244 | if (irq - FIRST_IRQ < 32) | ||
245 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, | ||
246 | 0, intr_mask); | ||
247 | else | ||
248 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, | ||
249 | 1, intr_mask); | ||
161 | 250 | ||
162 | REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask); | ||
163 | spin_unlock_irqrestore(&irq_lock, flags); | 251 | spin_unlock_irqrestore(&irq_lock, flags); |
164 | } | 252 | } |
165 | 253 | ||
@@ -298,8 +386,9 @@ crisv32_do_multiple(struct pt_regs* regs) | |||
298 | { | 386 | { |
299 | int cpu; | 387 | int cpu; |
300 | int mask; | 388 | int mask; |
301 | int masked; | 389 | int masked[NBR_REGS]; |
302 | int bit; | 390 | int bit; |
391 | int i; | ||
303 | 392 | ||
304 | cpu = smp_processor_id(); | 393 | cpu = smp_processor_id(); |
305 | 394 | ||
@@ -308,42 +397,59 @@ crisv32_do_multiple(struct pt_regs* regs) | |||
308 | */ | 397 | */ |
309 | irq_enter(); | 398 | irq_enter(); |
310 | 399 | ||
311 | /* Get which IRQs that happened. */ | 400 | for (i = 0; i < NBR_REGS; i++) { |
312 | masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect); | 401 | /* Get which IRQs that happend. */ |
402 | masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], | ||
403 | r_masked_vect, i); | ||
313 | 404 | ||
314 | /* Calculate new IRQ mask with these IRQs disabled. */ | 405 | /* Calculate new IRQ mask with these IRQs disabled. */ |
315 | mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); | 406 | mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); |
316 | mask &= ~masked; | 407 | mask &= ~masked[i]; |
317 | 408 | ||
318 | /* Timer IRQ is never masked */ | 409 | /* Timer IRQ is never masked */ |
319 | if (masked & TIMER_MASK) | 410 | #ifdef TIMER_VECT1 |
320 | mask |= TIMER_MASK; | 411 | if ((i == 1) && (masked[0] & TIMER_MASK)) |
321 | 412 | mask |= TIMER_MASK; | |
322 | /* Block all the IRQs */ | 413 | #else |
323 | REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask); | 414 | if ((i == 0) && (masked[0] & TIMER_MASK)) |
415 | mask |= TIMER_MASK; | ||
416 | #endif | ||
417 | /* Block all the IRQs */ | ||
418 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); | ||
324 | 419 | ||
325 | /* Check for timer IRQ and handle it special. */ | 420 | /* Check for timer IRQ and handle it special. */ |
326 | if (masked & TIMER_MASK) { | 421 | #ifdef TIMER_VECT1 |
327 | masked &= ~TIMER_MASK; | 422 | if ((i == 1) && (masked[i] & TIMER_MASK)) { |
328 | do_IRQ(TIMER_INTR_VECT, regs); | 423 | masked[i] &= ~TIMER_MASK; |
424 | do_IRQ(TIMER0_INTR_VECT, regs); | ||
425 | } | ||
426 | #else | ||
427 | if ((i == 0) && (masked[i] & TIMER_MASK)) { | ||
428 | masked[i] &= ~TIMER_MASK; | ||
429 | do_IRQ(TIMER0_INTR_VECT, regs); | ||
430 | } | ||
329 | } | 431 | } |
432 | #endif | ||
330 | 433 | ||
331 | #ifdef IGNORE_MASK | 434 | #ifdef IGNORE_MASK |
332 | /* Remove IRQs that can't be handled as multiple. */ | 435 | /* Remove IRQs that can't be handled as multiple. */ |
333 | masked &= ~IGNORE_MASK; | 436 | masked[0] &= ~IGNORE_MASK; |
334 | #endif | 437 | #endif |
335 | 438 | ||
336 | /* Handle the rest of the IRQs. */ | 439 | /* Handle the rest of the IRQs. */ |
337 | for (bit = 0; bit < 32; bit++) | 440 | for (i = 0; i < NBR_REGS; i++) { |
338 | { | 441 | for (bit = 0; bit < 32; bit++) { |
339 | if (masked & (1 << bit)) | 442 | if (masked[i] & (1 << bit)) |
340 | do_IRQ(bit + FIRST_IRQ, regs); | 443 | do_IRQ(bit + FIRST_IRQ + i*32, regs); |
444 | } | ||
341 | } | 445 | } |
342 | 446 | ||
343 | /* Unblock all the IRQs. */ | 447 | /* Unblock all the IRQs. */ |
344 | mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask); | 448 | for (i = 0; i < NBR_REGS; i++) { |
345 | mask |= masked; | 449 | mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); |
346 | REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask); | 450 | mask |= masked[i]; |
451 | REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); | ||
452 | } | ||
347 | 453 | ||
348 | /* This irq_exit() will trigger the soft IRQs. */ | 454 | /* This irq_exit() will trigger the soft IRQs. */ |
349 | irq_exit(); | 455 | irq_exit(); |
@@ -361,20 +467,21 @@ init_IRQ(void) | |||
361 | reg_intr_vect_rw_mask vect_mask = {0}; | 467 | reg_intr_vect_rw_mask vect_mask = {0}; |
362 | 468 | ||
363 | /* Clear all interrupts masks. */ | 469 | /* Clear all interrupts masks. */ |
364 | REG_WR(intr_vect, regi_irq, rw_mask, vect_mask); | 470 | for (i = 0; i < NBR_REGS; i++) |
471 | REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask); | ||
365 | 472 | ||
366 | for (i = 0; i < 256; i++) | 473 | for (i = 0; i < 256; i++) |
367 | etrax_irv->v[i] = weird_irq; | 474 | etrax_irv->v[i] = weird_irq; |
368 | 475 | ||
369 | /* Point all IRQs to bad handlers. */ | 476 | /* Point all IRQ's to bad handlers. */ |
370 | for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) { | 477 | for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) { |
371 | irq_desc[j].chip = &crisv32_irq_type; | 478 | irq_desc[j].chip = &crisv32_irq_type; |
372 | set_exception_vector(i, interrupt[j]); | 479 | set_exception_vector(i, interrupt[j]); |
373 | } | 480 | } |
374 | 481 | ||
375 | /* Mark Timer and IPI IRQs as CPU local */ | 482 | /* Mark Timer and IPI IRQs as CPU local */ |
376 | irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; | 483 | irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; |
377 | irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU; | 484 | irq_desc[TIMER0_INTR_VECT].status |= IRQ_PER_CPU; |
378 | irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; | 485 | irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; |
379 | irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU; | 486 | irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU; |
380 | 487 | ||
@@ -391,6 +498,11 @@ init_IRQ(void) | |||
391 | set_exception_vector(0x0a, d_mmu_access); | 498 | set_exception_vector(0x0a, d_mmu_access); |
392 | set_exception_vector(0x0b, d_mmu_write); | 499 | set_exception_vector(0x0b, d_mmu_write); |
393 | 500 | ||
501 | #ifdef CONFIG_BUG | ||
502 | /* Break 14 handler, used to implement cheap BUG(). */ | ||
503 | set_exception_vector(0x1e, breakh_BUG); | ||
504 | #endif | ||
505 | |||
394 | /* The system-call trap is reached by "break 13". */ | 506 | /* The system-call trap is reached by "break 13". */ |
395 | set_exception_vector(0x1d, system_call); | 507 | set_exception_vector(0x1d, system_call); |
396 | 508 | ||
diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c index 480e56348be2..4e2e2e271efb 100644 --- a/arch/cris/arch-v32/kernel/kgdb.c +++ b/arch/cris/arch-v32/kernel/kgdb.c | |||
@@ -381,7 +381,7 @@ static int read_register(char regno, unsigned int *valptr); | |||
381 | /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ | 381 | /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ |
382 | int getDebugChar(void); | 382 | int getDebugChar(void); |
383 | 383 | ||
384 | #ifdef CONFIG_ETRAXFS_SIM | 384 | #ifdef CONFIG_ETRAX_VCS_SIM |
385 | int getDebugChar(void) | 385 | int getDebugChar(void) |
386 | { | 386 | { |
387 | return socketread(); | 387 | return socketread(); |
@@ -391,7 +391,7 @@ int getDebugChar(void) | |||
391 | /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ | 391 | /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ |
392 | void putDebugChar(int val); | 392 | void putDebugChar(int val); |
393 | 393 | ||
394 | #ifdef CONFIG_ETRAXFS_SIM | 394 | #ifdef CONFIG_ETRAX_VCS_SIM |
395 | void putDebugChar(int val) | 395 | void putDebugChar(int val) |
396 | { | 396 | { |
397 | socketwrite((char *)&val, 1); | 397 | socketwrite((char *)&val, 1); |
@@ -1599,7 +1599,7 @@ kgdb_init(void) | |||
1599 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | 1599 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); |
1600 | 1600 | ||
1601 | ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask); | 1601 | ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask); |
1602 | ser_intr_mask.data_avail = regk_ser_yes; | 1602 | ser_intr_mask.dav = regk_ser_yes; |
1603 | REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask); | 1603 | REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask); |
1604 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) | 1604 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) |
1605 | /* Note: no shortcut registered (not handled by multiple_interrupt). | 1605 | /* Note: no shortcut registered (not handled by multiple_interrupt). |
@@ -1611,7 +1611,7 @@ kgdb_init(void) | |||
1611 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | 1611 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); |
1612 | 1612 | ||
1613 | ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask); | 1613 | ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask); |
1614 | ser_intr_mask.data_avail = regk_ser_yes; | 1614 | ser_intr_mask.dav = regk_ser_yes; |
1615 | REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask); | 1615 | REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask); |
1616 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) | 1616 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) |
1617 | /* Note: no shortcut registered (not handled by multiple_interrupt). | 1617 | /* Note: no shortcut registered (not handled by multiple_interrupt). |
@@ -1623,7 +1623,7 @@ kgdb_init(void) | |||
1623 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | 1623 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); |
1624 | 1624 | ||
1625 | ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask); | 1625 | ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask); |
1626 | ser_intr_mask.data_avail = regk_ser_yes; | 1626 | ser_intr_mask.dav = regk_ser_yes; |
1627 | REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask); | 1627 | REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask); |
1628 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) | 1628 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) |
1629 | /* Note: no shortcut registered (not handled by multiple_interrupt). | 1629 | /* Note: no shortcut registered (not handled by multiple_interrupt). |
@@ -1635,7 +1635,7 @@ kgdb_init(void) | |||
1635 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | 1635 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); |
1636 | 1636 | ||
1637 | ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask); | 1637 | ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask); |
1638 | ser_intr_mask.data_avail = regk_ser_yes; | 1638 | ser_intr_mask.dav = regk_ser_yes; |
1639 | REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask); | 1639 | REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask); |
1640 | #endif | 1640 | #endif |
1641 | 1641 | ||
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index b72a15580dc7..ced5b725d9bd 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c | |||
@@ -12,17 +12,13 @@ | |||
12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <asm/arch/hwregs/reg_rdwr.h> | 15 | #include <hwregs/reg_rdwr.h> |
16 | #include <asm/arch/hwregs/reg_map.h> | 16 | #include <hwregs/reg_map.h> |
17 | #include <asm/arch/hwregs/timer_defs.h> | 17 | #include <hwregs/timer_defs.h> |
18 | #include <asm/arch/hwregs/intr_vect_defs.h> | 18 | #include <hwregs/intr_vect_defs.h> |
19 | 19 | ||
20 | extern void stop_watchdog(void); | 20 | extern void stop_watchdog(void); |
21 | 21 | ||
22 | #ifdef CONFIG_ETRAX_GPIO | ||
23 | extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */ | ||
24 | #endif | ||
25 | |||
26 | extern int cris_hlt_counter; | 22 | extern int cris_hlt_counter; |
27 | 23 | ||
28 | /* We use this if we don't have any better idle routine. */ | 24 | /* We use this if we don't have any better idle routine. */ |
@@ -82,7 +78,7 @@ hard_reset_now(void) | |||
82 | wd_ctrl.cmd = regk_timer_start; | 78 | wd_ctrl.cmd = regk_timer_start; |
83 | 79 | ||
84 | arch_enable_nmi(); | 80 | arch_enable_nmi(); |
85 | REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); | 81 | REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); |
86 | } | 82 | } |
87 | #endif | 83 | #endif |
88 | 84 | ||
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index 2df60529a8af..e27f4670e88e 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000-2003, Axis Communications AB. | 2 | * Copyright (C) 2000-2007, Axis Communications AB. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/kernel.h> | 5 | #include <linux/kernel.h> |
@@ -149,7 +149,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
149 | ret = generic_ptrace_pokedata(child, addr, data); | 149 | ret = generic_ptrace_pokedata(child, addr, data); |
150 | break; | 150 | break; |
151 | 151 | ||
152 | /* Write the word at location address in the USER area. */ | 152 | /* Write the word at location address in the USER area. */ |
153 | case PTRACE_POKEUSR: | 153 | case PTRACE_POKEUSR: |
154 | ret = -EIO; | 154 | ret = -EIO; |
155 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) | 155 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) |
@@ -201,7 +201,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
201 | 201 | ||
202 | break; | 202 | break; |
203 | 203 | ||
204 | /* Make the child exit by sending it a sigkill. */ | 204 | /* Make the child exit by sending it a sigkill. */ |
205 | case PTRACE_KILL: | 205 | case PTRACE_KILL: |
206 | ret = 0; | 206 | ret = 0; |
207 | 207 | ||
@@ -245,9 +245,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
245 | break; | 245 | break; |
246 | 246 | ||
247 | } | 247 | } |
248 | |||
248 | /* Get all GP registers from the child. */ | 249 | /* Get all GP registers from the child. */ |
249 | case PTRACE_GETREGS: { | 250 | case PTRACE_GETREGS: { |
250 | int i; | 251 | int i; |
251 | unsigned long tmp; | 252 | unsigned long tmp; |
252 | 253 | ||
253 | for (i = 0; i <= PT_MAX; i++) { | 254 | for (i = 0; i <= PT_MAX; i++) { |
@@ -294,6 +295,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
294 | break; | 295 | break; |
295 | } | 296 | } |
296 | 297 | ||
298 | out_tsk: | ||
297 | return ret; | 299 | return ret; |
298 | } | 300 | } |
299 | 301 | ||
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 024cc6901974..58c1866804e3 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c | |||
@@ -50,7 +50,7 @@ struct rt_signal_frame { | |||
50 | unsigned char retcode[8]; /* Trampoline code. */ | 50 | unsigned char retcode[8]; /* Trampoline code. */ |
51 | }; | 51 | }; |
52 | 52 | ||
53 | int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs); | 53 | void do_signal(int restart, struct pt_regs *regs); |
54 | void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, | 54 | void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, |
55 | struct pt_regs *regs); | 55 | struct pt_regs *regs); |
56 | /* | 56 | /* |
@@ -61,74 +61,16 @@ int | |||
61 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | 61 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, |
62 | long srp, struct pt_regs *regs) | 62 | long srp, struct pt_regs *regs) |
63 | { | 63 | { |
64 | sigset_t saveset; | ||
65 | |||
66 | mask &= _BLOCKABLE; | 64 | mask &= _BLOCKABLE; |
67 | |||
68 | spin_lock_irq(¤t->sighand->siglock); | 65 | spin_lock_irq(¤t->sighand->siglock); |
69 | 66 | current->saved_sigmask = current->blocked; | |
70 | saveset = current->blocked; | ||
71 | |||
72 | siginitset(¤t->blocked, mask); | 67 | siginitset(¤t->blocked, mask); |
73 | |||
74 | recalc_sigpending(); | ||
75 | spin_unlock_irq(¤t->sighand->siglock); | ||
76 | |||
77 | regs->r10 = -EINTR; | ||
78 | |||
79 | while (1) { | ||
80 | current->state = TASK_INTERRUPTIBLE; | ||
81 | schedule(); | ||
82 | |||
83 | if (do_signal(0, &saveset, regs)) { | ||
84 | /* | ||
85 | * This point is reached twice: once to call | ||
86 | * the signal handler, then again to return | ||
87 | * from the sigsuspend system call. When | ||
88 | * calling the signal handler, R10 hold the | ||
89 | * signal number as set by do_signal(). The | ||
90 | * sigsuspend call will always return with | ||
91 | * the restored value above; -EINTR. | ||
92 | */ | ||
93 | return regs->r10; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /* Define some dummy arguments to be able to reach the regs argument. */ | ||
99 | int | ||
100 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, | ||
101 | long mof, long srp, struct pt_regs *regs) | ||
102 | { | ||
103 | sigset_t saveset; | ||
104 | sigset_t newset; | ||
105 | |||
106 | if (sigsetsize != sizeof(sigset_t)) | ||
107 | return -EINVAL; | ||
108 | |||
109 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
110 | return -EFAULT; | ||
111 | |||
112 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
113 | spin_lock_irq(¤t->sighand->siglock); | ||
114 | |||
115 | saveset = current->blocked; | ||
116 | current->blocked = newset; | ||
117 | |||
118 | recalc_sigpending(); | 68 | recalc_sigpending(); |
119 | spin_unlock_irq(¤t->sighand->siglock); | 69 | spin_unlock_irq(¤t->sighand->siglock); |
120 | 70 | current->state = TASK_INTERRUPTIBLE; | |
121 | regs->r10 = -EINTR; | 71 | schedule(); |
122 | 72 | set_thread_flag(TIF_RESTORE_SIGMASK); | |
123 | while (1) { | 73 | return -ERESTARTNOHAND; |
124 | current->state = TASK_INTERRUPTIBLE; | ||
125 | schedule(); | ||
126 | |||
127 | if (do_signal(0, &saveset, regs)) { | ||
128 | /* See comment in function above. */ | ||
129 | return regs->r10; | ||
130 | } | ||
131 | } | ||
132 | } | 74 | } |
133 | 75 | ||
134 | int | 76 | int |
@@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, | |||
290 | goto badframe; | 232 | goto badframe; |
291 | 233 | ||
292 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) | 234 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) |
293 | goto badframe; | 235 | goto badframe; |
294 | 236 | ||
295 | keep_debug_flags(oldccs, oldspc, regs); | 237 | keep_debug_flags(oldccs, oldspc, regs); |
296 | 238 | ||
@@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | |||
347 | /* Grab and setup a signal frame. | 289 | /* Grab and setup a signal frame. |
348 | * | 290 | * |
349 | * Basically a lot of state-info is stacked, and arranged for the | 291 | * Basically a lot of state-info is stacked, and arranged for the |
350 | * user-mode program to return to the kernel using either a trampoline | 292 | * user-mode program to return to the kernel using either a trampiline |
351 | * which performs the syscall sigreturn(), or a provided user-mode | 293 | * which performs the syscall sigreturn(), or a provided user-mode |
352 | * trampoline. | 294 | * trampoline. |
353 | */ | 295 | */ |
354 | static void | 296 | static int |
355 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | 297 | setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, |
356 | struct pt_regs * regs) | 298 | struct pt_regs * regs) |
357 | { | 299 | { |
@@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, | |||
417 | /* Actually move the USP to reflect the stacked frame. */ | 359 | /* Actually move the USP to reflect the stacked frame. */ |
418 | wrusp((unsigned long)frame); | 360 | wrusp((unsigned long)frame); |
419 | 361 | ||
420 | return; | 362 | return 0; |
421 | 363 | ||
422 | give_sigsegv: | 364 | give_sigsegv: |
423 | if (sig == SIGSEGV) | 365 | if (sig == SIGSEGV) |
424 | ka->sa.sa_handler = SIG_DFL; | 366 | ka->sa.sa_handler = SIG_DFL; |
425 | 367 | ||
426 | force_sig(SIGSEGV, current); | 368 | force_sig(SIGSEGV, current); |
369 | return -EFAULT; | ||
427 | } | 370 | } |
428 | 371 | ||
429 | static void | 372 | static int |
430 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 373 | setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
431 | sigset_t *set, struct pt_regs * regs) | 374 | sigset_t *set, struct pt_regs * regs) |
432 | { | 375 | { |
@@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
503 | /* Actually move the usp to reflect the stacked frame. */ | 446 | /* Actually move the usp to reflect the stacked frame. */ |
504 | wrusp((unsigned long)frame); | 447 | wrusp((unsigned long)frame); |
505 | 448 | ||
506 | return; | 449 | return 0; |
507 | 450 | ||
508 | give_sigsegv: | 451 | give_sigsegv: |
509 | if (sig == SIGSEGV) | 452 | if (sig == SIGSEGV) |
510 | ka->sa.sa_handler = SIG_DFL; | 453 | ka->sa.sa_handler = SIG_DFL; |
511 | 454 | ||
512 | force_sig(SIGSEGV, current); | 455 | force_sig(SIGSEGV, current); |
456 | return -EFAULT; | ||
513 | } | 457 | } |
514 | 458 | ||
515 | /* Invoke a singal handler to, well, handle the signal. */ | 459 | /* Invoke a singal handler to, well, handle the signal. */ |
516 | static inline void | 460 | static inline int |
517 | handle_signal(int canrestart, unsigned long sig, | 461 | handle_signal(int canrestart, unsigned long sig, |
518 | siginfo_t *info, struct k_sigaction *ka, | 462 | siginfo_t *info, struct k_sigaction *ka, |
519 | sigset_t *oldset, struct pt_regs * regs) | 463 | sigset_t *oldset, struct pt_regs * regs) |
520 | { | 464 | { |
465 | int ret; | ||
466 | |||
521 | /* Check if this got called from a system call. */ | 467 | /* Check if this got called from a system call. */ |
522 | if (canrestart) { | 468 | if (canrestart) { |
523 | /* If so, check system call restarting. */ | 469 | /* If so, check system call restarting. */ |
@@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig, | |||
561 | 507 | ||
562 | /* Set up the stack frame. */ | 508 | /* Set up the stack frame. */ |
563 | if (ka->sa.sa_flags & SA_SIGINFO) | 509 | if (ka->sa.sa_flags & SA_SIGINFO) |
564 | setup_rt_frame(sig, ka, info, oldset, regs); | 510 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
565 | else | 511 | else |
566 | setup_frame(sig, ka, oldset, regs); | 512 | ret = setup_frame(sig, ka, oldset, regs); |
567 | 513 | ||
568 | if (ka->sa.sa_flags & SA_ONESHOT) | 514 | if (ka->sa.sa_flags & SA_ONESHOT) |
569 | ka->sa.sa_handler = SIG_DFL; | 515 | ka->sa.sa_handler = SIG_DFL; |
570 | 516 | ||
571 | spin_lock_irq(¤t->sighand->siglock); | 517 | if (ret == 0) { |
572 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 518 | spin_lock_irq(¤t->sighand->siglock); |
573 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 519 | sigorsets(¤t->blocked, ¤t->blocked, |
574 | sigaddset(¤t->blocked,sig); | 520 | &ka->sa.sa_mask); |
575 | recalc_sigpending(); | 521 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
576 | spin_unlock_irq(¤t->sighand->siglock); | 522 | sigaddset(¤t->blocked, sig); |
523 | recalc_sigpending(); | ||
524 | spin_unlock_irq(¤t->sighand->siglock); | ||
525 | } | ||
526 | |||
527 | return ret; | ||
577 | } | 528 | } |
578 | 529 | ||
579 | /* | 530 | /* |
@@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig, | |||
587 | * we can use user_mode(regs) to see if we came directly from kernel or user | 538 | * we can use user_mode(regs) to see if we came directly from kernel or user |
588 | * mode below. | 539 | * mode below. |
589 | */ | 540 | */ |
590 | int | 541 | void |
591 | do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | 542 | do_signal(int canrestart, struct pt_regs *regs) |
592 | { | 543 | { |
593 | int signr; | 544 | int signr; |
594 | siginfo_t info; | 545 | siginfo_t info; |
595 | struct k_sigaction ka; | 546 | struct k_sigaction ka; |
547 | sigset_t *oldset; | ||
596 | 548 | ||
597 | /* | 549 | /* |
598 | * The common case should go fast, which is why this point is | 550 | * The common case should go fast, which is why this point is |
@@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
600 | * without doing anything. | 552 | * without doing anything. |
601 | */ | 553 | */ |
602 | if (!user_mode(regs)) | 554 | if (!user_mode(regs)) |
603 | return 1; | 555 | return; |
604 | 556 | ||
605 | if (!oldset) | 557 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
558 | oldset = ¤t->saved_sigmask; | ||
559 | else | ||
606 | oldset = ¤t->blocked; | 560 | oldset = ¤t->blocked; |
607 | 561 | ||
608 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 562 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
609 | 563 | ||
610 | if (signr > 0) { | 564 | if (signr > 0) { |
611 | /* Deliver the signal. */ | 565 | /* Whee! Actually deliver the signal. */ |
612 | handle_signal(canrestart, signr, &info, &ka, oldset, regs); | 566 | if (handle_signal(canrestart, signr, &info, &ka, |
613 | return 1; | 567 | oldset, regs)) { |
568 | /* a signal was successfully delivered; the saved | ||
569 | * sigmask will have been stored in the signal frame, | ||
570 | * and will be restored by sigreturn, so we can simply | ||
571 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
572 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
573 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
574 | } | ||
575 | |||
576 | return; | ||
614 | } | 577 | } |
615 | 578 | ||
616 | /* Got here from a system call? */ | 579 | /* Got here from a system call? */ |
@@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | |||
628 | } | 591 | } |
629 | } | 592 | } |
630 | 593 | ||
631 | return 0; | 594 | /* if there's no signal to deliver, we just put the saved sigmask |
595 | * back */ | ||
596 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
597 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
598 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
599 | } | ||
632 | } | 600 | } |
633 | 601 | ||
634 | asmlinkage void | 602 | asmlinkage void |
@@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig) | |||
641 | user_regs(ti)->spc = 0; | 609 | user_regs(ti)->spc = 0; |
642 | } | 610 | } |
643 | /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA | 611 | /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA |
644 | not within any configured h/w breakpoint range). Synchronize with | 612 | not withing any configured h/w breakpoint range). Synchronize with |
645 | what already exists for kernel debugging. */ | 613 | what already exists for kernel debugging. */ |
646 | if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { | 614 | if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { |
647 | /* Break 8: subtract 2 from ERP unless in a delay slot. */ | 615 | /* Break 8: subtract 2 from ERP unless in a delay slot. */ |
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 171c96e0a5d3..a9c3334e46c9 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c | |||
@@ -1,11 +1,12 @@ | |||
1 | #include <linux/types.h> | ||
1 | #include <asm/delay.h> | 2 | #include <asm/delay.h> |
2 | #include <asm/arch/irq.h> | 3 | #include <irq.h> |
3 | #include <asm/arch/hwregs/intr_vect.h> | 4 | #include <hwregs/intr_vect.h> |
4 | #include <asm/arch/hwregs/intr_vect_defs.h> | 5 | #include <hwregs/intr_vect_defs.h> |
5 | #include <asm/tlbflush.h> | 6 | #include <asm/tlbflush.h> |
6 | #include <asm/mmu_context.h> | 7 | #include <asm/mmu_context.h> |
7 | #include <asm/arch/hwregs/mmu_defs_asm.h> | 8 | #include <hwregs/asm/mmu_defs_asm.h> |
8 | #include <asm/arch/hwregs/supp_reg.h> | 9 | #include <hwregs/supp_reg.h> |
9 | #include <asm/atomic.h> | 10 | #include <asm/atomic.h> |
10 | 11 | ||
11 | #include <linux/err.h> | 12 | #include <linux/err.h> |
@@ -20,6 +21,7 @@ | |||
20 | #define IPI_SCHEDULE 1 | 21 | #define IPI_SCHEDULE 1 |
21 | #define IPI_CALL 2 | 22 | #define IPI_CALL 2 |
22 | #define IPI_FLUSH_TLB 4 | 23 | #define IPI_FLUSH_TLB 4 |
24 | #define IPI_BOOT 8 | ||
23 | 25 | ||
24 | #define FLUSH_ALL (void*)0xffffffff | 26 | #define FLUSH_ALL (void*)0xffffffff |
25 | 27 | ||
@@ -30,6 +32,8 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED}; | |||
30 | cpumask_t cpu_online_map = CPU_MASK_NONE; | 32 | cpumask_t cpu_online_map = CPU_MASK_NONE; |
31 | EXPORT_SYMBOL(cpu_online_map); | 33 | EXPORT_SYMBOL(cpu_online_map); |
32 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; | 34 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; |
35 | cpumask_t cpu_possible_map; | ||
36 | EXPORT_SYMBOL(cpu_possible_map); | ||
33 | EXPORT_SYMBOL(phys_cpu_present_map); | 37 | EXPORT_SYMBOL(phys_cpu_present_map); |
34 | 38 | ||
35 | /* Variables used during SMP boot */ | 39 | /* Variables used during SMP boot */ |
@@ -55,13 +59,12 @@ static unsigned long flush_addr; | |||
55 | extern int setup_irq(int, struct irqaction *); | 59 | extern int setup_irq(int, struct irqaction *); |
56 | 60 | ||
57 | /* Mode registers */ | 61 | /* Mode registers */ |
58 | static unsigned long irq_regs[NR_CPUS] = | 62 | static unsigned long irq_regs[NR_CPUS] = { |
59 | { | ||
60 | regi_irq, | 63 | regi_irq, |
61 | regi_irq2 | 64 | regi_irq2 |
62 | }; | 65 | }; |
63 | 66 | ||
64 | static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs); | 67 | static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id); |
65 | static int send_ipi(int vector, int wait, cpumask_t cpu_mask); | 68 | static int send_ipi(int vector, int wait, cpumask_t cpu_mask); |
66 | static struct irqaction irq_ipi = { | 69 | static struct irqaction irq_ipi = { |
67 | .handler = crisv32_ipi_interrupt, | 70 | .handler = crisv32_ipi_interrupt, |
@@ -101,6 +104,7 @@ void __devinit smp_prepare_boot_cpu(void) | |||
101 | 104 | ||
102 | cpu_set(0, cpu_online_map); | 105 | cpu_set(0, cpu_online_map); |
103 | cpu_set(0, phys_cpu_present_map); | 106 | cpu_set(0, phys_cpu_present_map); |
107 | cpu_set(0, cpu_possible_map); | ||
104 | } | 108 | } |
105 | 109 | ||
106 | void __init smp_cpus_done(unsigned int max_cpus) | 110 | void __init smp_cpus_done(unsigned int max_cpus) |
@@ -113,6 +117,7 @@ smp_boot_one_cpu(int cpuid) | |||
113 | { | 117 | { |
114 | unsigned timeout; | 118 | unsigned timeout; |
115 | struct task_struct *idle; | 119 | struct task_struct *idle; |
120 | cpumask_t cpu_mask = CPU_MASK_NONE; | ||
116 | 121 | ||
117 | idle = fork_idle(cpuid); | 122 | idle = fork_idle(cpuid); |
118 | if (IS_ERR(idle)) | 123 | if (IS_ERR(idle)) |
@@ -124,6 +129,12 @@ smp_boot_one_cpu(int cpuid) | |||
124 | smp_init_current_idle_thread = task_thread_info(idle); | 129 | smp_init_current_idle_thread = task_thread_info(idle); |
125 | cpu_now_booting = cpuid; | 130 | cpu_now_booting = cpuid; |
126 | 131 | ||
132 | /* Kick it */ | ||
133 | cpu_set(cpuid, cpu_online_map); | ||
134 | cpu_set(cpuid, cpu_mask); | ||
135 | send_ipi(IPI_BOOT, 0, cpu_mask); | ||
136 | cpu_clear(cpuid, cpu_online_map); | ||
137 | |||
127 | /* Wait for CPU to come online */ | 138 | /* Wait for CPU to come online */ |
128 | for (timeout = 0; timeout < 10000; timeout++) { | 139 | for (timeout = 0; timeout < 10000; timeout++) { |
129 | if(cpu_online(cpuid)) { | 140 | if(cpu_online(cpuid)) { |
@@ -165,7 +176,7 @@ void __init smp_callin(void) | |||
165 | /* Enable IRQ and idle */ | 176 | /* Enable IRQ and idle */ |
166 | REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask); | 177 | REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask); |
167 | unmask_irq(IPI_INTR_VECT); | 178 | unmask_irq(IPI_INTR_VECT); |
168 | unmask_irq(TIMER_INTR_VECT); | 179 | unmask_irq(TIMER0_INTR_VECT); |
169 | preempt_disable(); | 180 | preempt_disable(); |
170 | local_irq_enable(); | 181 | local_irq_enable(); |
171 | 182 | ||
@@ -328,7 +339,7 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
328 | return ret; | 339 | return ret; |
329 | } | 340 | } |
330 | 341 | ||
331 | irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 342 | irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id) |
332 | { | 343 | { |
333 | void (*func) (void *info) = call_data->func; | 344 | void (*func) (void *info) = call_data->func; |
334 | void *info = call_data->info; | 345 | void *info = call_data->info; |
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 2f7e8e200f2c..3a13dd6e0a9a 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c | |||
@@ -1,8 +1,7 @@ | |||
1 | /* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $ | 1 | /* |
2 | * | ||
3 | * linux/arch/cris/arch-v32/kernel/time.c | 2 | * linux/arch/cris/arch-v32/kernel/time.c |
4 | * | 3 | * |
5 | * Copyright (C) 2003 Axis Communications AB | 4 | * Copyright (C) 2003-2007 Axis Communications AB |
6 | * | 5 | * |
7 | */ | 6 | */ |
8 | 7 | ||
@@ -14,28 +13,34 @@ | |||
14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/threads.h> | 15 | #include <linux/threads.h> |
16 | #include <linux/cpufreq.h> | ||
17 | #include <asm/types.h> | 17 | #include <asm/types.h> |
18 | #include <asm/signal.h> | 18 | #include <asm/signal.h> |
19 | #include <asm/io.h> | 19 | #include <asm/io.h> |
20 | #include <asm/delay.h> | 20 | #include <asm/delay.h> |
21 | #include <asm/rtc.h> | 21 | #include <asm/rtc.h> |
22 | #include <asm/irq.h> | 22 | #include <asm/irq.h> |
23 | 23 | #include <asm/irq_regs.h> | |
24 | #include <asm/arch/hwregs/reg_map.h> | 24 | |
25 | #include <asm/arch/hwregs/reg_rdwr.h> | 25 | #include <hwregs/reg_map.h> |
26 | #include <asm/arch/hwregs/timer_defs.h> | 26 | #include <hwregs/reg_rdwr.h> |
27 | #include <asm/arch/hwregs/intr_vect_defs.h> | 27 | #include <hwregs/timer_defs.h> |
28 | #include <hwregs/intr_vect_defs.h> | ||
29 | #ifdef CONFIG_CRIS_MACH_ARTPEC3 | ||
30 | #include <hwregs/clkgen_defs.h> | ||
31 | #endif | ||
28 | 32 | ||
29 | /* Watchdog defines */ | 33 | /* Watchdog defines */ |
30 | #define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ | 34 | #define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ |
31 | #define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ | 35 | #define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ |
32 | #define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */ | 36 | /* Number of 763 counts before watchdog bites */ |
37 | #define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) | ||
33 | 38 | ||
34 | unsigned long timer_regs[NR_CPUS] = | 39 | unsigned long timer_regs[NR_CPUS] = |
35 | { | 40 | { |
36 | regi_timer, | 41 | regi_timer0, |
37 | #ifdef CONFIG_SMP | 42 | #ifdef CONFIG_SMP |
38 | regi_timer2 | 43 | regi_timer2 |
39 | #endif | 44 | #endif |
40 | }; | 45 | }; |
41 | 46 | ||
@@ -44,12 +49,22 @@ extern int set_rtc_mmss(unsigned long nowtime); | |||
44 | extern int setup_irq(int, struct irqaction *); | 49 | extern int setup_irq(int, struct irqaction *); |
45 | extern int have_rtc; | 50 | extern int have_rtc; |
46 | 51 | ||
52 | #ifdef CONFIG_CPU_FREQ | ||
53 | static int | ||
54 | cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
55 | void *data); | ||
56 | |||
57 | static struct notifier_block cris_time_freq_notifier_block = { | ||
58 | .notifier_call = cris_time_freq_notifier, | ||
59 | }; | ||
60 | #endif | ||
61 | |||
47 | unsigned long get_ns_in_jiffie(void) | 62 | unsigned long get_ns_in_jiffie(void) |
48 | { | 63 | { |
49 | reg_timer_r_tmr0_data data; | 64 | reg_timer_r_tmr0_data data; |
50 | unsigned long ns; | 65 | unsigned long ns; |
51 | 66 | ||
52 | data = REG_RD(timer, regi_timer, r_tmr0_data); | 67 | data = REG_RD(timer, regi_timer0, r_tmr0_data); |
53 | ns = (TIMER0_DIV - data) * 10; | 68 | ns = (TIMER0_DIV - data) * 10; |
54 | return ns; | 69 | return ns; |
55 | } | 70 | } |
@@ -59,31 +74,27 @@ unsigned long do_slow_gettimeoffset(void) | |||
59 | unsigned long count; | 74 | unsigned long count; |
60 | unsigned long usec_count = 0; | 75 | unsigned long usec_count = 0; |
61 | 76 | ||
62 | static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ | 77 | /* For the first call after boot */ |
78 | static unsigned long count_p = TIMER0_DIV; | ||
63 | static unsigned long jiffies_p = 0; | 79 | static unsigned long jiffies_p = 0; |
64 | 80 | ||
65 | /* | 81 | /* Cache volatile jiffies temporarily; we have IRQs turned off. */ |
66 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
67 | */ | ||
68 | unsigned long jiffies_t; | 82 | unsigned long jiffies_t; |
69 | 83 | ||
70 | /* The timer interrupt comes from Etrax timer 0. In order to get | 84 | /* The timer interrupt comes from Etrax timer 0. In order to get |
71 | * better precision, we check the current value. It might have | 85 | * better precision, we check the current value. It might have |
72 | * underflowed already though. | 86 | * underflowed already though. */ |
73 | */ | 87 | count = REG_RD(timer, regi_timer0, r_tmr0_data); |
88 | jiffies_t = jiffies; | ||
74 | 89 | ||
75 | count = REG_RD(timer, regi_timer, r_tmr0_data); | 90 | /* Avoiding timer inconsistencies (they are rare, but they happen) |
76 | jiffies_t = jiffies; | 91 | * There is one problem that must be avoided here: |
77 | 92 | * 1. the timer counter underflows | |
78 | /* | ||
79 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
80 | * there are one problem that must be avoided here: | ||
81 | * 1. the timer counter underflows | ||
82 | */ | 93 | */ |
83 | if( jiffies_t == jiffies_p ) { | 94 | if( jiffies_t == jiffies_p ) { |
84 | if( count > count_p ) { | 95 | if( count > count_p ) { |
85 | /* Timer wrapped, use new count and prescale | 96 | /* Timer wrapped, use new count and prescale. |
86 | * increase the time corresponding to one jiffie | 97 | * Increase the time corresponding to one jiffy. |
87 | */ | 98 | */ |
88 | usec_count = 1000000/HZ; | 99 | usec_count = 1000000/HZ; |
89 | } | 100 | } |
@@ -106,17 +117,15 @@ unsigned long do_slow_gettimeoffset(void) | |||
106 | */ | 117 | */ |
107 | /* This gives us 1.3 ms to do something useful when the NMI comes */ | 118 | /* This gives us 1.3 ms to do something useful when the NMI comes */ |
108 | 119 | ||
109 | /* right now, starting the watchdog is the same as resetting it */ | 120 | /* Right now, starting the watchdog is the same as resetting it */ |
110 | #define start_watchdog reset_watchdog | 121 | #define start_watchdog reset_watchdog |
111 | 122 | ||
112 | #if defined(CONFIG_ETRAX_WATCHDOG) | 123 | #if defined(CONFIG_ETRAX_WATCHDOG) |
113 | static short int watchdog_key = 42; /* arbitrary 7 bit number */ | 124 | static short int watchdog_key = 42; /* arbitrary 7 bit number */ |
114 | #endif | 125 | #endif |
115 | 126 | ||
116 | /* number of pages to consider "out of memory". it is normal that the memory | 127 | /* Number of pages to consider "out of memory". It is normal that the memory |
117 | * is used though, so put this really low. | 128 | * is used though, so set this really low. */ |
118 | */ | ||
119 | |||
120 | #define WATCHDOG_MIN_FREE_PAGES 8 | 129 | #define WATCHDOG_MIN_FREE_PAGES 8 |
121 | 130 | ||
122 | void | 131 | void |
@@ -125,14 +134,15 @@ reset_watchdog(void) | |||
125 | #if defined(CONFIG_ETRAX_WATCHDOG) | 134 | #if defined(CONFIG_ETRAX_WATCHDOG) |
126 | reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; | 135 | reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; |
127 | 136 | ||
128 | /* only keep watchdog happy as long as we have memory left! */ | 137 | /* Only keep watchdog happy as long as we have memory left! */ |
129 | if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { | 138 | if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { |
130 | /* reset the watchdog with the inverse of the old key */ | 139 | /* Reset the watchdog with the inverse of the old key */ |
131 | watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */ | 140 | /* Invert key, which is 7 bits */ |
141 | watchdog_key ^= ETRAX_WD_KEY_MASK; | ||
132 | wd_ctrl.cnt = ETRAX_WD_CNT; | 142 | wd_ctrl.cnt = ETRAX_WD_CNT; |
133 | wd_ctrl.cmd = regk_timer_start; | 143 | wd_ctrl.cmd = regk_timer_start; |
134 | wd_ctrl.key = watchdog_key; | 144 | wd_ctrl.key = watchdog_key; |
135 | REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); | 145 | REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); |
136 | } | 146 | } |
137 | #endif | 147 | #endif |
138 | } | 148 | } |
@@ -148,7 +158,7 @@ stop_watchdog(void) | |||
148 | wd_ctrl.cnt = ETRAX_WD_CNT; | 158 | wd_ctrl.cnt = ETRAX_WD_CNT; |
149 | wd_ctrl.cmd = regk_timer_stop; | 159 | wd_ctrl.cmd = regk_timer_stop; |
150 | wd_ctrl.key = watchdog_key; | 160 | wd_ctrl.key = watchdog_key; |
151 | REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl); | 161 | REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); |
152 | #endif | 162 | #endif |
153 | } | 163 | } |
154 | 164 | ||
@@ -160,17 +170,28 @@ handle_watchdog_bite(struct pt_regs* regs) | |||
160 | #if defined(CONFIG_ETRAX_WATCHDOG) | 170 | #if defined(CONFIG_ETRAX_WATCHDOG) |
161 | extern int cause_of_death; | 171 | extern int cause_of_death; |
162 | 172 | ||
163 | raw_printk("Watchdog bite\n"); | 173 | oops_in_progress = 1; |
174 | printk(KERN_WARNING "Watchdog bite\n"); | ||
164 | 175 | ||
165 | /* Check if forced restart or unexpected watchdog */ | 176 | /* Check if forced restart or unexpected watchdog */ |
166 | if (cause_of_death == 0xbedead) { | 177 | if (cause_of_death == 0xbedead) { |
178 | #ifdef CONFIG_CRIS_MACH_ARTPEC3 | ||
179 | /* There is a bug in Artpec-3 (voodoo TR 78) that requires | ||
180 | * us to go to lower frequency for the reset to be reliable | ||
181 | */ | ||
182 | reg_clkgen_rw_clk_ctrl ctrl = | ||
183 | REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | ||
184 | ctrl.pll = 0; | ||
185 | REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl); | ||
186 | #endif | ||
167 | while(1); | 187 | while(1); |
168 | } | 188 | } |
169 | 189 | ||
170 | /* Unexpected watchdog, stop the watchdog and dump registers*/ | 190 | /* Unexpected watchdog, stop the watchdog and dump registers. */ |
171 | stop_watchdog(); | 191 | stop_watchdog(); |
172 | raw_printk("Oops: bitten by watchdog\n"); | 192 | printk(KERN_WARNING "Oops: bitten by watchdog\n"); |
173 | show_registers(regs); | 193 | show_registers(regs); |
194 | oops_in_progress = 0; | ||
174 | #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | 195 | #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY |
175 | reset_watchdog(); | 196 | reset_watchdog(); |
176 | #endif | 197 | #endif |
@@ -178,21 +199,19 @@ handle_watchdog_bite(struct pt_regs* regs) | |||
178 | #endif | 199 | #endif |
179 | } | 200 | } |
180 | 201 | ||
181 | /* last time the cmos clock got updated */ | 202 | /* Last time the cmos clock got updated. */ |
182 | static long last_rtc_update = 0; | 203 | static long last_rtc_update = 0; |
183 | 204 | ||
184 | /* | 205 | /* |
185 | * timer_interrupt() needs to keep up the real-time clock, | 206 | * timer_interrupt() needs to keep up the real-time clock, |
186 | * as well as call the "do_timer()" routine every clocktick | 207 | * as well as call the "do_timer()" routine every clocktick. |
187 | */ | 208 | */ |
188 | |||
189 | //static unsigned short myjiff; /* used by our debug routine print_timestamp */ | ||
190 | |||
191 | extern void cris_do_profile(struct pt_regs *regs); | 209 | extern void cris_do_profile(struct pt_regs *regs); |
192 | 210 | ||
193 | static inline irqreturn_t | 211 | static inline irqreturn_t |
194 | timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 212 | timer_interrupt(int irq, void *dev_id) |
195 | { | 213 | { |
214 | struct pt_regs *regs = get_irq_regs(); | ||
196 | int cpu = smp_processor_id(); | 215 | int cpu = smp_processor_id(); |
197 | reg_timer_r_masked_intr masked_intr; | 216 | reg_timer_r_masked_intr masked_intr; |
198 | reg_timer_rw_ack_intr ack_intr = { 0 }; | 217 | reg_timer_rw_ack_intr ack_intr = { 0 }; |
@@ -202,11 +221,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
202 | if (!masked_intr.tmr0) | 221 | if (!masked_intr.tmr0) |
203 | return IRQ_NONE; | 222 | return IRQ_NONE; |
204 | 223 | ||
205 | /* acknowledge the timer irq */ | 224 | /* Acknowledge the timer irq. */ |
206 | ack_intr.tmr0 = 1; | 225 | ack_intr.tmr0 = 1; |
207 | REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); | 226 | REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr); |
208 | 227 | ||
209 | /* reset watchdog otherwise it resets us! */ | 228 | /* Reset watchdog otherwise it resets us! */ |
210 | reset_watchdog(); | 229 | reset_watchdog(); |
211 | 230 | ||
212 | /* Update statistics. */ | 231 | /* Update statistics. */ |
@@ -218,7 +237,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
218 | if (cpu != 0) | 237 | if (cpu != 0) |
219 | return IRQ_HANDLED; | 238 | return IRQ_HANDLED; |
220 | 239 | ||
221 | /* call the real timer interrupt handler */ | 240 | /* Call the real timer interrupt handler */ |
222 | do_timer(1); | 241 | do_timer(1); |
223 | 242 | ||
224 | /* | 243 | /* |
@@ -236,17 +255,17 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
236 | if (set_rtc_mmss(xtime.tv_sec) == 0) | 255 | if (set_rtc_mmss(xtime.tv_sec) == 0) |
237 | last_rtc_update = xtime.tv_sec; | 256 | last_rtc_update = xtime.tv_sec; |
238 | else | 257 | else |
239 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | 258 | /* Do it again in 60 s */ |
259 | last_rtc_update = xtime.tv_sec - 600; | ||
240 | } | 260 | } |
241 | return IRQ_HANDLED; | 261 | return IRQ_HANDLED; |
242 | } | 262 | } |
243 | 263 | ||
244 | /* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain | 264 | /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. |
245 | * it needs to be IRQF_DISABLED to make the jiffies update work properly | 265 | * It needs to be IRQF_DISABLED to make the jiffies update work properly. |
246 | */ | 266 | */ |
247 | 267 | static struct irqaction irq_timer = { | |
248 | static struct irqaction irq_timer = { | 268 | .handler = timer_interrupt, |
249 | .mask = timer_interrupt, | ||
250 | .flags = IRQF_SHARED | IRQF_DISABLED, | 269 | .flags = IRQF_SHARED | IRQF_DISABLED, |
251 | .mask = CPU_MASK_NONE, | 270 | .mask = CPU_MASK_NONE, |
252 | .name = "timer" | 271 | .name = "timer" |
@@ -256,27 +275,27 @@ void __init | |||
256 | cris_timer_init(void) | 275 | cris_timer_init(void) |
257 | { | 276 | { |
258 | int cpu = smp_processor_id(); | 277 | int cpu = smp_processor_id(); |
259 | reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; | 278 | reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 }; |
260 | reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; | 279 | reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV; |
261 | reg_timer_rw_intr_mask timer_intr_mask; | 280 | reg_timer_rw_intr_mask timer_intr_mask; |
262 | 281 | ||
263 | /* Setup the etrax timers | 282 | /* Setup the etrax timers. |
264 | * Base frequency is 100MHz, divider 1000000 -> 100 HZ | 283 | * Base frequency is 100MHz, divider 1000000 -> 100 HZ |
265 | * We use timer0, so timer1 is free. | 284 | * We use timer0, so timer1 is free. |
266 | * The trig timer is used by the fasttimer API if enabled. | 285 | * The trig timer is used by the fasttimer API if enabled. |
267 | */ | 286 | */ |
268 | 287 | ||
269 | tmr0_ctrl.op = regk_timer_ld; | 288 | tmr0_ctrl.op = regk_timer_ld; |
270 | tmr0_ctrl.freq = regk_timer_f100; | 289 | tmr0_ctrl.freq = regk_timer_f100; |
271 | REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); | 290 | REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div); |
272 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ | 291 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */ |
273 | tmr0_ctrl.op = regk_timer_run; | 292 | tmr0_ctrl.op = regk_timer_run; |
274 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ | 293 | REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */ |
275 | 294 | ||
276 | /* enable the timer irq */ | 295 | /* Enable the timer irq. */ |
277 | timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); | 296 | timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask); |
278 | timer_intr_mask.tmr0 = 1; | 297 | timer_intr_mask.tmr0 = 1; |
279 | REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); | 298 | REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask); |
280 | } | 299 | } |
281 | 300 | ||
282 | void __init | 301 | void __init |
@@ -284,7 +303,7 @@ time_init(void) | |||
284 | { | 303 | { |
285 | reg_intr_vect_rw_mask intr_mask; | 304 | reg_intr_vect_rw_mask intr_mask; |
286 | 305 | ||
287 | /* probe for the RTC and read it if it exists | 306 | /* Probe for the RTC and read it if it exists. |
288 | * Before the RTC can be probed the loops_per_usec variable needs | 307 | * Before the RTC can be probed the loops_per_usec variable needs |
289 | * to be initialized to make usleep work. A better value for | 308 | * to be initialized to make usleep work. A better value for |
290 | * loops_per_usec is calculated by the kernel later once the | 309 | * loops_per_usec is calculated by the kernel later once the |
@@ -293,52 +312,74 @@ time_init(void) | |||
293 | loops_per_usec = 50; | 312 | loops_per_usec = 50; |
294 | 313 | ||
295 | if(RTC_INIT() < 0) { | 314 | if(RTC_INIT() < 0) { |
296 | /* no RTC, start at 1980 */ | 315 | /* No RTC, start at 1980 */ |
297 | xtime.tv_sec = 0; | 316 | xtime.tv_sec = 0; |
298 | xtime.tv_nsec = 0; | 317 | xtime.tv_nsec = 0; |
299 | have_rtc = 0; | 318 | have_rtc = 0; |
300 | } else { | 319 | } else { |
301 | /* get the current time */ | 320 | /* Get the current time */ |
302 | have_rtc = 1; | 321 | have_rtc = 1; |
303 | update_xtime_from_cmos(); | 322 | update_xtime_from_cmos(); |
304 | } | 323 | } |
305 | 324 | ||
306 | /* | 325 | /* |
307 | * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the | 326 | * Initialize wall_to_monotonic such that adding it to |
308 | * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC). | 327 | * xtime will yield zero, the tv_nsec field must be normalized |
328 | * (i.e., 0 <= nsec < NSEC_PER_SEC). | ||
309 | */ | 329 | */ |
310 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); | 330 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); |
311 | 331 | ||
312 | /* Start CPU local timer */ | 332 | /* Start CPU local timer. */ |
313 | cris_timer_init(); | 333 | cris_timer_init(); |
314 | 334 | ||
315 | /* enable the timer irq in global config */ | 335 | /* Enable the timer irq in global config. */ |
316 | intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); | 336 | intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1); |
317 | intr_mask.timer = 1; | 337 | intr_mask.timer0 = 1; |
318 | REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); | 338 | REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask); |
319 | |||
320 | /* now actually register the timer irq handler that calls timer_interrupt() */ | ||
321 | 339 | ||
322 | setup_irq(TIMER_INTR_VECT, &irq_timer); | 340 | /* Now actually register the timer irq handler that calls |
341 | * timer_interrupt(). */ | ||
342 | setup_irq(TIMER0_INTR_VECT, &irq_timer); | ||
323 | 343 | ||
324 | /* enable watchdog if we should use one */ | 344 | /* Enable watchdog if we should use one. */ |
325 | 345 | ||
326 | #if defined(CONFIG_ETRAX_WATCHDOG) | 346 | #if defined(CONFIG_ETRAX_WATCHDOG) |
327 | printk("Enabling watchdog...\n"); | 347 | printk(KERN_INFO "Enabling watchdog...\n"); |
328 | start_watchdog(); | 348 | start_watchdog(); |
329 | 349 | ||
330 | /* If we use the hardware watchdog, we want to trap it as an NMI | 350 | /* If we use the hardware watchdog, we want to trap it as an NMI |
331 | and dump registers before it resets us. For this to happen, we | 351 | * and dump registers before it resets us. For this to happen, we |
332 | must set the "m" NMI enable flag (which once set, is unset only | 352 | * must set the "m" NMI enable flag (which once set, is unset only |
333 | when an NMI is taken). | 353 | * when an NMI is taken). */ |
334 | 354 | { | |
335 | The same goes for the external NMI, but that doesn't have any | 355 | unsigned long flags; |
336 | driver or infrastructure support yet. */ | 356 | local_save_flags(flags); |
337 | { | 357 | flags |= (1<<30); /* NMI M flag is at bit 30 */ |
338 | unsigned long flags; | 358 | local_irq_restore(flags); |
339 | local_save_flags(flags); | 359 | } |
340 | flags |= (1<<30); /* NMI M flag is at bit 30 */ | 360 | #endif |
341 | local_irq_restore(flags); | 361 | |
342 | } | 362 | #ifdef CONFIG_CPU_FREQ |
363 | cpufreq_register_notifier(&cris_time_freq_notifier_block, | ||
364 | CPUFREQ_TRANSITION_NOTIFIER); | ||
343 | #endif | 365 | #endif |
344 | } | 366 | } |
367 | |||
368 | #ifdef CONFIG_CPU_FREQ | ||
369 | static int | ||
370 | cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
371 | void *data) | ||
372 | { | ||
373 | struct cpufreq_freqs *freqs = data; | ||
374 | if (val == CPUFREQ_POSTCHANGE) { | ||
375 | reg_timer_r_tmr0_data data; | ||
376 | reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ; | ||
377 | do { | ||
378 | data = REG_RD(timer, timer_regs[freqs->cpu], | ||
379 | r_tmr0_data); | ||
380 | } while (data > 20); | ||
381 | REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div); | ||
382 | } | ||
383 | return 0; | ||
384 | } | ||
385 | #endif | ||
diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c index 17fd3dbd1c80..9003e382cada 100644 --- a/arch/cris/arch-v32/kernel/traps.c +++ b/arch/cris/arch-v32/kernel/traps.c | |||
@@ -1,50 +1,45 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2003, Axis Communications AB. | 2 | * Copyright (C) 2003-2006, Axis Communications AB. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/ptrace.h> | 5 | #include <linux/ptrace.h> |
6 | #include <linux/module.h> | ||
6 | #include <asm/uaccess.h> | 7 | #include <asm/uaccess.h> |
7 | 8 | #include <hwregs/supp_reg.h> | |
8 | #include <asm/arch/hwregs/supp_reg.h> | 9 | #include <hwregs/intr_vect_defs.h> |
9 | 10 | #include <asm/irq.h> | |
10 | extern void reset_watchdog(void); | ||
11 | extern void stop_watchdog(void); | ||
12 | |||
13 | extern int raw_printk(const char *fmt, ...); | ||
14 | 11 | ||
15 | void | 12 | void |
16 | show_registers(struct pt_regs *regs) | 13 | show_registers(struct pt_regs *regs) |
17 | { | 14 | { |
18 | /* | 15 | /* |
19 | * It's possible to use either the USP register or current->thread.usp. | 16 | * It's possible to use either the USP register or current->thread.usp. |
20 | * USP might not correspond to the current proccess for all cases this | 17 | * USP might not correspond to the current process for all cases this |
21 | * function is called, and current->thread.usp isn't up to date for the | 18 | * function is called, and current->thread.usp isn't up to date for the |
22 | * current proccess. Experience shows that using USP is the way to go. | 19 | * current process. Experience shows that using USP is the way to go. |
23 | */ | 20 | */ |
24 | unsigned long usp; | 21 | unsigned long usp = rdusp(); |
25 | unsigned long d_mmu_cause; | 22 | unsigned long d_mmu_cause; |
26 | unsigned long i_mmu_cause; | 23 | unsigned long i_mmu_cause; |
27 | 24 | ||
28 | usp = rdusp(); | 25 | printk("CPU: %d\n", smp_processor_id()); |
29 | 26 | ||
30 | raw_printk("CPU: %d\n", smp_processor_id()); | 27 | printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", |
28 | regs->erp, regs->srp, regs->ccs, usp, regs->mof); | ||
31 | 29 | ||
32 | raw_printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", | 30 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", |
33 | regs->erp, regs->srp, regs->ccs, usp, regs->mof); | 31 | regs->r0, regs->r1, regs->r2, regs->r3); |
34 | 32 | ||
35 | raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", | 33 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", |
36 | regs->r0, regs->r1, regs->r2, regs->r3); | 34 | regs->r4, regs->r5, regs->r6, regs->r7); |
37 | 35 | ||
38 | raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | 36 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", |
39 | regs->r4, regs->r5, regs->r6, regs->r7); | 37 | regs->r8, regs->r9, regs->r10, regs->r11); |
40 | 38 | ||
41 | raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | 39 | printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", |
42 | regs->r8, regs->r9, regs->r10, regs->r11); | 40 | regs->r12, regs->r13, regs->orig_r10, regs->acr); |
43 | 41 | ||
44 | raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", | 42 | printk(" sp: %08lx\n", (unsigned long)regs); |
45 | regs->r12, regs->r13, regs->orig_r10, regs->acr); | ||
46 | |||
47 | raw_printk("sp: %08lx\n", regs); | ||
48 | 43 | ||
49 | SUPP_BANK_SEL(BANK_IM); | 44 | SUPP_BANK_SEL(BANK_IM); |
50 | SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); | 45 | SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); |
@@ -52,18 +47,20 @@ show_registers(struct pt_regs *regs) | |||
52 | SUPP_BANK_SEL(BANK_DM); | 47 | SUPP_BANK_SEL(BANK_DM); |
53 | SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); | 48 | SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); |
54 | 49 | ||
55 | raw_printk(" Data MMU Cause: %08lx\n", d_mmu_cause); | 50 | printk(" Data MMU Cause: %08lx\n", d_mmu_cause); |
56 | raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); | 51 | printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); |
57 | 52 | ||
58 | raw_printk("Process %s (pid: %d, stackpage: %08lx)\n", | 53 | printk("Process %s (pid: %d, stackpage=%08lx)\n", |
59 | current->comm, current->pid, (unsigned long) current); | 54 | current->comm, current->pid, (unsigned long)current); |
60 | 55 | ||
61 | /* Show additional info if in kernel-mode. */ | 56 | /* |
57 | * When in-kernel, we also print out the stack and code at the | ||
58 | * time of the fault.. | ||
59 | */ | ||
62 | if (!user_mode(regs)) { | 60 | if (!user_mode(regs)) { |
63 | int i; | 61 | int i; |
64 | unsigned char c; | ||
65 | 62 | ||
66 | show_stack(NULL, (unsigned long *) usp); | 63 | show_stack(NULL, (unsigned long *)usp); |
67 | 64 | ||
68 | /* | 65 | /* |
69 | * If the previous stack-dump wasn't a kernel one, dump the | 66 | * If the previous stack-dump wasn't a kernel one, dump the |
@@ -72,7 +69,7 @@ show_registers(struct pt_regs *regs) | |||
72 | if (usp != 0) | 69 | if (usp != 0) |
73 | show_stack(NULL, NULL); | 70 | show_stack(NULL, NULL); |
74 | 71 | ||
75 | raw_printk("\nCode: "); | 72 | printk("\nCode: "); |
76 | 73 | ||
77 | if (regs->erp < PAGE_OFFSET) | 74 | if (regs->erp < PAGE_OFFSET) |
78 | goto bad_value; | 75 | goto bad_value; |
@@ -84,76 +81,115 @@ show_registers(struct pt_regs *regs) | |||
84 | * instruction decoding should be in sync at the interesting | 81 | * instruction decoding should be in sync at the interesting |
85 | * point, but small enough to fit on a row. The regs->erp | 82 | * point, but small enough to fit on a row. The regs->erp |
86 | * location is pointed out in a ksymoops-friendly way by | 83 | * location is pointed out in a ksymoops-friendly way by |
87 | * wrapping the byte for that address in parenthesis. | 84 | * wrapping the byte for that address in parenthesises. |
88 | */ | 85 | */ |
89 | for (i = -12; i < 12; i++) { | 86 | for (i = -12; i < 12; i++) { |
90 | if (__get_user(c, &((unsigned char *) regs->erp)[i])) { | 87 | unsigned char c; |
88 | |||
89 | if (__get_user(c, &((unsigned char *)regs->erp)[i])) { | ||
91 | bad_value: | 90 | bad_value: |
92 | raw_printk(" Bad IP value."); | 91 | printk(" Bad IP value."); |
93 | break; | 92 | break; |
94 | } | 93 | } |
95 | 94 | ||
96 | if (i == 0) | 95 | if (i == 0) |
97 | raw_printk("(%02x) ", c); | 96 | printk("(%02x) ", c); |
98 | else | 97 | else |
99 | raw_printk("%02x ", c); | 98 | printk("%02x ", c); |
100 | } | 99 | } |
101 | 100 | printk("\n"); | |
102 | raw_printk("\n"); | ||
103 | } | 101 | } |
104 | } | 102 | } |
105 | 103 | ||
106 | /* | ||
107 | * This gets called from entry.S when the watchdog has bitten. Show something | ||
108 | * similar to an Oops dump, and if the kernel is configured to be a nice doggy; | ||
109 | * halt instead of reboot. | ||
110 | */ | ||
111 | void | 104 | void |
112 | watchdog_bite_hook(struct pt_regs *regs) | 105 | arch_enable_nmi(void) |
113 | { | 106 | { |
114 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | 107 | unsigned long flags; |
115 | local_irq_disable(); | ||
116 | stop_watchdog(); | ||
117 | show_registers(regs); | ||
118 | 108 | ||
119 | while (1) | 109 | local_save_flags(flags); |
120 | ; /* Do nothing. */ | 110 | flags |= (1 << 30); /* NMI M flag is at bit 30 */ |
121 | #else | 111 | local_irq_restore(flags); |
122 | show_registers(regs); | ||
123 | #endif | ||
124 | } | 112 | } |
125 | 113 | ||
126 | /* This is normally the Oops function. */ | 114 | extern void (*nmi_handler)(struct pt_regs *); |
127 | void | 115 | void handle_nmi(struct pt_regs *regs) |
128 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | ||
129 | { | 116 | { |
130 | if (user_mode(regs)) | 117 | #ifdef CONFIG_ETRAXFS |
131 | return; | 118 | reg_intr_vect_r_nmi r; |
119 | #endif | ||
132 | 120 | ||
133 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | 121 | if (nmi_handler) |
134 | /* | 122 | nmi_handler(regs); |
135 | * This printout might take too long and could trigger | 123 | |
136 | * the watchdog normally. If NICE_DOGGY is set, simply | 124 | #ifdef CONFIG_ETRAXFS |
137 | * stop the watchdog during the printout. | 125 | /* Wait until nmi is no longer active. */ |
138 | */ | 126 | do { |
139 | stop_watchdog(); | 127 | r = REG_RD(intr_vect, regi_irq, r_nmi); |
128 | } while (r.ext == regk_intr_vect_on); | ||
140 | #endif | 129 | #endif |
130 | } | ||
141 | 131 | ||
142 | raw_printk("%s: %04lx\n", str, err & 0xffff); | ||
143 | 132 | ||
144 | show_registers(regs); | 133 | #ifdef CONFIG_BUG |
134 | extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); | ||
145 | 135 | ||
146 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | 136 | /* Copy of the regs at BUG() time. */ |
147 | reset_watchdog(); | 137 | struct pt_regs BUG_regs; |
148 | #endif | ||
149 | 138 | ||
150 | do_exit(SIGSEGV); | 139 | void do_BUG(char *file, unsigned int line) |
140 | { | ||
141 | printk("kernel BUG at %s:%d!\n", file, line); | ||
142 | die_if_kernel("Oops", &BUG_regs, 0); | ||
151 | } | 143 | } |
144 | EXPORT_SYMBOL(do_BUG); | ||
152 | 145 | ||
153 | void arch_enable_nmi(void) | 146 | void fixup_BUG(struct pt_regs *regs) |
154 | { | 147 | { |
155 | unsigned long flags; | 148 | BUG_regs = *regs; |
156 | local_save_flags(flags); | 149 | |
157 | flags |= (1<<30); /* NMI M flag is at bit 30 */ | 150 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
158 | local_irq_restore(flags); | 151 | /* |
152 | * Fixup the BUG arguments through exception handlers. | ||
153 | */ | ||
154 | { | ||
155 | const struct exception_table_entry *fixup; | ||
156 | |||
157 | /* | ||
158 | * ERP points at the "break 14" + 2, compensate for the 2 | ||
159 | * bytes. | ||
160 | */ | ||
161 | fixup = search_exception_tables(instruction_pointer(regs) - 2); | ||
162 | if (fixup) { | ||
163 | /* Adjust the instruction pointer in the stackframe. */ | ||
164 | instruction_pointer(regs) = fixup->fixup; | ||
165 | arch_fixup(regs); | ||
166 | } | ||
167 | } | ||
168 | #else | ||
169 | /* Dont try to lookup the filename + line, just dump regs. */ | ||
170 | do_BUG("unknown", 0); | ||
171 | #endif | ||
159 | } | 172 | } |
173 | |||
174 | /* | ||
175 | * Break 14 handler. Save regs and jump into the fixup_BUG. | ||
176 | */ | ||
177 | __asm__ ( ".text\n\t" | ||
178 | ".global breakh_BUG\n\t" | ||
179 | "breakh_BUG:\n\t" | ||
180 | SAVE_ALL | ||
181 | KGDB_FIXUP | ||
182 | "move.d $sp, $r10\n\t" | ||
183 | "jsr fixup_BUG\n\t" | ||
184 | "nop\n\t" | ||
185 | "jump ret_from_intr\n\t" | ||
186 | "nop\n\t"); | ||
187 | |||
188 | |||
189 | #ifdef CONFIG_DEBUG_BUGVERBOSE | ||
190 | void | ||
191 | handle_BUG(struct pt_regs *regs) | ||
192 | { | ||
193 | } | ||
194 | #endif | ||
195 | #endif | ||
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.c b/arch/cris/arch-v32/kernel/vcs_hook.c deleted file mode 100644 index 64d71c54c22c..000000000000 --- a/arch/cris/arch-v32/kernel/vcs_hook.c +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
1 | // $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $ | ||
2 | // | ||
3 | // Call simulator hook. This is the part running in the | ||
4 | // simulated program. | ||
5 | // | ||
6 | |||
7 | #include "vcs_hook.h" | ||
8 | #include <stdarg.h> | ||
9 | #include <asm/arch-v32/hwregs/reg_map.h> | ||
10 | #include <asm/arch-v32/hwregs/intr_vect_defs.h> | ||
11 | |||
12 | #define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */ | ||
13 | #define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */ | ||
14 | |||
15 | #define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset] | ||
16 | #define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset] | ||
17 | #define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } while(0) | ||
18 | #define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset] | ||
19 | |||
20 | |||
21 | // ------------------------------------------------------------------ hook_call | ||
22 | int hook_call( unsigned id, unsigned pcnt, ...) { | ||
23 | va_list ap; | ||
24 | unsigned i; | ||
25 | unsigned ret; | ||
26 | #ifdef USING_SOS | ||
27 | PREEMPT_OFF_SAVE(); | ||
28 | #endif | ||
29 | |||
30 | // pass parameters | ||
31 | HOOK_DATA(0) = id; | ||
32 | |||
33 | /* Have to make hook_print_str a special case since we call with a | ||
34 | parameter of byte type. Should perhaps be a separate | ||
35 | hook_call. */ | ||
36 | |||
37 | if (id == hook_print_str) { | ||
38 | int i; | ||
39 | char *str; | ||
40 | |||
41 | HOOK_DATA(1) = pcnt; | ||
42 | |||
43 | va_start(ap, pcnt); | ||
44 | str = (char*)va_arg(ap,unsigned); | ||
45 | |||
46 | for (i=0; i!=pcnt; i++) { | ||
47 | HOOK_DATA_BYTE(8+i) = str[i]; | ||
48 | } | ||
49 | HOOK_DATA_BYTE(8+i) = 0; /* null byte */ | ||
50 | } | ||
51 | else { | ||
52 | va_start(ap, pcnt); | ||
53 | for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned); | ||
54 | va_end(ap); | ||
55 | } | ||
56 | |||
57 | // read from mem to make sure data has propagated to memory before trigging | ||
58 | *((volatile unsigned*) HOOK_MEM_BASE_ADDR); | ||
59 | |||
60 | // trigger hook | ||
61 | HOOK_TRIG(id); | ||
62 | |||
63 | // wait for call to finish | ||
64 | while( VHOOK_DATA(0) > 0 ) {} | ||
65 | |||
66 | // extract return value | ||
67 | |||
68 | ret = VHOOK_DATA(1); | ||
69 | |||
70 | #ifdef USING_SOS | ||
71 | PREEMPT_RESTORE(); | ||
72 | #endif | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | unsigned | ||
77 | hook_buf(unsigned i) | ||
78 | { | ||
79 | return (HOOK_DATA(i)); | ||
80 | } | ||
81 | |||
82 | void print_str( const char *str ) { | ||
83 | int i; | ||
84 | for (i=1; str[i]; i++); /* find null at end of string */ | ||
85 | hook_call(hook_print_str, i, str); | ||
86 | } | ||
87 | |||
88 | // --------------------------------------------------------------- CPU_KICK_DOG | ||
89 | void CPU_KICK_DOG(void) { | ||
90 | (void) hook_call( hook_kick_dog, 0 ); | ||
91 | } | ||
92 | |||
93 | // ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT | ||
94 | void CPU_WATCHDOG_TIMEOUT( unsigned t ) { | ||
95 | (void) hook_call( hook_dog_timeout, 1, t ); | ||
96 | } | ||
diff --git a/arch/cris/arch-v32/lib/Makefile b/arch/cris/arch-v32/lib/Makefile index 05b3ec6978d6..eb4aad1f1158 100644 --- a/arch/cris/arch-v32/lib/Makefile +++ b/arch/cris/arch-v32/lib/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | # Makefile for Etrax-specific library files.. | 2 | # Makefile for Etrax-specific library files.. |
3 | # | 3 | # |
4 | 4 | ||
5 | lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o spinlock.o | 5 | lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o \ |
6 | csumcpfruser.o spinlock.o delay.o | ||
6 | 7 | ||
diff --git a/arch/cris/arch-v32/lib/checksum.S b/arch/cris/arch-v32/lib/checksum.S index 32e66181b826..87f3fd71ab10 100644 --- a/arch/cris/arch-v32/lib/checksum.S +++ b/arch/cris/arch-v32/lib/checksum.S | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * A fast checksum routine using movem | 2 | * A fast checksum routine using movem |
3 | * Copyright (c) 1998-2001, 2003 Axis Communications AB | 3 | * Copyright (c) 1998-2007 Axis Communications AB |
4 | * | 4 | * |
5 | * csum_partial(const unsigned char * buff, int len, unsigned int sum) | 5 | * csum_partial(const unsigned char * buff, int len, unsigned int sum) |
6 | */ | 6 | */ |
@@ -12,30 +12,23 @@ csum_partial: | |||
12 | ;; r11 - length | 12 | ;; r11 - length |
13 | ;; r12 - checksum | 13 | ;; r12 - checksum |
14 | 14 | ||
15 | ;; check for breakeven length between movem and normal word looping versions | 15 | ;; Optimized for large packets |
16 | ;; we also do _NOT_ want to compute a checksum over more than the | 16 | subq 10*4, $r11 |
17 | ;; actual length when length < 40 | 17 | blt _word_loop |
18 | 18 | move.d $r11, $acr | |
19 | cmpu.w 80,$r11 | ||
20 | blo _word_loop | ||
21 | nop | ||
22 | |||
23 | ;; need to save the registers we use below in the movem loop | ||
24 | ;; this overhead is why we have a check above for breakeven length | ||
25 | ;; only r0 - r8 have to be saved, the other ones are clobber-able | ||
26 | ;; according to the ABI | ||
27 | 19 | ||
28 | subq 9*4,$sp | 20 | subq 9*4,$sp |
29 | subq 10*4,$r11 ; update length for the first loop | 21 | clearf c |
30 | movem $r8,[$sp] | 22 | movem $r8,[$sp] |
31 | 23 | ||
32 | ;; do a movem checksum | 24 | ;; do a movem checksum |
33 | 25 | ||
34 | _mloop: movem [$r10+],$r9 ; read 10 longwords | 26 | _mloop: movem [$r10+],$r9 ; read 10 longwords |
35 | 27 | ;; Loop count without touching the c flag. | |
28 | addoq -10*4, $acr, $acr | ||
36 | ;; perform dword checksumming on the 10 longwords | 29 | ;; perform dword checksumming on the 10 longwords |
37 | 30 | ||
38 | add.d $r0,$r12 | 31 | addc $r0,$r12 |
39 | addc $r1,$r12 | 32 | addc $r1,$r12 |
40 | addc $r2,$r12 | 33 | addc $r2,$r12 |
41 | addc $r3,$r12 | 34 | addc $r3,$r12 |
@@ -46,60 +39,41 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords | |||
46 | addc $r8,$r12 | 39 | addc $r8,$r12 |
47 | addc $r9,$r12 | 40 | addc $r9,$r12 |
48 | 41 | ||
49 | ;; fold the carry into the checksum, to avoid having to loop the carry | 42 | ;; test $acr without trashing carry. |
50 | ;; back into the top | 43 | move.d $acr, $acr |
51 | 44 | bpl _mloop | |
52 | addc 0,$r12 | 45 | ;; r11 <= acr is not really needed in the mloop, just using the dslot |
53 | addc 0,$r12 ; do it again, since we might have generated a carry | 46 | ;; to prepare for what is needed after mloop. |
54 | 47 | move.d $acr, $r11 | |
55 | subq 10*4,$r11 | ||
56 | bge _mloop | ||
57 | nop | ||
58 | |||
59 | addq 10*4,$r11 ; compensate for last loop underflowing length | ||
60 | 48 | ||
49 | ;; fold the last carry into r13 | ||
50 | addc 0, $r12 | ||
61 | movem [$sp+],$r8 ; restore regs | 51 | movem [$sp+],$r8 ; restore regs |
62 | 52 | ||
63 | _word_loop: | 53 | _word_loop: |
64 | ;; only fold if there is anything to fold. | 54 | addq 10*4,$r11 ; compensate for last loop underflowing length |
65 | |||
66 | cmpq 0,$r12 | ||
67 | beq _no_fold | ||
68 | |||
69 | ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below. | ||
70 | ;; r9 and r13 can be used as temporaries. | ||
71 | 55 | ||
72 | moveq -1,$r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 | 56 | moveq -1,$r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 |
73 | lsrq 16,$r9 | 57 | lsrq 16,$r9 |
74 | 58 | ||
75 | move.d $r12,$r13 | 59 | move.d $r12,$r13 |
76 | lsrq 16,$r13 ; r13 = checksum >> 16 | 60 | lsrq 16,$r13 ; r13 = checksum >> 16 |
77 | and.d $r9,$r12 ; checksum = checksum & 0xffff | 61 | and.d $r9,$r12 ; checksum = checksum & 0xffff |
78 | add.d $r13,$r12 ; checksum += r13 | ||
79 | move.d $r12,$r13 ; do the same again, maybe we got a carry last add | ||
80 | lsrq 16,$r13 | ||
81 | and.d $r9,$r12 | ||
82 | add.d $r13,$r12 | ||
83 | 62 | ||
84 | _no_fold: | 63 | _no_fold: |
85 | cmpq 2,$r11 | 64 | subq 2,$r11 |
86 | blt _no_words | 65 | blt _no_words |
87 | nop | 66 | add.d $r13,$r12 ; checksum += r13 |
88 | 67 | ||
89 | ;; checksum the rest of the words | 68 | ;; checksum the rest of the words |
90 | |||
91 | subq 2,$r11 | ||
92 | |||
93 | _wloop: subq 2,$r11 | 69 | _wloop: subq 2,$r11 |
94 | bge _wloop | 70 | bge _wloop |
95 | addu.w [$r10+],$r12 | 71 | addu.w [$r10+],$r12 |
96 | 72 | ||
97 | addq 2,$r11 | ||
98 | |||
99 | _no_words: | 73 | _no_words: |
74 | addq 2,$r11 | ||
100 | ;; see if we have one odd byte more | 75 | ;; see if we have one odd byte more |
101 | cmpq 1,$r11 | 76 | bne _do_byte |
102 | beq _do_byte | ||
103 | nop | 77 | nop |
104 | ret | 78 | ret |
105 | move.d $r12,$r10 | 79 | move.d $r12,$r10 |
diff --git a/arch/cris/arch-v32/lib/checksumcopy.S b/arch/cris/arch-v32/lib/checksumcopy.S index 9303ccbadc6d..21aabe91489b 100644 --- a/arch/cris/arch-v32/lib/checksumcopy.S +++ b/arch/cris/arch-v32/lib/checksumcopy.S | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * A fast checksum+copy routine using movem | 2 | * A fast checksum+copy routine using movem |
3 | * Copyright (c) 1998, 2001, 2003 Axis Communications AB | 3 | * Copyright (c) 1998-2007 Axis Communications AB |
4 | * | 4 | * |
5 | * Authors: Bjorn Wesen | 5 | * Authors: Bjorn Wesen |
6 | * | 6 | * |
@@ -16,32 +16,23 @@ csum_partial_copy_nocheck: | |||
16 | ;; r12 - length | 16 | ;; r12 - length |
17 | ;; r13 - checksum | 17 | ;; r13 - checksum |
18 | 18 | ||
19 | ;; check for breakeven length between movem and normal word looping versions | 19 | ;; Optimized for large packets |
20 | ;; we also do _NOT_ want to compute a checksum over more than the | 20 | subq 10*4, $r12 |
21 | ;; actual length when length < 40 | 21 | blt _word_loop |
22 | 22 | move.d $r12, $acr | |
23 | cmpu.w 80,$r12 | ||
24 | blo _word_loop | ||
25 | nop | ||
26 | |||
27 | ;; need to save the registers we use below in the movem loop | ||
28 | ;; this overhead is why we have a check above for breakeven length | ||
29 | ;; only r0 - r8 have to be saved, the other ones are clobber-able | ||
30 | ;; according to the ABI | ||
31 | 23 | ||
32 | subq 9*4,$sp | 24 | subq 9*4,$sp |
33 | subq 10*4,$r12 ; update length for the first loop | 25 | clearf c |
34 | movem $r8,[$sp] | 26 | movem $r8,[$sp] |
35 | 27 | ||
36 | ;; do a movem copy and checksum | 28 | ;; do a movem copy and checksum |
37 | |||
38 | 1: ;; A failing userspace access (the read) will have this as PC. | 29 | 1: ;; A failing userspace access (the read) will have this as PC. |
39 | _mloop: movem [$r10+],$r9 ; read 10 longwords | 30 | _mloop: movem [$r10+],$r9 ; read 10 longwords |
31 | addoq -10*4, $acr, $acr ; loop counter in latency cycle | ||
40 | movem $r9,[$r11+] ; write 10 longwords | 32 | movem $r9,[$r11+] ; write 10 longwords |
41 | 33 | ||
42 | ;; perform dword checksumming on the 10 longwords | 34 | ;; perform dword checksumming on the 10 longwords |
43 | 35 | addc $r0,$r13 | |
44 | add.d $r0,$r13 | ||
45 | addc $r1,$r13 | 36 | addc $r1,$r13 |
46 | addc $r2,$r13 | 37 | addc $r2,$r13 |
47 | addc $r3,$r13 | 38 | addc $r3,$r13 |
@@ -52,47 +43,30 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords | |||
52 | addc $r8,$r13 | 43 | addc $r8,$r13 |
53 | addc $r9,$r13 | 44 | addc $r9,$r13 |
54 | 45 | ||
55 | ;; fold the carry into the checksum, to avoid having to loop the carry | 46 | ;; test $acr, without trashing carry. |
56 | ;; back into the top | 47 | move.d $acr, $acr |
57 | 48 | bpl _mloop | |
58 | addc 0,$r13 | 49 | ;; r12 <= acr is needed after mloop and in the exception handlers. |
59 | addc 0,$r13 ; do it again, since we might have generated a carry | 50 | move.d $acr, $r12 |
60 | |||
61 | subq 10*4,$r12 | ||
62 | bge _mloop | ||
63 | nop | ||
64 | |||
65 | addq 10*4,$r12 ; compensate for last loop underflowing length | ||
66 | 51 | ||
52 | ;; fold the last carry into r13 | ||
53 | addc 0, $r13 | ||
67 | movem [$sp+],$r8 ; restore regs | 54 | movem [$sp+],$r8 ; restore regs |
68 | 55 | ||
69 | _word_loop: | 56 | _word_loop: |
70 | ;; only fold if there is anything to fold. | 57 | addq 10*4,$r12 ; compensate for last loop underflowing length |
71 | |||
72 | cmpq 0,$r13 | ||
73 | beq _no_fold | ||
74 | 58 | ||
75 | ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below | 59 | ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below |
76 | ;; r9 can be used as temporary. | 60 | ;; r9 can be used as temporary. |
77 | |||
78 | move.d $r13,$r9 | 61 | move.d $r13,$r9 |
79 | lsrq 16,$r9 ; r0 = checksum >> 16 | 62 | lsrq 16,$r9 ; r0 = checksum >> 16 |
80 | and.d 0xffff,$r13 ; checksum = checksum & 0xffff | 63 | and.d 0xffff,$r13 ; checksum = checksum & 0xffff |
81 | add.d $r9,$r13 ; checksum += r0 | ||
82 | move.d $r13,$r9 ; do the same again, maybe we got a carry last add | ||
83 | lsrq 16,$r9 | ||
84 | and.d 0xffff,$r13 | ||
85 | add.d $r9,$r13 | ||
86 | 64 | ||
87 | _no_fold: | 65 | subq 2, $r12 |
88 | cmpq 2,$r12 | ||
89 | blt _no_words | 66 | blt _no_words |
90 | nop | 67 | add.d $r9,$r13 ; checksum += r0 |
91 | 68 | ||
92 | ;; copy and checksum the rest of the words | 69 | ;; copy and checksum the rest of the words |
93 | |||
94 | subq 2,$r12 | ||
95 | |||
96 | 2: ;; A failing userspace access for the read below will have this as PC. | 70 | 2: ;; A failing userspace access for the read below will have this as PC. |
97 | _wloop: move.w [$r10+],$r9 | 71 | _wloop: move.w [$r10+],$r9 |
98 | addu.w $r9,$r13 | 72 | addu.w $r9,$r13 |
@@ -100,12 +74,9 @@ _wloop: move.w [$r10+],$r9 | |||
100 | bge _wloop | 74 | bge _wloop |
101 | move.w $r9,[$r11+] | 75 | move.w $r9,[$r11+] |
102 | 76 | ||
103 | addq 2,$r12 | ||
104 | |||
105 | _no_words: | 77 | _no_words: |
106 | ;; see if we have one odd byte more | 78 | addq 2,$r12 |
107 | cmpq 1,$r12 | 79 | bne _do_byte |
108 | beq _do_byte | ||
109 | nop | 80 | nop |
110 | ret | 81 | ret |
111 | move.d $r13,$r10 | 82 | move.d $r13,$r10 |
diff --git a/arch/cris/arch-v32/lib/delay.c b/arch/cris/arch-v32/lib/delay.c new file mode 100644 index 000000000000..39f1ac9995b4 --- /dev/null +++ b/arch/cris/arch-v32/lib/delay.c | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Precise Delay Loops for ETRAX FS | ||
3 | * | ||
4 | * Copyright (C) 2006 Axis Communications AB. | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <hwregs/reg_map.h> | ||
9 | #include <hwregs/reg_rdwr.h> | ||
10 | #include <hwregs/timer_defs.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | /* | ||
16 | * On ETRAX FS, we can check the free-running read-only 100MHz timer | ||
17 | * getting 32-bit 10ns precision, theoretically good for 42.94967295 | ||
18 | * seconds. Unsigned arithmetic and careful expression handles | ||
19 | * wrapping. | ||
20 | */ | ||
21 | |||
22 | void cris_delay10ns(u32 n10ns) | ||
23 | { | ||
24 | u32 t0 = REG_RD(timer, regi_timer0, r_time); | ||
25 | while (REG_RD(timer, regi_timer0, r_time) - t0 < n10ns) | ||
26 | ; | ||
27 | } | ||
28 | EXPORT_SYMBOL(cris_delay10ns); | ||
diff --git a/arch/cris/arch-v32/lib/spinlock.S b/arch/cris/arch-v32/lib/spinlock.S index 2437ae7f6ed2..79087ef59a1c 100644 --- a/arch/cris/arch-v32/lib/spinlock.S +++ b/arch/cris/arch-v32/lib/spinlock.S | |||
@@ -12,11 +12,11 @@ | |||
12 | 12 | ||
13 | cris_spin_lock: | 13 | cris_spin_lock: |
14 | clearf p | 14 | clearf p |
15 | 1: test.d [$r10] | 15 | 1: test.b [$r10] |
16 | beq 1b | 16 | beq 1b |
17 | clearf p | 17 | clearf p |
18 | ax | 18 | ax |
19 | clear.d [$r10] | 19 | clear.b [$r10] |
20 | bcs 1b | 20 | bcs 1b |
21 | clearf p | 21 | clearf p |
22 | ret | 22 | ret |
@@ -24,10 +24,10 @@ cris_spin_lock: | |||
24 | 24 | ||
25 | cris_spin_trylock: | 25 | cris_spin_trylock: |
26 | clearf p | 26 | clearf p |
27 | 1: move.d [$r10], $r11 | 27 | 1: move.b [$r10], $r11 |
28 | ax | 28 | ax |
29 | clear.d [$r10] | 29 | clear.b [$r10] |
30 | bcs 1b | 30 | bcs 1b |
31 | clearf p | 31 | clearf p |
32 | ret | 32 | ret |
33 | move.d $r11,$r10 | 33 | movu.b $r11,$r10 |
diff --git a/arch/cris/arch-v32/mach-a3/Kconfig b/arch/cris/arch-v32/mach-a3/Kconfig new file mode 100644 index 000000000000..a4df06d5997a --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/Kconfig | |||
@@ -0,0 +1,110 @@ | |||
1 | if CRIS_MACH_ARTPEC3 | ||
2 | |||
3 | menu "Artpec-3 options" | ||
4 | depends on CRIS_MACH_ARTPEC3 | ||
5 | |||
6 | config ETRAX_DRAM_VIRTUAL_BASE | ||
7 | hex | ||
8 | default "c0000000" | ||
9 | |||
10 | config ETRAX_L2CACHE | ||
11 | bool | ||
12 | default y | ||
13 | |||
14 | config ETRAX_SERIAL_PORTS | ||
15 | int | ||
16 | default 5 | ||
17 | |||
18 | config ETRAX_DDR | ||
19 | bool | ||
20 | default y | ||
21 | |||
22 | config ETRAX_DDR2_MRS | ||
23 | hex "DDR2 MRS" | ||
24 | default "0" | ||
25 | |||
26 | config ETRAX_DDR2_TIMING | ||
27 | hex "DDR2 SDRAM timing" | ||
28 | default "0" | ||
29 | help | ||
30 | SDRAM timing parameters. | ||
31 | |||
32 | config ETRAX_DDR2_CONFIG | ||
33 | hex "DDR2 config" | ||
34 | default "0" | ||
35 | |||
36 | config ETRAX_PIO_CE0_CFG | ||
37 | hex "PIO CE0 configuration" | ||
38 | default "0" | ||
39 | |||
40 | config ETRAX_PIO_CE1_CFG | ||
41 | hex "PIO CE1 configuration" | ||
42 | default "0" | ||
43 | |||
44 | config ETRAX_PIO_CE2_CFG | ||
45 | hex "PIO CE2 configuration" | ||
46 | default "0" | ||
47 | |||
48 | config ETRAX_DEF_GIO_PA_OE | ||
49 | hex "GIO_PA_OE" | ||
50 | default "00000000" | ||
51 | help | ||
52 | Configures the direction of general port A bits. 1 is out, 0 is in. | ||
53 | This is often totally different depending on the product used. | ||
54 | There are some guidelines though - if you know that only LED's are | ||
55 | connected to port PA, then they are usually connected to bits 2-4 | ||
56 | and you can therefore use 1c. On other boards which don't have the | ||
57 | LED's at the general ports, these bits are used for all kinds of | ||
58 | stuff. If you don't know what to use, it is always safe to put all | ||
59 | as inputs, although floating inputs isn't good. | ||
60 | |||
61 | config ETRAX_DEF_GIO_PA_OUT | ||
62 | hex "GIO_PA_OUT" | ||
63 | default "00000000" | ||
64 | help | ||
65 | Configures the initial data for the general port A bits. Most | ||
66 | products should use 00 here. | ||
67 | |||
68 | config ETRAX_DEF_GIO_PB_OE | ||
69 | hex "GIO_PB_OE" | ||
70 | default "000000000" | ||
71 | help | ||
72 | Configures the direction of general port B bits. 1 is out, 0 is in. | ||
73 | This is often totally different depending on the product used. | ||
74 | There are some guidelines though - if you know that only LED's are | ||
75 | connected to port PA, then they are usually connected to bits 2-4 | ||
76 | and you can therefore use 1c. On other boards which don't have the | ||
77 | LED's at the general ports, these bits are used for all kinds of | ||
78 | stuff. If you don't know what to use, it is always safe to put all | ||
79 | as inputs, although floating inputs isn't good. | ||
80 | |||
81 | config ETRAX_DEF_GIO_PB_OUT | ||
82 | hex "GIO_PB_OUT" | ||
83 | default "000000000" | ||
84 | help | ||
85 | Configures the initial data for the general port B bits. Most | ||
86 | products should use 00000 here. | ||
87 | |||
88 | config ETRAX_DEF_GIO_PC_OE | ||
89 | hex "GIO_PC_OE" | ||
90 | default "00000" | ||
91 | help | ||
92 | Configures the direction of general port C bits. 1 is out, 0 is in. | ||
93 | This is often totally different depending on the product used. | ||
94 | There are some guidelines though - if you know that only LED's are | ||
95 | connected to port PA, then they are usually connected to bits 2-4 | ||
96 | and you can therefore use 1c. On other boards which don't have the | ||
97 | LED's at the general ports, these bits are used for all kinds of | ||
98 | stuff. If you don't know what to use, it is always safe to put all | ||
99 | as inputs, although floating inputs isn't good. | ||
100 | |||
101 | config ETRAX_DEF_GIO_PC_OUT | ||
102 | hex "GIO_PC_OUT" | ||
103 | default "00000" | ||
104 | help | ||
105 | Configures the initial data for the general port C bits. Most | ||
106 | products should use 00000 here. | ||
107 | |||
108 | endmenu | ||
109 | |||
110 | endif | ||
diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile new file mode 100644 index 000000000000..41fa6a6893a9 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | obj-y := dma.o pinmux.o io.o arbiter.o | ||
7 | obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o | ||
8 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
9 | |||
10 | clean: | ||
11 | |||
diff --git a/arch/cris/arch-v32/mach-a3/arbiter.c b/arch/cris/arch-v32/mach-a3/arbiter.c new file mode 100644 index 000000000000..8b924db71c9a --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/arbiter.c | |||
@@ -0,0 +1,634 @@ | |||
1 | /* | ||
2 | * Memory arbiter functions. Allocates bandwidth through the | ||
3 | * arbiter and sets up arbiter breakpoints. | ||
4 | * | ||
5 | * The algorithm first assigns slots to the clients that has specified | ||
6 | * bandwidth (e.g. ethernet) and then the remaining slots are divided | ||
7 | * on all the active clients. | ||
8 | * | ||
9 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
10 | * | ||
11 | * The artpec-3 has two arbiters. The memory hierarchy looks like this: | ||
12 | * | ||
13 | * | ||
14 | * CPU DMAs | ||
15 | * | | | ||
16 | * | | | ||
17 | * -------------- ------------------ | ||
18 | * | foo arbiter|----| Internal memory| | ||
19 | * -------------- ------------------ | ||
20 | * | | ||
21 | * -------------- | ||
22 | * | L2 cache | | ||
23 | * -------------- | ||
24 | * | | ||
25 | * h264 etc | | ||
26 | * | | | ||
27 | * | | | ||
28 | * -------------- | ||
29 | * | bar arbiter| | ||
30 | * -------------- | ||
31 | * | | ||
32 | * --------- | ||
33 | * | SDRAM | | ||
34 | * --------- | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include <hwregs/reg_map.h> | ||
39 | #include <hwregs/reg_rdwr.h> | ||
40 | #include <hwregs/marb_foo_defs.h> | ||
41 | #include <hwregs/marb_bar_defs.h> | ||
42 | #include <arbiter.h> | ||
43 | #include <hwregs/intr_vect.h> | ||
44 | #include <linux/interrupt.h> | ||
45 | #include <linux/irq.h> | ||
46 | #include <linux/signal.h> | ||
47 | #include <linux/errno.h> | ||
48 | #include <linux/spinlock.h> | ||
49 | #include <asm/io.h> | ||
50 | #include <asm/irq_regs.h> | ||
51 | |||
52 | #define D(x) | ||
53 | |||
54 | struct crisv32_watch_entry { | ||
55 | unsigned long instance; | ||
56 | watch_callback *cb; | ||
57 | unsigned long start; | ||
58 | unsigned long end; | ||
59 | int used; | ||
60 | }; | ||
61 | |||
62 | #define NUMBER_OF_BP 4 | ||
63 | #define SDRAM_BANDWIDTH 400000000 | ||
64 | #define INTMEM_BANDWIDTH 400000000 | ||
65 | #define NBR_OF_SLOTS 64 | ||
66 | #define NBR_OF_REGIONS 2 | ||
67 | #define NBR_OF_CLIENTS 15 | ||
68 | #define ARBITERS 2 | ||
69 | #define UNASSIGNED 100 | ||
70 | |||
71 | struct arbiter { | ||
72 | unsigned long instance; | ||
73 | int nbr_regions; | ||
74 | int nbr_clients; | ||
75 | int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
76 | int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
77 | }; | ||
78 | |||
79 | static struct crisv32_watch_entry watches[ARBITERS][NUMBER_OF_BP] = | ||
80 | { | ||
81 | { | ||
82 | {regi_marb_foo_bp0}, | ||
83 | {regi_marb_foo_bp1}, | ||
84 | {regi_marb_foo_bp2}, | ||
85 | {regi_marb_foo_bp3} | ||
86 | }, | ||
87 | { | ||
88 | {regi_marb_bar_bp0}, | ||
89 | {regi_marb_bar_bp1}, | ||
90 | {regi_marb_bar_bp2}, | ||
91 | {regi_marb_bar_bp3} | ||
92 | } | ||
93 | }; | ||
94 | |||
95 | struct arbiter arbiters[ARBITERS] = | ||
96 | { | ||
97 | { /* L2 cache arbiter */ | ||
98 | .instance = regi_marb_foo, | ||
99 | .nbr_regions = 2, | ||
100 | .nbr_clients = 15 | ||
101 | }, | ||
102 | { /* DDR2 arbiter */ | ||
103 | .instance = regi_marb_bar, | ||
104 | .nbr_regions = 1, | ||
105 | .nbr_clients = 9 | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH}; | ||
110 | |||
111 | DEFINE_SPINLOCK(arbiter_lock); | ||
112 | |||
113 | static irqreturn_t | ||
114 | crisv32_foo_arbiter_irq(int irq, void *dev_id); | ||
115 | static irqreturn_t | ||
116 | crisv32_bar_arbiter_irq(int irq, void *dev_id); | ||
117 | |||
118 | /* | ||
119 | * "I'm the arbiter, I know the score. | ||
120 | * From square one I'll be watching all 64." | ||
121 | * (memory arbiter slots, that is) | ||
122 | * | ||
123 | * Or in other words: | ||
124 | * Program the memory arbiter slots for "region" according to what's | ||
125 | * in requested_slots[] and active_clients[], while minimizing | ||
126 | * latency. A caller may pass a non-zero positive amount for | ||
127 | * "unused_slots", which must then be the unallocated, remaining | ||
128 | * number of slots, free to hand out to any client. | ||
129 | */ | ||
130 | |||
131 | static void crisv32_arbiter_config(int arbiter, int region, int unused_slots) | ||
132 | { | ||
133 | int slot; | ||
134 | int client; | ||
135 | int interval = 0; | ||
136 | |||
137 | /* | ||
138 | * This vector corresponds to the hardware arbiter slots (see | ||
139 | * the hardware documentation for semantics). We initialize | ||
140 | * each slot with a suitable sentinel value outside the valid | ||
141 | * range {0 .. NBR_OF_CLIENTS - 1} and replace them with | ||
142 | * client indexes. Then it's fed to the hardware. | ||
143 | */ | ||
144 | s8 val[NBR_OF_SLOTS]; | ||
145 | |||
146 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | ||
147 | val[slot] = -1; | ||
148 | |||
149 | for (client = 0; client < arbiters[arbiter].nbr_clients; client++) { | ||
150 | int pos; | ||
151 | /* Allocate the requested non-zero number of slots, but | ||
152 | * also give clients with zero-requests one slot each | ||
153 | * while stocks last. We do the latter here, in client | ||
154 | * order. This makes sure zero-request clients are the | ||
155 | * first to get to any spare slots, else those slots | ||
156 | * could, when bandwidth is allocated close to the limit, | ||
157 | * all be allocated to low-index non-zero-request clients | ||
158 | * in the default-fill loop below. Another positive but | ||
159 | * secondary effect is a somewhat better spread of the | ||
160 | * zero-bandwidth clients in the vector, avoiding some of | ||
161 | * the latency that could otherwise be caused by the | ||
162 | * partitioning of non-zero-bandwidth clients at low | ||
163 | * indexes and zero-bandwidth clients at high | ||
164 | * indexes. (Note that this spreading can only affect the | ||
165 | * unallocated bandwidth.) All the above only matters for | ||
166 | * memory-intensive situations, of course. | ||
167 | */ | ||
168 | if (!arbiters[arbiter].requested_slots[region][client]) { | ||
169 | /* | ||
170 | * Skip inactive clients. Also skip zero-slot | ||
171 | * allocations in this pass when there are no known | ||
172 | * free slots. | ||
173 | */ | ||
174 | if (!arbiters[arbiter].active_clients[region][client] || | ||
175 | unused_slots <= 0) | ||
176 | continue; | ||
177 | |||
178 | unused_slots--; | ||
179 | |||
180 | /* Only allocate one slot for this client. */ | ||
181 | interval = NBR_OF_SLOTS; | ||
182 | } else | ||
183 | interval = NBR_OF_SLOTS / | ||
184 | arbiters[arbiter].requested_slots[region][client]; | ||
185 | |||
186 | pos = 0; | ||
187 | while (pos < NBR_OF_SLOTS) { | ||
188 | if (val[pos] >= 0) | ||
189 | pos++; | ||
190 | else { | ||
191 | val[pos] = client; | ||
192 | pos += interval; | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | client = 0; | ||
198 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) { | ||
199 | /* | ||
200 | * Allocate remaining slots in round-robin | ||
201 | * client-number order for active clients. For this | ||
202 | * pass, we ignore requested bandwidth and previous | ||
203 | * allocations. | ||
204 | */ | ||
205 | if (val[slot] < 0) { | ||
206 | int first = client; | ||
207 | while (!arbiters[arbiter].active_clients[region][client]) { | ||
208 | client = (client + 1) % | ||
209 | arbiters[arbiter].nbr_clients; | ||
210 | if (client == first) | ||
211 | break; | ||
212 | } | ||
213 | val[slot] = client; | ||
214 | client = (client + 1) % arbiters[arbiter].nbr_clients; | ||
215 | } | ||
216 | if (arbiter == 0) { | ||
217 | if (region == EXT_REGION) | ||
218 | REG_WR_INT_VECT(marb_foo, regi_marb_foo, | ||
219 | rw_l2_slots, slot, val[slot]); | ||
220 | else if (region == INT_REGION) | ||
221 | REG_WR_INT_VECT(marb_foo, regi_marb_foo, | ||
222 | rw_intm_slots, slot, val[slot]); | ||
223 | } else { | ||
224 | REG_WR_INT_VECT(marb_bar, regi_marb_bar, | ||
225 | rw_ddr2_slots, slot, val[slot]); | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | extern char _stext, _etext; | ||
231 | |||
232 | static void crisv32_arbiter_init(void) | ||
233 | { | ||
234 | static int initialized; | ||
235 | |||
236 | if (initialized) | ||
237 | return; | ||
238 | |||
239 | initialized = 1; | ||
240 | |||
241 | /* | ||
242 | * CPU caches are always set to active, but with zero | ||
243 | * bandwidth allocated. It should be ok to allocate zero | ||
244 | * bandwidth for the caches, because DMA for other channels | ||
245 | * will supposedly finish, once their programmed amount is | ||
246 | * done, and then the caches will get access according to the | ||
247 | * "fixed scheme" for unclaimed slots. Though, if for some | ||
248 | * use-case somewhere, there's a maximum CPU latency for | ||
249 | * e.g. some interrupt, we have to start allocating specific | ||
250 | * bandwidth for the CPU caches too. | ||
251 | */ | ||
252 | arbiters[0].active_clients[EXT_REGION][11] = 1; | ||
253 | arbiters[0].active_clients[EXT_REGION][12] = 1; | ||
254 | crisv32_arbiter_config(0, EXT_REGION, 0); | ||
255 | crisv32_arbiter_config(0, INT_REGION, 0); | ||
256 | crisv32_arbiter_config(1, EXT_REGION, 0); | ||
257 | |||
258 | if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq, | ||
259 | IRQF_DISABLED, "arbiter", NULL)) | ||
260 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | ||
261 | |||
262 | if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq, | ||
263 | IRQF_DISABLED, "arbiter", NULL)) | ||
264 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | ||
265 | |||
266 | #ifndef CONFIG_ETRAX_KGDB | ||
267 | /* Global watch for writes to kernel text segment. */ | ||
268 | crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext, | ||
269 | MARB_CLIENTS(arbiter_all_clients, arbiter_bar_all_clients), | ||
270 | arbiter_all_write, NULL); | ||
271 | #endif | ||
272 | |||
273 | /* Set up max burst sizes by default */ | ||
274 | REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_rd_burst, 3); | ||
275 | REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_wr_burst, 3); | ||
276 | REG_WR_INT(marb_bar, regi_marb_bar, rw_ccd_burst, 3); | ||
277 | REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_wr_burst, 3); | ||
278 | REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_rd_burst, 3); | ||
279 | REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_rd_burst, 3); | ||
280 | REG_WR_INT(marb_bar, regi_marb_bar, rw_vout_burst, 3); | ||
281 | REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_fifo_burst, 3); | ||
282 | REG_WR_INT(marb_bar, regi_marb_bar, rw_l2cache_burst, 3); | ||
283 | } | ||
284 | |||
285 | int crisv32_arbiter_allocate_bandwidth(int client, int region, | ||
286 | unsigned long bandwidth) | ||
287 | { | ||
288 | int i; | ||
289 | int total_assigned = 0; | ||
290 | int total_clients = 0; | ||
291 | int req; | ||
292 | int arbiter = 0; | ||
293 | |||
294 | crisv32_arbiter_init(); | ||
295 | |||
296 | if (client & 0xffff0000) { | ||
297 | arbiter = 1; | ||
298 | client >>= 16; | ||
299 | } | ||
300 | |||
301 | for (i = 0; i < arbiters[arbiter].nbr_clients; i++) { | ||
302 | total_assigned += arbiters[arbiter].requested_slots[region][i]; | ||
303 | total_clients += arbiters[arbiter].active_clients[region][i]; | ||
304 | } | ||
305 | |||
306 | /* Avoid division by 0 for 0-bandwidth requests. */ | ||
307 | req = bandwidth == 0 | ||
308 | ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); | ||
309 | |||
310 | /* | ||
311 | * We make sure that there are enough slots only for non-zero | ||
312 | * requests. Requesting 0 bandwidth *may* allocate slots, | ||
313 | * though if all bandwidth is allocated, such a client won't | ||
314 | * get any and will have to rely on getting memory access | ||
315 | * according to the fixed scheme that's the default when one | ||
316 | * of the slot-allocated clients doesn't claim their slot. | ||
317 | */ | ||
318 | if (total_assigned + req > NBR_OF_SLOTS) | ||
319 | return -ENOMEM; | ||
320 | |||
321 | arbiters[arbiter].active_clients[region][client] = 1; | ||
322 | arbiters[arbiter].requested_slots[region][client] = req; | ||
323 | crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned); | ||
324 | |||
325 | /* Propagate allocation from foo to bar */ | ||
326 | if (arbiter == 0) | ||
327 | crisv32_arbiter_allocate_bandwidth(8 << 16, | ||
328 | EXT_REGION, bandwidth); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Main entry for bandwidth deallocation. | ||
334 | * | ||
335 | * Strictly speaking, for a somewhat constant set of clients where | ||
336 | * each client gets a constant bandwidth and is just enabled or | ||
337 | * disabled (somewhat dynamically), no action is necessary here to | ||
338 | * avoid starvation for non-zero-allocation clients, as the allocated | ||
339 | * slots will just be unused. However, handing out those unused slots | ||
340 | * to active clients avoids needless latency if the "fixed scheme" | ||
341 | * would give unclaimed slots to an eager low-index client. | ||
342 | */ | ||
343 | |||
344 | void crisv32_arbiter_deallocate_bandwidth(int client, int region) | ||
345 | { | ||
346 | int i; | ||
347 | int total_assigned = 0; | ||
348 | int arbiter = 0; | ||
349 | |||
350 | if (client & 0xffff0000) | ||
351 | arbiter = 1; | ||
352 | |||
353 | arbiters[arbiter].requested_slots[region][client] = 0; | ||
354 | arbiters[arbiter].active_clients[region][client] = 0; | ||
355 | |||
356 | for (i = 0; i < arbiters[arbiter].nbr_clients; i++) | ||
357 | total_assigned += arbiters[arbiter].requested_slots[region][i]; | ||
358 | |||
359 | crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned); | ||
360 | } | ||
361 | |||
362 | int crisv32_arbiter_watch(unsigned long start, unsigned long size, | ||
363 | unsigned long clients, unsigned long accesses, | ||
364 | watch_callback *cb) | ||
365 | { | ||
366 | int i; | ||
367 | int arbiter; | ||
368 | int used[2]; | ||
369 | int ret = 0; | ||
370 | |||
371 | crisv32_arbiter_init(); | ||
372 | |||
373 | if (start > 0x80000000) { | ||
374 | printk(KERN_ERR "Arbiter: %lX doesn't look like a " | ||
375 | "physical address", start); | ||
376 | return -EFAULT; | ||
377 | } | ||
378 | |||
379 | spin_lock(&arbiter_lock); | ||
380 | |||
381 | if (clients & 0xffff) | ||
382 | used[0] = 1; | ||
383 | if (clients & 0xffff0000) | ||
384 | used[1] = 1; | ||
385 | |||
386 | for (arbiter = 0; arbiter < ARBITERS; arbiter++) { | ||
387 | if (!used[arbiter]) | ||
388 | continue; | ||
389 | |||
390 | for (i = 0; i < NUMBER_OF_BP; i++) { | ||
391 | if (!watches[arbiter][i].used) { | ||
392 | unsigned intr_mask; | ||
393 | if (arbiter) | ||
394 | intr_mask = REG_RD_INT(marb_bar, | ||
395 | regi_marb_bar, rw_intr_mask); | ||
396 | else | ||
397 | intr_mask = REG_RD_INT(marb_foo, | ||
398 | regi_marb_foo, rw_intr_mask); | ||
399 | |||
400 | watches[arbiter][i].used = 1; | ||
401 | watches[arbiter][i].start = start; | ||
402 | watches[arbiter][i].end = start + size; | ||
403 | watches[arbiter][i].cb = cb; | ||
404 | |||
405 | ret |= (i + 1) << (arbiter + 8); | ||
406 | if (arbiter) { | ||
407 | REG_WR_INT(marb_bar_bp, | ||
408 | watches[arbiter][i].instance, | ||
409 | rw_first_addr, | ||
410 | watches[arbiter][i].start); | ||
411 | REG_WR_INT(marb_bar_bp, | ||
412 | watches[arbiter][i].instance, | ||
413 | rw_last_addr, | ||
414 | watches[arbiter][i].end); | ||
415 | REG_WR_INT(marb_bar_bp, | ||
416 | watches[arbiter][i].instance, | ||
417 | rw_op, accesses); | ||
418 | REG_WR_INT(marb_bar_bp, | ||
419 | watches[arbiter][i].instance, | ||
420 | rw_clients, | ||
421 | clients & 0xffff); | ||
422 | } else { | ||
423 | REG_WR_INT(marb_foo_bp, | ||
424 | watches[arbiter][i].instance, | ||
425 | rw_first_addr, | ||
426 | watches[arbiter][i].start); | ||
427 | REG_WR_INT(marb_foo_bp, | ||
428 | watches[arbiter][i].instance, | ||
429 | rw_last_addr, | ||
430 | watches[arbiter][i].end); | ||
431 | REG_WR_INT(marb_foo_bp, | ||
432 | watches[arbiter][i].instance, | ||
433 | rw_op, accesses); | ||
434 | REG_WR_INT(marb_foo_bp, | ||
435 | watches[arbiter][i].instance, | ||
436 | rw_clients, clients >> 16); | ||
437 | } | ||
438 | |||
439 | if (i == 0) | ||
440 | intr_mask |= 1; | ||
441 | else if (i == 1) | ||
442 | intr_mask |= 2; | ||
443 | else if (i == 2) | ||
444 | intr_mask |= 4; | ||
445 | else if (i == 3) | ||
446 | intr_mask |= 8; | ||
447 | |||
448 | if (arbiter) | ||
449 | REG_WR_INT(marb_bar, regi_marb_bar, | ||
450 | rw_intr_mask, intr_mask); | ||
451 | else | ||
452 | REG_WR_INT(marb_foo, regi_marb_foo, | ||
453 | rw_intr_mask, intr_mask); | ||
454 | |||
455 | spin_unlock(&arbiter_lock); | ||
456 | |||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | spin_unlock(&arbiter_lock); | ||
462 | if (ret) | ||
463 | return ret; | ||
464 | else | ||
465 | return -ENOMEM; | ||
466 | } | ||
467 | |||
468 | int crisv32_arbiter_unwatch(int id) | ||
469 | { | ||
470 | int arbiter; | ||
471 | int intr_mask; | ||
472 | |||
473 | crisv32_arbiter_init(); | ||
474 | |||
475 | spin_lock(&arbiter_lock); | ||
476 | |||
477 | for (arbiter = 0; arbiter < ARBITERS; arbiter++) { | ||
478 | int id2; | ||
479 | |||
480 | if (arbiter) | ||
481 | intr_mask = REG_RD_INT(marb_bar, regi_marb_bar, | ||
482 | rw_intr_mask); | ||
483 | else | ||
484 | intr_mask = REG_RD_INT(marb_foo, regi_marb_foo, | ||
485 | rw_intr_mask); | ||
486 | |||
487 | id2 = (id & (0xff << (arbiter + 8))) >> (arbiter + 8); | ||
488 | if (id2 == 0) | ||
489 | continue; | ||
490 | id2--; | ||
491 | if ((id2 >= NUMBER_OF_BP) || (!watches[arbiter][id2].used)) { | ||
492 | spin_unlock(&arbiter_lock); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | memset(&watches[arbiter][id2], 0, | ||
497 | sizeof(struct crisv32_watch_entry)); | ||
498 | |||
499 | if (id2 == 0) | ||
500 | intr_mask &= ~1; | ||
501 | else if (id2 == 1) | ||
502 | intr_mask &= ~2; | ||
503 | else if (id2 == 2) | ||
504 | intr_mask &= ~4; | ||
505 | else if (id2 == 3) | ||
506 | intr_mask &= ~8; | ||
507 | |||
508 | if (arbiter) | ||
509 | REG_WR_INT(marb_bar, regi_marb_bar, rw_intr_mask, | ||
510 | intr_mask); | ||
511 | else | ||
512 | REG_WR_INT(marb_foo, regi_marb_foo, rw_intr_mask, | ||
513 | intr_mask); | ||
514 | } | ||
515 | |||
516 | spin_unlock(&arbiter_lock); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | extern void show_registers(struct pt_regs *regs); | ||
521 | |||
522 | |||
523 | static irqreturn_t | ||
524 | crisv32_foo_arbiter_irq(int irq, void *dev_id) | ||
525 | { | ||
526 | reg_marb_foo_r_masked_intr masked_intr = | ||
527 | REG_RD(marb_foo, regi_marb_foo, r_masked_intr); | ||
528 | reg_marb_foo_bp_r_brk_clients r_clients; | ||
529 | reg_marb_foo_bp_r_brk_addr r_addr; | ||
530 | reg_marb_foo_bp_r_brk_op r_op; | ||
531 | reg_marb_foo_bp_r_brk_first_client r_first; | ||
532 | reg_marb_foo_bp_r_brk_size r_size; | ||
533 | reg_marb_foo_bp_rw_ack ack = {0}; | ||
534 | reg_marb_foo_rw_ack_intr ack_intr = { | ||
535 | .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 | ||
536 | }; | ||
537 | struct crisv32_watch_entry *watch; | ||
538 | unsigned arbiter = (unsigned)dev_id; | ||
539 | |||
540 | masked_intr = REG_RD(marb_foo, regi_marb_foo, r_masked_intr); | ||
541 | |||
542 | if (masked_intr.bp0) | ||
543 | watch = &watches[arbiter][0]; | ||
544 | else if (masked_intr.bp1) | ||
545 | watch = &watches[arbiter][1]; | ||
546 | else if (masked_intr.bp2) | ||
547 | watch = &watches[arbiter][2]; | ||
548 | else if (masked_intr.bp3) | ||
549 | watch = &watches[arbiter][3]; | ||
550 | else | ||
551 | return IRQ_NONE; | ||
552 | |||
553 | /* Retrieve all useful information and print it. */ | ||
554 | r_clients = REG_RD(marb_foo_bp, watch->instance, r_brk_clients); | ||
555 | r_addr = REG_RD(marb_foo_bp, watch->instance, r_brk_addr); | ||
556 | r_op = REG_RD(marb_foo_bp, watch->instance, r_brk_op); | ||
557 | r_first = REG_RD(marb_foo_bp, watch->instance, r_brk_first_client); | ||
558 | r_size = REG_RD(marb_foo_bp, watch->instance, r_brk_size); | ||
559 | |||
560 | printk(KERN_DEBUG "Arbiter IRQ\n"); | ||
561 | printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n", | ||
562 | REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_clients, r_clients), | ||
563 | REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_addr, r_addr), | ||
564 | REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_op, r_op), | ||
565 | REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_first_client, r_first), | ||
566 | REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_size, r_size)); | ||
567 | |||
568 | REG_WR(marb_foo_bp, watch->instance, rw_ack, ack); | ||
569 | REG_WR(marb_foo, regi_marb_foo, rw_ack_intr, ack_intr); | ||
570 | |||
571 | printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs()); | ||
572 | |||
573 | if (watch->cb) | ||
574 | watch->cb(); | ||
575 | |||
576 | return IRQ_HANDLED; | ||
577 | } | ||
578 | |||
579 | static irqreturn_t | ||
580 | crisv32_bar_arbiter_irq(int irq, void *dev_id) | ||
581 | { | ||
582 | reg_marb_bar_r_masked_intr masked_intr = | ||
583 | REG_RD(marb_bar, regi_marb_bar, r_masked_intr); | ||
584 | reg_marb_bar_bp_r_brk_clients r_clients; | ||
585 | reg_marb_bar_bp_r_brk_addr r_addr; | ||
586 | reg_marb_bar_bp_r_brk_op r_op; | ||
587 | reg_marb_bar_bp_r_brk_first_client r_first; | ||
588 | reg_marb_bar_bp_r_brk_size r_size; | ||
589 | reg_marb_bar_bp_rw_ack ack = {0}; | ||
590 | reg_marb_bar_rw_ack_intr ack_intr = { | ||
591 | .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 | ||
592 | }; | ||
593 | struct crisv32_watch_entry *watch; | ||
594 | unsigned arbiter = (unsigned)dev_id; | ||
595 | |||
596 | masked_intr = REG_RD(marb_bar, regi_marb_bar, r_masked_intr); | ||
597 | |||
598 | if (masked_intr.bp0) | ||
599 | watch = &watches[arbiter][0]; | ||
600 | else if (masked_intr.bp1) | ||
601 | watch = &watches[arbiter][1]; | ||
602 | else if (masked_intr.bp2) | ||
603 | watch = &watches[arbiter][2]; | ||
604 | else if (masked_intr.bp3) | ||
605 | watch = &watches[arbiter][3]; | ||
606 | else | ||
607 | return IRQ_NONE; | ||
608 | |||
609 | /* Retrieve all useful information and print it. */ | ||
610 | r_clients = REG_RD(marb_bar_bp, watch->instance, r_brk_clients); | ||
611 | r_addr = REG_RD(marb_bar_bp, watch->instance, r_brk_addr); | ||
612 | r_op = REG_RD(marb_bar_bp, watch->instance, r_brk_op); | ||
613 | r_first = REG_RD(marb_bar_bp, watch->instance, r_brk_first_client); | ||
614 | r_size = REG_RD(marb_bar_bp, watch->instance, r_brk_size); | ||
615 | |||
616 | printk(KERN_DEBUG "Arbiter IRQ\n"); | ||
617 | printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n", | ||
618 | REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_clients, r_clients), | ||
619 | REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_addr, r_addr), | ||
620 | REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_op, r_op), | ||
621 | REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_first_client, r_first), | ||
622 | REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_size, r_size)); | ||
623 | |||
624 | REG_WR(marb_bar_bp, watch->instance, rw_ack, ack); | ||
625 | REG_WR(marb_bar, regi_marb_bar, rw_ack_intr, ack_intr); | ||
626 | |||
627 | printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs()->erp); | ||
628 | |||
629 | if (watch->cb) | ||
630 | watch->cb(); | ||
631 | |||
632 | return IRQ_HANDLED; | ||
633 | } | ||
634 | |||
diff --git a/arch/cris/arch-v32/mach-a3/cpufreq.c b/arch/cris/arch-v32/mach-a3/cpufreq.c new file mode 100644 index 000000000000..8e5a3cab8ad7 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/cpufreq.c | |||
@@ -0,0 +1,153 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/cpufreq.h> | ||
4 | #include <hwregs/reg_map.h> | ||
5 | #include <hwregs/reg_rdwr.h> | ||
6 | #include <hwregs/clkgen_defs.h> | ||
7 | #include <hwregs/ddr2_defs.h> | ||
8 | |||
9 | static int | ||
10 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
11 | void *data); | ||
12 | |||
13 | static struct notifier_block cris_sdram_freq_notifier_block = { | ||
14 | .notifier_call = cris_sdram_freq_notifier | ||
15 | }; | ||
16 | |||
17 | static struct cpufreq_frequency_table cris_freq_table[] = { | ||
18 | {0x01, 6000}, | ||
19 | {0x02, 200000}, | ||
20 | {0, CPUFREQ_TABLE_END}, | ||
21 | }; | ||
22 | |||
23 | static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) | ||
24 | { | ||
25 | reg_clkgen_rw_clk_ctrl clk_ctrl; | ||
26 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | ||
27 | return clk_ctrl.pll ? 200000 : 6000; | ||
28 | } | ||
29 | |||
30 | static void cris_freq_set_cpu_state(unsigned int state) | ||
31 | { | ||
32 | int i = 0; | ||
33 | struct cpufreq_freqs freqs; | ||
34 | reg_clkgen_rw_clk_ctrl clk_ctrl; | ||
35 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | ||
36 | |||
37 | #ifdef CONFIG_SMP | ||
38 | for_each_present_cpu(i) | ||
39 | #endif | ||
40 | { | ||
41 | freqs.old = cris_freq_get_cpu_frequency(i); | ||
42 | freqs.new = cris_freq_table[state].frequency; | ||
43 | freqs.cpu = i; | ||
44 | } | ||
45 | |||
46 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
47 | |||
48 | local_irq_disable(); | ||
49 | |||
50 | /* Even though we may be SMP they will share the same clock | ||
51 | * so all settings are made on CPU0. */ | ||
52 | if (cris_freq_table[state].frequency == 200000) | ||
53 | clk_ctrl.pll = 1; | ||
54 | else | ||
55 | clk_ctrl.pll = 0; | ||
56 | REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); | ||
57 | |||
58 | local_irq_enable(); | ||
59 | |||
60 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
61 | }; | ||
62 | |||
63 | static int cris_freq_verify(struct cpufreq_policy *policy) | ||
64 | { | ||
65 | return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]); | ||
66 | } | ||
67 | |||
68 | static int cris_freq_target(struct cpufreq_policy *policy, | ||
69 | unsigned int target_freq, | ||
70 | unsigned int relation) | ||
71 | { | ||
72 | unsigned int newstate = 0; | ||
73 | |||
74 | if (cpufreq_frequency_table_target(policy, cris_freq_table, | ||
75 | target_freq, relation, &newstate)) | ||
76 | return -EINVAL; | ||
77 | |||
78 | cris_freq_set_cpu_state(newstate); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int cris_freq_cpu_init(struct cpufreq_policy *policy) | ||
84 | { | ||
85 | int result; | ||
86 | |||
87 | /* cpuinfo and default policy values */ | ||
88 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
89 | policy->cpuinfo.transition_latency = 1000000; /* 1ms */ | ||
90 | policy->cur = cris_freq_get_cpu_frequency(0); | ||
91 | |||
92 | result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table); | ||
93 | if (result) | ||
94 | return (result); | ||
95 | |||
96 | cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | |||
102 | static int cris_freq_cpu_exit(struct cpufreq_policy *policy) | ||
103 | { | ||
104 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | |||
109 | static struct freq_attr *cris_freq_attr[] = { | ||
110 | &cpufreq_freq_attr_scaling_available_freqs, | ||
111 | NULL, | ||
112 | }; | ||
113 | |||
114 | static struct cpufreq_driver cris_freq_driver = { | ||
115 | .get = cris_freq_get_cpu_frequency, | ||
116 | .verify = cris_freq_verify, | ||
117 | .target = cris_freq_target, | ||
118 | .init = cris_freq_cpu_init, | ||
119 | .exit = cris_freq_cpu_exit, | ||
120 | .name = "cris_freq", | ||
121 | .owner = THIS_MODULE, | ||
122 | .attr = cris_freq_attr, | ||
123 | }; | ||
124 | |||
125 | static int __init cris_freq_init(void) | ||
126 | { | ||
127 | int ret; | ||
128 | ret = cpufreq_register_driver(&cris_freq_driver); | ||
129 | cpufreq_register_notifier(&cris_sdram_freq_notifier_block, | ||
130 | CPUFREQ_TRANSITION_NOTIFIER); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int | ||
135 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
136 | void *data) | ||
137 | { | ||
138 | int i; | ||
139 | struct cpufreq_freqs *freqs = data; | ||
140 | if (val == CPUFREQ_PRECHANGE) { | ||
141 | reg_ddr2_rw_cfg cfg = | ||
142 | REG_RD(ddr2, regi_ddr2_ctrl, rw_cfg); | ||
143 | cfg.ref_interval = (freqs->new == 200000 ? 1560 : 46); | ||
144 | |||
145 | if (freqs->new == 200000) | ||
146 | for (i = 0; i < 50000; i++); | ||
147 | REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing); | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | |||
153 | module_init(cris_freq_init); | ||
diff --git a/arch/cris/arch-v32/mach-a3/dma.c b/arch/cris/arch-v32/mach-a3/dma.c new file mode 100644 index 000000000000..25f236ef0b81 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/dma.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* Wrapper for DMA channel allocator that starts clocks etc */ | ||
2 | |||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/spinlock.h> | ||
5 | #include <asm/arch/mach/dma.h> | ||
6 | #include <hwregs/reg_map.h> | ||
7 | #include <hwregs/reg_rdwr.h> | ||
8 | #include <hwregs/marb_defs.h> | ||
9 | #include <hwregs/clkgen_defs.h> | ||
10 | #include <hwregs/strmux_defs.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <asm/system.h> | ||
13 | #include <arbiter.h> | ||
14 | |||
15 | static char used_dma_channels[MAX_DMA_CHANNELS]; | ||
16 | static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; | ||
17 | |||
18 | static DEFINE_SPINLOCK(dma_lock); | ||
19 | |||
20 | int crisv32_request_dma(unsigned int dmanr, const char *device_id, | ||
21 | unsigned options, unsigned int bandwidth, enum dma_owner owner) | ||
22 | { | ||
23 | unsigned long flags; | ||
24 | reg_clkgen_rw_clk_ctrl clk_ctrl; | ||
25 | reg_strmux_rw_cfg strmux_cfg; | ||
26 | |||
27 | if (crisv32_arbiter_allocate_bandwidth(dmanr, | ||
28 | options & DMA_INT_MEM ? INT_REGION : EXT_REGION, | ||
29 | bandwidth)) | ||
30 | return -ENOMEM; | ||
31 | |||
32 | spin_lock_irqsave(&dma_lock, flags); | ||
33 | |||
34 | if (used_dma_channels[dmanr]) { | ||
35 | spin_unlock_irqrestore(&dma_lock, flags); | ||
36 | if (options & DMA_VERBOSE_ON_ERROR) | ||
37 | printk(KERN_ERR "Failed to request DMA %i for %s, " | ||
38 | "already allocated by %s\n", | ||
39 | dmanr, | ||
40 | device_id, | ||
41 | used_dma_channels_users[dmanr]); | ||
42 | |||
43 | if (options & DMA_PANIC_ON_ERROR) | ||
44 | panic("request_dma error!"); | ||
45 | spin_unlock_irqrestore(&dma_lock, flags); | ||
46 | return -EBUSY; | ||
47 | } | ||
48 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | ||
49 | strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); | ||
50 | |||
51 | switch (dmanr) { | ||
52 | case 0: | ||
53 | case 1: | ||
54 | clk_ctrl.dma0_1_eth = 1; | ||
55 | break; | ||
56 | case 2: | ||
57 | case 3: | ||
58 | clk_ctrl.dma2_3_strcop = 1; | ||
59 | break; | ||
60 | case 4: | ||
61 | case 5: | ||
62 | clk_ctrl.dma4_5_iop = 1; | ||
63 | break; | ||
64 | case 6: | ||
65 | case 7: | ||
66 | clk_ctrl.sser_ser_dma6_7 = 1; | ||
67 | break; | ||
68 | case 9: | ||
69 | case 11: | ||
70 | clk_ctrl.dma9_11 = 1; | ||
71 | break; | ||
72 | #if MAX_DMA_CHANNELS-1 != 11 | ||
73 | #error Check dma.c | ||
74 | #endif | ||
75 | default: | ||
76 | spin_unlock_irqrestore(&dma_lock, flags); | ||
77 | if (options & DMA_VERBOSE_ON_ERROR) | ||
78 | printk(KERN_ERR "Failed to request DMA %i for %s, " | ||
79 | "only 0-%i valid)\n", | ||
80 | dmanr, device_id, MAX_DMA_CHANNELS-1); | ||
81 | |||
82 | if (options & DMA_PANIC_ON_ERROR) | ||
83 | panic("request_dma error!"); | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | |||
87 | switch (owner) { | ||
88 | case dma_eth: | ||
89 | if (dmanr == 0) | ||
90 | strmux_cfg.dma0 = regk_strmux_eth; | ||
91 | else if (dmanr == 1) | ||
92 | strmux_cfg.dma1 = regk_strmux_eth; | ||
93 | else | ||
94 | panic("Invalid DMA channel for eth\n"); | ||
95 | break; | ||
96 | case dma_ser0: | ||
97 | if (dmanr == 0) | ||
98 | strmux_cfg.dma0 = regk_strmux_ser0; | ||
99 | else if (dmanr == 1) | ||
100 | strmux_cfg.dma1 = regk_strmux_ser0; | ||
101 | else | ||
102 | panic("Invalid DMA channel for ser0\n"); | ||
103 | break; | ||
104 | case dma_ser3: | ||
105 | if (dmanr == 2) | ||
106 | strmux_cfg.dma2 = regk_strmux_ser3; | ||
107 | else if (dmanr == 3) | ||
108 | strmux_cfg.dma3 = regk_strmux_ser3; | ||
109 | else | ||
110 | panic("Invalid DMA channel for ser3\n"); | ||
111 | break; | ||
112 | case dma_strp: | ||
113 | if (dmanr == 2) | ||
114 | strmux_cfg.dma2 = regk_strmux_strcop; | ||
115 | else if (dmanr == 3) | ||
116 | strmux_cfg.dma3 = regk_strmux_strcop; | ||
117 | else | ||
118 | panic("Invalid DMA channel for strp\n"); | ||
119 | break; | ||
120 | case dma_ser1: | ||
121 | if (dmanr == 4) | ||
122 | strmux_cfg.dma4 = regk_strmux_ser1; | ||
123 | else if (dmanr == 5) | ||
124 | strmux_cfg.dma5 = regk_strmux_ser1; | ||
125 | else | ||
126 | panic("Invalid DMA channel for ser1\n"); | ||
127 | break; | ||
128 | case dma_iop: | ||
129 | if (dmanr == 4) | ||
130 | strmux_cfg.dma4 = regk_strmux_iop; | ||
131 | else if (dmanr == 5) | ||
132 | strmux_cfg.dma5 = regk_strmux_iop; | ||
133 | else | ||
134 | panic("Invalid DMA channel for iop\n"); | ||
135 | break; | ||
136 | case dma_ser2: | ||
137 | if (dmanr == 6) | ||
138 | strmux_cfg.dma6 = regk_strmux_ser2; | ||
139 | else if (dmanr == 7) | ||
140 | strmux_cfg.dma7 = regk_strmux_ser2; | ||
141 | else | ||
142 | panic("Invalid DMA channel for ser2\n"); | ||
143 | break; | ||
144 | case dma_sser: | ||
145 | if (dmanr == 6) | ||
146 | strmux_cfg.dma6 = regk_strmux_sser; | ||
147 | else if (dmanr == 7) | ||
148 | strmux_cfg.dma7 = regk_strmux_sser; | ||
149 | else | ||
150 | panic("Invalid DMA channel for sser\n"); | ||
151 | break; | ||
152 | case dma_ser4: | ||
153 | if (dmanr == 9) | ||
154 | strmux_cfg.dma9 = regk_strmux_ser4; | ||
155 | else | ||
156 | panic("Invalid DMA channel for ser4\n"); | ||
157 | break; | ||
158 | case dma_jpeg: | ||
159 | if (dmanr == 9) | ||
160 | strmux_cfg.dma9 = regk_strmux_jpeg; | ||
161 | else | ||
162 | panic("Invalid DMA channel for JPEG\n"); | ||
163 | break; | ||
164 | case dma_h264: | ||
165 | if (dmanr == 11) | ||
166 | strmux_cfg.dma11 = regk_strmux_h264; | ||
167 | else | ||
168 | panic("Invalid DMA channel for H264\n"); | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | used_dma_channels[dmanr] = 1; | ||
173 | used_dma_channels_users[dmanr] = device_id; | ||
174 | REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); | ||
175 | REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); | ||
176 | spin_unlock_irqrestore(&dma_lock, flags); | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | void crisv32_free_dma(unsigned int dmanr) | ||
181 | { | ||
182 | spin_lock(&dma_lock); | ||
183 | used_dma_channels[dmanr] = 0; | ||
184 | spin_unlock(&dma_lock); | ||
185 | } | ||
diff --git a/arch/cris/arch-v32/mach-a3/dram_init.S b/arch/cris/arch-v32/mach-a3/dram_init.S new file mode 100644 index 000000000000..94d6b41cb299 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/dram_init.S | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * DDR SDRAM initialization - alter with care | ||
3 | * This file is intended to be included from other assembler files | ||
4 | * | ||
5 | * Note: This file may not modify r8 or r9 because they are used to | ||
6 | * carry information from the decompresser to the kernel | ||
7 | * | ||
8 | * Copyright (C) 2005-2007 Axis Communications AB | ||
9 | * | ||
10 | * Authors: Mikael Starvik <starvik@axis.com> | ||
11 | */ | ||
12 | |||
13 | /* Just to be certain the config file is included, we include it here | ||
14 | * explicitely instead of depending on it being included in the file that | ||
15 | * uses this code. | ||
16 | */ | ||
17 | |||
18 | #include <hwregs/asm/reg_map_asm.h> | ||
19 | #include <hwregs/asm/ddr2_defs_asm.h> | ||
20 | |||
21 | ;; WARNING! The registers r8 and r9 are used as parameters carrying | ||
22 | ;; information from the decompressor (if the kernel was compressed). | ||
23 | ;; They should not be used in the code below. | ||
24 | |||
25 | ;; Refer to ddr2 MDS for initialization sequence | ||
26 | |||
27 | ; Start clock | ||
28 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_cfg), $r0 | ||
29 | move.d REG_STATE(ddr2, rw_phy_cfg, en, yes), $r1 | ||
30 | move.d $r1, [$r0] | ||
31 | |||
32 | ; Reset phy and start calibration | ||
33 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_ctrl), $r0 | ||
34 | move.d REG_STATE(ddr2, rw_phy_ctrl, rst, yes) | \ | ||
35 | REG_STATE(ddr2, rw_phy_ctrl, cal_rst, yes), $r1 | ||
36 | move.d $r1, [$r0] | ||
37 | move.d REG_STATE(ddr2, rw_phy_ctrl, cal_start, yes), $r1 | ||
38 | move.d $r1, [$r0] | ||
39 | |||
40 | ; 2. Wait 200us | ||
41 | move.d 10000, $r2 | ||
42 | 1: bne 1b | ||
43 | subq 1, $r2 | ||
44 | |||
45 | ; Issue commands | ||
46 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_ctrl), $r0 | ||
47 | move.d sdram_commands_start, $r2 | ||
48 | command_loop: | ||
49 | movu.b [$r2+], $r1 | ||
50 | movu.w [$r2+], $r3 | ||
51 | do_cmd: | ||
52 | lslq 16, $r1 | ||
53 | or.d $r3, $r1 | ||
54 | move.d $r1, [$r0] | ||
55 | cmp.d sdram_commands_end, $r2 | ||
56 | blo command_loop | ||
57 | nop | ||
58 | |||
59 | ; Set timing | ||
60 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing), $r0 | ||
61 | move.d CONFIG_ETRAX_DDR2_TIMING, $r1 | ||
62 | move.d $r1, [$r0] | ||
63 | |||
64 | ; Set latency | ||
65 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_latency), $r0 | ||
66 | move.d 0x13, $r1 | ||
67 | move.d $r1, [$r0] | ||
68 | |||
69 | ; Set configuration | ||
70 | move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg), $r0 | ||
71 | move.d CONFIG_ETRAX_DDR2_CONFIG, $r1 | ||
72 | move.d $r1, [$r0] | ||
73 | |||
74 | ba after_sdram_commands | ||
75 | nop | ||
76 | |||
77 | sdram_commands_start: | ||
78 | .byte regk_ddr2_deselect | ||
79 | .word 0 | ||
80 | .byte regk_ddr2_pre | ||
81 | .word regk_ddr2_pre_all | ||
82 | .byte regk_ddr2_emrs2 | ||
83 | .word 0 | ||
84 | .byte regk_ddr2_emrs3 | ||
85 | .word 0 | ||
86 | .byte regk_ddr2_emrs | ||
87 | .word regk_ddr2_dll_en | ||
88 | .byte regk_ddr2_mrs | ||
89 | .word regk_ddr2_dll_rst | ||
90 | .byte regk_ddr2_pre | ||
91 | .word regk_ddr2_pre_all | ||
92 | .byte regk_ddr2_ref | ||
93 | .word 0 | ||
94 | .byte regk_ddr2_ref | ||
95 | .word 0 | ||
96 | .byte regk_ddr2_mrs | ||
97 | .word CONFIG_ETRAX_DDR2_MRS & 0xffff | ||
98 | .byte regk_ddr2_emrs | ||
99 | .word regk_ddr2_ocd_default | regk_ddr2_dll_en | ||
100 | .byte regk_ddr2_emrs | ||
101 | .word regk_ddr2_ocd_exit | regk_ddr2_dll_en | (CONFIG_ETRAX_DDR2_MRS >> 16) | ||
102 | sdram_commands_end: | ||
103 | .align 1 | ||
104 | after_sdram_commands: | ||
diff --git a/arch/cris/arch-v32/mach-a3/hw_settings.S b/arch/cris/arch-v32/mach-a3/hw_settings.S new file mode 100644 index 000000000000..258a6329cd4a --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/hw_settings.S | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * This table is used by some tools to extract hardware parameters. | ||
3 | * The table should be included in the kernel and the decompressor. | ||
4 | * Don't forget to update the tools if you change this table. | ||
5 | * | ||
6 | * Copyright (C) 2001-2007 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Mikael Starvik <starvik@axis.com> | ||
9 | */ | ||
10 | |||
11 | #include <hwregs/asm/reg_map_asm.h> | ||
12 | #include <hwregs/asm/ddr2_defs_asm.h> | ||
13 | #include <hwregs/asm/gio_defs_asm.h> | ||
14 | |||
15 | .ascii "HW_PARAM_MAGIC" ; Magic number | ||
16 | .dword 0xc0004000 ; Kernel start address | ||
17 | |||
18 | ; Debug port | ||
19 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | ||
20 | .dword 0 | ||
21 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
22 | .dword 1 | ||
23 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
24 | .dword 2 | ||
25 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
26 | .dword 3 | ||
27 | #else | ||
28 | .dword 4 ; No debug | ||
29 | #endif | ||
30 | |||
31 | ; Register values | ||
32 | .dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg) | ||
33 | .dword CONFIG_ETRAX_DDR2_CONFIG | ||
34 | .dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing) | ||
35 | .dword CONFIG_ETRAX_DDR2_TIMING | ||
36 | .dword CONFIG_ETRAX_DDR2_MRS | ||
37 | |||
38 | .dword REG_ADDR(gio, regi_gio, rw_pa_dout) | ||
39 | .dword CONFIG_ETRAX_DEF_GIO_PA_OUT | ||
40 | .dword REG_ADDR(gio, regi_gio, rw_pa_oe) | ||
41 | .dword CONFIG_ETRAX_DEF_GIO_PA_OE | ||
42 | .dword REG_ADDR(gio, regi_gio, rw_pb_dout) | ||
43 | .dword CONFIG_ETRAX_DEF_GIO_PB_OUT | ||
44 | .dword REG_ADDR(gio, regi_gio, rw_pb_oe) | ||
45 | .dword CONFIG_ETRAX_DEF_GIO_PB_OE | ||
46 | .dword REG_ADDR(gio, regi_gio, rw_pc_dout) | ||
47 | .dword CONFIG_ETRAX_DEF_GIO_PC_OUT | ||
48 | .dword REG_ADDR(gio, regi_gio, rw_pc_oe) | ||
49 | .dword CONFIG_ETRAX_DEF_GIO_PC_OE | ||
50 | |||
51 | .dword 0 ; No more register values | ||
diff --git a/arch/cris/arch-v32/mach-a3/io.c b/arch/cris/arch-v32/mach-a3/io.c new file mode 100644 index 000000000000..9eeaf3eca474 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/io.c | |||
@@ -0,0 +1,149 @@ | |||
1 | /* | ||
2 | * Helper functions for I/O pins. | ||
3 | * | ||
4 | * Copyright (c) 2005-2007 Axis Communications AB. | ||
5 | */ | ||
6 | |||
7 | #include <linux/types.h> | ||
8 | #include <linux/errno.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/arch/mach/pinmux.h> | ||
16 | #include <hwregs/gio_defs.h> | ||
17 | |||
18 | struct crisv32_ioport crisv32_ioports[] = { | ||
19 | { | ||
20 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe), | ||
21 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout), | ||
22 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din), | ||
23 | 32 | ||
24 | }, | ||
25 | { | ||
26 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe), | ||
27 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout), | ||
28 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din), | ||
29 | 32 | ||
30 | }, | ||
31 | { | ||
32 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe), | ||
33 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout), | ||
34 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din), | ||
35 | 16 | ||
36 | }, | ||
37 | }; | ||
38 | |||
39 | #define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport) | ||
40 | |||
41 | struct crisv32_iopin crisv32_led_net0_green; | ||
42 | struct crisv32_iopin crisv32_led_net0_red; | ||
43 | struct crisv32_iopin crisv32_led2_green; | ||
44 | struct crisv32_iopin crisv32_led2_red; | ||
45 | struct crisv32_iopin crisv32_led3_green; | ||
46 | struct crisv32_iopin crisv32_led3_red; | ||
47 | |||
48 | /* Dummy port used when green LED and red LED is on the same bit */ | ||
49 | static unsigned long io_dummy; | ||
50 | static struct crisv32_ioport dummy_port = { | ||
51 | &io_dummy, | ||
52 | &io_dummy, | ||
53 | &io_dummy, | ||
54 | 32 | ||
55 | }; | ||
56 | static struct crisv32_iopin dummy_led = { | ||
57 | &dummy_port, | ||
58 | 0 | ||
59 | }; | ||
60 | |||
61 | static int __init crisv32_io_init(void) | ||
62 | { | ||
63 | int ret = 0; | ||
64 | |||
65 | u32 i; | ||
66 | |||
67 | /* Locks *should* be dynamically initialized. */ | ||
68 | for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++) | ||
69 | spin_lock_init(&crisv32_ioports[i].lock); | ||
70 | spin_lock_init(&dummy_port.lock); | ||
71 | |||
72 | /* Initialize LEDs */ | ||
73 | #if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) | ||
74 | ret += crisv32_io_get_name(&crisv32_led_net0_green, | ||
75 | CONFIG_ETRAX_LED_G_NET0); | ||
76 | crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out); | ||
77 | if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) { | ||
78 | ret += crisv32_io_get_name(&crisv32_led_net0_red, | ||
79 | CONFIG_ETRAX_LED_R_NET0); | ||
80 | crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out); | ||
81 | } else | ||
82 | crisv32_led_net0_red = dummy_led; | ||
83 | #endif | ||
84 | |||
85 | ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G); | ||
86 | ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R); | ||
87 | ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G); | ||
88 | ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R); | ||
89 | |||
90 | crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); | ||
91 | crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); | ||
92 | crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); | ||
93 | crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); | ||
94 | |||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | __initcall(crisv32_io_init); | ||
99 | |||
100 | int crisv32_io_get(struct crisv32_iopin *iopin, | ||
101 | unsigned int port, unsigned int pin) | ||
102 | { | ||
103 | if (port > NBR_OF_PORTS) | ||
104 | return -EINVAL; | ||
105 | if (port > crisv32_ioports[port].pin_count) | ||
106 | return -EINVAL; | ||
107 | |||
108 | iopin->bit = 1 << pin; | ||
109 | iopin->port = &crisv32_ioports[port]; | ||
110 | |||
111 | if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) | ||
112 | return -EIO; | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name) | ||
118 | { | ||
119 | int port; | ||
120 | int pin; | ||
121 | |||
122 | if (toupper(*name) == 'P') | ||
123 | name++; | ||
124 | |||
125 | if (toupper(*name) < 'A' || toupper(*name) > 'E') | ||
126 | return -EINVAL; | ||
127 | |||
128 | port = toupper(*name) - 'A'; | ||
129 | name++; | ||
130 | pin = simple_strtoul(name, NULL, 10); | ||
131 | |||
132 | if (pin < 0 || pin > crisv32_ioports[port].pin_count) | ||
133 | return -EINVAL; | ||
134 | |||
135 | iopin->bit = 1 << pin; | ||
136 | iopin->port = &crisv32_ioports[port]; | ||
137 | |||
138 | if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio)) | ||
139 | return -EIO; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | #ifdef CONFIG_PCI | ||
145 | /* PCI I/O access stuff */ | ||
146 | struct cris_io_operations *cris_iops = NULL; | ||
147 | EXPORT_SYMBOL(cris_iops); | ||
148 | #endif | ||
149 | |||
diff --git a/arch/cris/arch-v32/mach-a3/pinmux.c b/arch/cris/arch-v32/mach-a3/pinmux.c new file mode 100644 index 000000000000..0a28c9bedfb7 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/pinmux.c | |||
@@ -0,0 +1,386 @@ | |||
1 | /* | ||
2 | * Allocator for I/O pins. All pins are allocated to GPIO at bootup. | ||
3 | * Unassigned pins and GPIO pins can be allocated to a fixed interface | ||
4 | * or the I/O processor instead. | ||
5 | * | ||
6 | * Copyright (c) 2005-2007 Axis Communications AB. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <hwregs/reg_map.h> | ||
15 | #include <hwregs/reg_rdwr.h> | ||
16 | #include <pinmux.h> | ||
17 | #include <hwregs/pinmux_defs.h> | ||
18 | #include <hwregs/clkgen_defs.h> | ||
19 | |||
20 | #undef DEBUG | ||
21 | |||
22 | #define PINS 80 | ||
23 | #define PORT_PINS 32 | ||
24 | #define PORTS 3 | ||
25 | |||
26 | static char pins[PINS]; | ||
27 | static DEFINE_SPINLOCK(pinmux_lock); | ||
28 | |||
29 | static void crisv32_pinmux_set(int port); | ||
30 | |||
31 | int | ||
32 | crisv32_pinmux_init(void) | ||
33 | { | ||
34 | static int initialized; | ||
35 | |||
36 | if (!initialized) { | ||
37 | initialized = 1; | ||
38 | REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0); | ||
39 | crisv32_pinmux_alloc(PORT_A, 0, 31, pinmux_gpio); | ||
40 | crisv32_pinmux_alloc(PORT_B, 0, 31, pinmux_gpio); | ||
41 | crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_gpio); | ||
42 | } | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | int | ||
48 | crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) | ||
49 | { | ||
50 | int i; | ||
51 | unsigned long flags; | ||
52 | |||
53 | crisv32_pinmux_init(); | ||
54 | |||
55 | if (port >= PORTS) | ||
56 | return -EINVAL; | ||
57 | |||
58 | spin_lock_irqsave(&pinmux_lock, flags); | ||
59 | |||
60 | for (i = first_pin; i <= last_pin; i++) { | ||
61 | if ((pins[port * PORT_PINS + i] != pinmux_none) && | ||
62 | (pins[port * PORT_PINS + i] != pinmux_gpio) && | ||
63 | (pins[port * PORT_PINS + i] != mode)) { | ||
64 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
65 | #ifdef DEBUG | ||
66 | panic("Pinmux alloc failed!\n"); | ||
67 | #endif | ||
68 | return -EPERM; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | for (i = first_pin; i <= last_pin; i++) | ||
73 | pins[port * PORT_PINS + i] = mode; | ||
74 | |||
75 | crisv32_pinmux_set(port); | ||
76 | |||
77 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | crisv32_pinmux_alloc_fixed(enum fixed_function function) | ||
84 | { | ||
85 | int ret = -EINVAL; | ||
86 | char saved[sizeof pins]; | ||
87 | unsigned long flags; | ||
88 | |||
89 | spin_lock_irqsave(&pinmux_lock, flags); | ||
90 | |||
91 | /* Save internal data for recovery */ | ||
92 | memcpy(saved, pins, sizeof pins); | ||
93 | |||
94 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ | ||
95 | |||
96 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
97 | reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen, | ||
98 | rw_clk_ctrl); | ||
99 | |||
100 | switch (function) { | ||
101 | case pinmux_eth: | ||
102 | clk_ctrl.eth = regk_clkgen_yes; | ||
103 | clk_ctrl.dma0_1_eth = regk_clkgen_yes; | ||
104 | ret = crisv32_pinmux_alloc(PORT_B, 8, 23, pinmux_fixed); | ||
105 | ret |= crisv32_pinmux_alloc(PORT_B, 24, 25, pinmux_fixed); | ||
106 | hwprot.eth = hwprot.eth_mdio = regk_pinmux_yes; | ||
107 | break; | ||
108 | case pinmux_geth: | ||
109 | ret = crisv32_pinmux_alloc(PORT_B, 0, 7, pinmux_fixed); | ||
110 | hwprot.geth = regk_pinmux_yes; | ||
111 | break; | ||
112 | case pinmux_tg_cmos: | ||
113 | clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes; | ||
114 | ret = crisv32_pinmux_alloc(PORT_B, 27, 29, pinmux_fixed); | ||
115 | hwprot.tg_clk = regk_pinmux_yes; | ||
116 | break; | ||
117 | case pinmux_tg_ccd: | ||
118 | clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes; | ||
119 | ret = crisv32_pinmux_alloc(PORT_B, 27, 31, pinmux_fixed); | ||
120 | ret |= crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_fixed); | ||
121 | hwprot.tg = hwprot.tg_clk = regk_pinmux_yes; | ||
122 | break; | ||
123 | case pinmux_vout: | ||
124 | clk_ctrl.strdma0_2_video = regk_clkgen_yes; | ||
125 | ret = crisv32_pinmux_alloc(PORT_A, 8, 18, pinmux_fixed); | ||
126 | hwprot.vout = hwprot.vout_sync = regk_pinmux_yes; | ||
127 | break; | ||
128 | case pinmux_ser1: | ||
129 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
130 | ret = crisv32_pinmux_alloc(PORT_A, 24, 25, pinmux_fixed); | ||
131 | hwprot.ser1 = regk_pinmux_yes; | ||
132 | break; | ||
133 | case pinmux_ser2: | ||
134 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
135 | ret = crisv32_pinmux_alloc(PORT_A, 26, 27, pinmux_fixed); | ||
136 | hwprot.ser2 = regk_pinmux_yes; | ||
137 | break; | ||
138 | case pinmux_ser3: | ||
139 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
140 | ret = crisv32_pinmux_alloc(PORT_A, 28, 29, pinmux_fixed); | ||
141 | hwprot.ser3 = regk_pinmux_yes; | ||
142 | break; | ||
143 | case pinmux_ser4: | ||
144 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
145 | ret = crisv32_pinmux_alloc(PORT_A, 30, 31, pinmux_fixed); | ||
146 | hwprot.ser4 = regk_pinmux_yes; | ||
147 | break; | ||
148 | case pinmux_sser: | ||
149 | clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; | ||
150 | ret = crisv32_pinmux_alloc(PORT_A, 19, 23, pinmux_fixed); | ||
151 | hwprot.sser = regk_pinmux_yes; | ||
152 | break; | ||
153 | case pinmux_pio: | ||
154 | hwprot.pio = regk_pinmux_yes; | ||
155 | ret = 0; | ||
156 | break; | ||
157 | case pinmux_pwm0: | ||
158 | ret = crisv32_pinmux_alloc(PORT_A, 30, 30, pinmux_fixed); | ||
159 | hwprot.pwm0 = regk_pinmux_yes; | ||
160 | break; | ||
161 | case pinmux_pwm1: | ||
162 | ret = crisv32_pinmux_alloc(PORT_A, 31, 31, pinmux_fixed); | ||
163 | hwprot.pwm1 = regk_pinmux_yes; | ||
164 | break; | ||
165 | case pinmux_pwm2: | ||
166 | ret = crisv32_pinmux_alloc(PORT_B, 26, 26, pinmux_fixed); | ||
167 | hwprot.pwm2 = regk_pinmux_yes; | ||
168 | break; | ||
169 | case pinmux_i2c0: | ||
170 | ret = crisv32_pinmux_alloc(PORT_A, 0, 1, pinmux_fixed); | ||
171 | hwprot.i2c0 = regk_pinmux_yes; | ||
172 | break; | ||
173 | case pinmux_i2c1: | ||
174 | ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); | ||
175 | hwprot.i2c1 = regk_pinmux_yes; | ||
176 | break; | ||
177 | case pinmux_i2c1_3wire: | ||
178 | ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); | ||
179 | ret |= crisv32_pinmux_alloc(PORT_A, 7, 7, pinmux_fixed); | ||
180 | hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_yes; | ||
181 | break; | ||
182 | case pinmux_i2c1_sda1: | ||
183 | ret = crisv32_pinmux_alloc(PORT_A, 2, 4, pinmux_fixed); | ||
184 | hwprot.i2c1 = hwprot.i2c1_sda1 = regk_pinmux_yes; | ||
185 | break; | ||
186 | case pinmux_i2c1_sda2: | ||
187 | ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); | ||
188 | ret |= crisv32_pinmux_alloc(PORT_A, 5, 5, pinmux_fixed); | ||
189 | hwprot.i2c1 = hwprot.i2c1_sda2 = regk_pinmux_yes; | ||
190 | break; | ||
191 | case pinmux_i2c1_sda3: | ||
192 | ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); | ||
193 | ret |= crisv32_pinmux_alloc(PORT_A, 6, 6, pinmux_fixed); | ||
194 | hwprot.i2c1 = hwprot.i2c1_sda3 = regk_pinmux_yes; | ||
195 | break; | ||
196 | default: | ||
197 | ret = -EINVAL; | ||
198 | break; | ||
199 | } | ||
200 | |||
201 | if (!ret) { | ||
202 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
203 | REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); | ||
204 | } else | ||
205 | memcpy(pins, saved, sizeof pins); | ||
206 | |||
207 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
208 | |||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | void | ||
213 | crisv32_pinmux_set(int port) | ||
214 | { | ||
215 | int i; | ||
216 | int gpio_val = 0; | ||
217 | int iop_val = 0; | ||
218 | int pin = port * PORT_PINS; | ||
219 | |||
220 | for (i = 0; (i < PORT_PINS) && (pin < PINS); i++, pin++) { | ||
221 | if (pins[pin] == pinmux_gpio) | ||
222 | gpio_val |= (1 << i); | ||
223 | else if (pins[pin] == pinmux_iop) | ||
224 | iop_val |= (1 << i); | ||
225 | } | ||
226 | |||
227 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_gio_pa + 4 * port, | ||
228 | gpio_val); | ||
229 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_iop_pa + 4 * port, | ||
230 | iop_val); | ||
231 | |||
232 | #ifdef DEBUG | ||
233 | crisv32_pinmux_dump(); | ||
234 | #endif | ||
235 | } | ||
236 | |||
237 | int | ||
238 | crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) | ||
239 | { | ||
240 | int i; | ||
241 | unsigned long flags; | ||
242 | |||
243 | crisv32_pinmux_init(); | ||
244 | |||
245 | if (port > PORTS) | ||
246 | return -EINVAL; | ||
247 | |||
248 | spin_lock_irqsave(&pinmux_lock, flags); | ||
249 | |||
250 | for (i = first_pin; i <= last_pin; i++) | ||
251 | pins[port * PORT_PINS + i] = pinmux_none; | ||
252 | |||
253 | crisv32_pinmux_set(port); | ||
254 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | int | ||
260 | crisv32_pinmux_dealloc_fixed(enum fixed_function function) | ||
261 | { | ||
262 | int ret = -EINVAL; | ||
263 | char saved[sizeof pins]; | ||
264 | unsigned long flags; | ||
265 | |||
266 | spin_lock_irqsave(&pinmux_lock, flags); | ||
267 | |||
268 | /* Save internal data for recovery */ | ||
269 | memcpy(saved, pins, sizeof pins); | ||
270 | |||
271 | crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ | ||
272 | |||
273 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
274 | |||
275 | switch (function) { | ||
276 | case pinmux_eth: | ||
277 | ret = crisv32_pinmux_dealloc(PORT_B, 8, 23); | ||
278 | ret |= crisv32_pinmux_dealloc(PORT_B, 24, 25); | ||
279 | ret |= crisv32_pinmux_dealloc(PORT_B, 0, 7); | ||
280 | hwprot.eth = hwprot.eth_mdio = hwprot.geth = regk_pinmux_no; | ||
281 | break; | ||
282 | case pinmux_tg_cmos: | ||
283 | ret = crisv32_pinmux_dealloc(PORT_B, 27, 29); | ||
284 | hwprot.tg_clk = regk_pinmux_no; | ||
285 | break; | ||
286 | case pinmux_tg_ccd: | ||
287 | ret = crisv32_pinmux_dealloc(PORT_B, 27, 31); | ||
288 | ret |= crisv32_pinmux_dealloc(PORT_C, 0, 15); | ||
289 | hwprot.tg = hwprot.tg_clk = regk_pinmux_no; | ||
290 | break; | ||
291 | case pinmux_vout: | ||
292 | ret = crisv32_pinmux_dealloc(PORT_A, 8, 18); | ||
293 | hwprot.vout = hwprot.vout_sync = regk_pinmux_no; | ||
294 | break; | ||
295 | case pinmux_ser1: | ||
296 | ret = crisv32_pinmux_dealloc(PORT_A, 24, 25); | ||
297 | hwprot.ser1 = regk_pinmux_no; | ||
298 | break; | ||
299 | case pinmux_ser2: | ||
300 | ret = crisv32_pinmux_dealloc(PORT_A, 26, 27); | ||
301 | hwprot.ser2 = regk_pinmux_no; | ||
302 | break; | ||
303 | case pinmux_ser3: | ||
304 | ret = crisv32_pinmux_dealloc(PORT_A, 28, 29); | ||
305 | hwprot.ser3 = regk_pinmux_no; | ||
306 | break; | ||
307 | case pinmux_ser4: | ||
308 | ret = crisv32_pinmux_dealloc(PORT_A, 30, 31); | ||
309 | hwprot.ser4 = regk_pinmux_no; | ||
310 | break; | ||
311 | case pinmux_sser: | ||
312 | ret = crisv32_pinmux_dealloc(PORT_A, 19, 23); | ||
313 | hwprot.sser = regk_pinmux_no; | ||
314 | break; | ||
315 | case pinmux_pwm0: | ||
316 | ret = crisv32_pinmux_dealloc(PORT_A, 30, 30); | ||
317 | hwprot.pwm0 = regk_pinmux_no; | ||
318 | break; | ||
319 | case pinmux_pwm1: | ||
320 | ret = crisv32_pinmux_dealloc(PORT_A, 31, 31); | ||
321 | hwprot.pwm1 = regk_pinmux_no; | ||
322 | break; | ||
323 | case pinmux_pwm2: | ||
324 | ret = crisv32_pinmux_dealloc(PORT_B, 26, 26); | ||
325 | hwprot.pwm2 = regk_pinmux_no; | ||
326 | break; | ||
327 | case pinmux_i2c0: | ||
328 | ret = crisv32_pinmux_dealloc(PORT_A, 0, 1); | ||
329 | hwprot.i2c0 = regk_pinmux_no; | ||
330 | break; | ||
331 | case pinmux_i2c1: | ||
332 | ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); | ||
333 | hwprot.i2c1 = regk_pinmux_no; | ||
334 | break; | ||
335 | case pinmux_i2c1_3wire: | ||
336 | ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); | ||
337 | ret |= crisv32_pinmux_dealloc(PORT_A, 7, 7); | ||
338 | hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_no; | ||
339 | break; | ||
340 | case pinmux_i2c1_sda1: | ||
341 | ret = crisv32_pinmux_dealloc(PORT_A, 2, 4); | ||
342 | hwprot.i2c1_sda1 = regk_pinmux_no; | ||
343 | break; | ||
344 | case pinmux_i2c1_sda2: | ||
345 | ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); | ||
346 | ret |= crisv32_pinmux_dealloc(PORT_A, 5, 5); | ||
347 | hwprot.i2c1_sda2 = regk_pinmux_no; | ||
348 | break; | ||
349 | case pinmux_i2c1_sda3: | ||
350 | ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); | ||
351 | ret |= crisv32_pinmux_dealloc(PORT_A, 6, 6); | ||
352 | hwprot.i2c1_sda3 = regk_pinmux_no; | ||
353 | break; | ||
354 | default: | ||
355 | ret = -EINVAL; | ||
356 | break; | ||
357 | } | ||
358 | |||
359 | if (!ret) | ||
360 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
361 | else | ||
362 | memcpy(pins, saved, sizeof pins); | ||
363 | |||
364 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | void | ||
370 | crisv32_pinmux_dump(void) | ||
371 | { | ||
372 | int i, j; | ||
373 | int pin = 0; | ||
374 | |||
375 | crisv32_pinmux_init(); | ||
376 | |||
377 | for (i = 0; i < PORTS; i++) { | ||
378 | pin++; | ||
379 | printk(KERN_DEBUG "Port %c\n", 'A'+i); | ||
380 | for (j = 0; (j < PORT_PINS) && (pin < PINS); j++, pin++) | ||
381 | printk(KERN_DEBUG | ||
382 | " Pin %d = %d\n", j, pins[i * PORT_PINS + j]); | ||
383 | } | ||
384 | } | ||
385 | |||
386 | __initcall(crisv32_pinmux_init); | ||
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.c b/arch/cris/arch-v32/mach-a3/vcs_hook.c new file mode 100644 index 000000000000..58b1a5469fd7 --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/vcs_hook.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * Simulator hook mechanism | ||
3 | */ | ||
4 | |||
5 | #include "vcs_hook.h" | ||
6 | #include <asm/io.h> | ||
7 | #include <stdarg.h> | ||
8 | |||
9 | #define HOOK_TRIG_ADDR 0xb7000000 | ||
10 | #define HOOK_MEM_BASE_ADDR 0xce000000 | ||
11 | |||
12 | static volatile unsigned *hook_base; | ||
13 | |||
14 | #define HOOK_DATA(offset) hook_base[offset] | ||
15 | #define VHOOK_DATA(offset) hook_base[offset] | ||
16 | #define HOOK_TRIG(funcid) \ | ||
17 | do { \ | ||
18 | *((unsigned *) HOOK_TRIG_ADDR) = funcid; \ | ||
19 | } while (0) | ||
20 | #define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset] | ||
21 | |||
22 | static void hook_init(void) | ||
23 | { | ||
24 | static int first = 1; | ||
25 | if (first) { | ||
26 | first = 0; | ||
27 | hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | static unsigned hook_trig(unsigned id) | ||
32 | { | ||
33 | unsigned ret; | ||
34 | |||
35 | /* preempt_disable(); */ | ||
36 | |||
37 | /* Dummy read from mem to make sure data has propagated to memory | ||
38 | * before trigging */ | ||
39 | ret = *hook_base; | ||
40 | |||
41 | /* trigger hook */ | ||
42 | HOOK_TRIG(id); | ||
43 | |||
44 | /* wait for call to finish */ | ||
45 | while (VHOOK_DATA(0) > 0) ; | ||
46 | |||
47 | /* extract return value */ | ||
48 | |||
49 | ret = VHOOK_DATA(1); | ||
50 | |||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | int hook_call(unsigned id, unsigned pcnt, ...) | ||
55 | { | ||
56 | va_list ap; | ||
57 | int i; | ||
58 | unsigned ret; | ||
59 | |||
60 | hook_init(); | ||
61 | |||
62 | HOOK_DATA(0) = id; | ||
63 | |||
64 | va_start(ap, pcnt); | ||
65 | for (i = 1; i <= pcnt; i++) | ||
66 | HOOK_DATA(i) = va_arg(ap, unsigned); | ||
67 | va_end(ap); | ||
68 | |||
69 | ret = hook_trig(id); | ||
70 | |||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | int hook_call_str(unsigned id, unsigned size, const char *str) | ||
75 | { | ||
76 | int i; | ||
77 | unsigned ret; | ||
78 | |||
79 | hook_init(); | ||
80 | |||
81 | HOOK_DATA(0) = id; | ||
82 | HOOK_DATA(1) = size; | ||
83 | |||
84 | for (i = 0; i < size; i++) | ||
85 | HOOK_DATA_BYTE(8 + i) = str[i]; | ||
86 | HOOK_DATA_BYTE(8 + i) = 0; | ||
87 | |||
88 | ret = hook_trig(id); | ||
89 | |||
90 | return ret; | ||
91 | } | ||
92 | |||
93 | void print_str(const char *str) | ||
94 | { | ||
95 | int i; | ||
96 | /* find null at end of string */ | ||
97 | for (i = 1; str[i]; i++) ; | ||
98 | hook_call(hook_print_str, i, str); | ||
99 | } | ||
100 | |||
101 | void CPU_WATCHDOG_TIMEOUT(unsigned t) | ||
102 | { | ||
103 | } | ||
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.h b/arch/cris/arch-v32/mach-a3/vcs_hook.h new file mode 100644 index 000000000000..8b73d0e8392d --- /dev/null +++ b/arch/cris/arch-v32/mach-a3/vcs_hook.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Simulator hook call mechanism | ||
3 | */ | ||
4 | |||
5 | #ifndef __hook_h__ | ||
6 | #define __hook_h__ | ||
7 | |||
8 | int hook_call(unsigned id, unsigned pcnt, ...); | ||
9 | int hook_call_str(unsigned id, unsigned size, const char *str); | ||
10 | |||
11 | enum hook_ids { | ||
12 | hook_debug_on = 1, | ||
13 | hook_debug_off, | ||
14 | hook_stop_sim_ok, | ||
15 | hook_stop_sim_fail, | ||
16 | hook_alloc_shared, | ||
17 | hook_ptr_shared, | ||
18 | hook_free_shared, | ||
19 | hook_file2shared, | ||
20 | hook_cmp_shared, | ||
21 | hook_print_params, | ||
22 | hook_sim_time, | ||
23 | hook_stop_sim, | ||
24 | hook_kick_dog, | ||
25 | hook_dog_timeout, | ||
26 | hook_rand, | ||
27 | hook_srand, | ||
28 | hook_rand_range, | ||
29 | hook_print_str, | ||
30 | hook_print_hex, | ||
31 | hook_cmp_offset_shared, | ||
32 | hook_fill_random_shared, | ||
33 | hook_alloc_random_data, | ||
34 | hook_calloc_random_data, | ||
35 | hook_print_int, | ||
36 | hook_print_uint, | ||
37 | hook_fputc, | ||
38 | hook_init_fd, | ||
39 | hook_sbrk, | ||
40 | hook_print_context_descr, | ||
41 | hook_print_data_descr, | ||
42 | hook_print_group_descr, | ||
43 | hook_fill_shared, | ||
44 | hook_sl_srand, | ||
45 | hook_sl_rand_irange, | ||
46 | hook_sl_rand_urange, | ||
47 | hook_sl_sh_malloc_aligned, | ||
48 | hook_sl_sh_calloc_aligned, | ||
49 | hook_sl_sh_alloc_random_data, | ||
50 | hook_sl_sh_file2mem, | ||
51 | hook_sl_vera_mbox_handle, | ||
52 | hook_sl_vera_mbox_put, | ||
53 | hook_sl_vera_mbox_get, | ||
54 | hook_sl_system, | ||
55 | hook_sl_sh_hexdump | ||
56 | }; | ||
57 | |||
58 | #endif | ||
diff --git a/arch/cris/arch-v32/mach-fs/Kconfig b/arch/cris/arch-v32/mach-fs/Kconfig new file mode 100644 index 000000000000..f6d74475f1c6 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/Kconfig | |||
@@ -0,0 +1,216 @@ | |||
1 | if ETRAXFS | ||
2 | |||
3 | menu "ETRAX FS options" | ||
4 | depends on ETRAXFS | ||
5 | |||
6 | config ETRAX_DRAM_VIRTUAL_BASE | ||
7 | hex | ||
8 | depends on ETRAX_ARCH_V32 | ||
9 | default "c0000000" | ||
10 | |||
11 | config ETRAX_SERIAL_PORTS | ||
12 | int | ||
13 | default 4 | ||
14 | |||
15 | config ETRAX_MEM_GRP1_CONFIG | ||
16 | hex "MEM_GRP1_CONFIG" | ||
17 | depends on ETRAX_ARCH_V32 | ||
18 | default "4044a" | ||
19 | help | ||
20 | Waitstates for flash. The default value is suitable for the | ||
21 | standard flashes used in axis products (120 ns). | ||
22 | |||
23 | config ETRAX_MEM_GRP2_CONFIG | ||
24 | hex "MEM_GRP2_CONFIG" | ||
25 | depends on ETRAX_ARCH_V32 | ||
26 | default "0" | ||
27 | help | ||
28 | Waitstates for SRAM. 0 is a good choice for most Axis products. | ||
29 | |||
30 | config ETRAX_MEM_GRP3_CONFIG | ||
31 | hex "MEM_GRP3_CONFIG" | ||
32 | depends on ETRAX_ARCH_V32 | ||
33 | default "0" | ||
34 | help | ||
35 | Waitstates for CSP0-3. 0 is a good choice for most Axis products. | ||
36 | It may need to be changed if external devices such as extra | ||
37 | register-mapped LEDs are used. | ||
38 | |||
39 | config ETRAX_MEM_GRP4_CONFIG | ||
40 | hex "MEM_GRP4_CONFIG" | ||
41 | depends on ETRAX_ARCH_V32 | ||
42 | default "0" | ||
43 | help | ||
44 | Waitstates for CSP4-6. 0 is a good choice for most Axis products. | ||
45 | |||
46 | config ETRAX_SDRAM_GRP0_CONFIG | ||
47 | hex "SDRAM_GRP0_CONFIG" | ||
48 | depends on ETRAX_ARCH_V32 | ||
49 | default "336" | ||
50 | help | ||
51 | SDRAM configuration for group 0. The value depends on the | ||
52 | hardware configuration. The default value is suitable | ||
53 | for 32 MB organized as two 16 bits chips (e.g. Axis | ||
54 | part number 18550) connected as one 32 bit device (i.e. in | ||
55 | the same group). | ||
56 | |||
57 | config ETRAX_SDRAM_GRP1_CONFIG | ||
58 | hex "SDRAM_GRP1_CONFIG" | ||
59 | depends on ETRAX_ARCH_V32 | ||
60 | default "0" | ||
61 | help | ||
62 | SDRAM configuration for group 1. The defult value is 0 | ||
63 | because group 1 is not used in the default configuration, | ||
64 | described in the help for SDRAM_GRP0_CONFIG. | ||
65 | |||
66 | config ETRAX_SDRAM_TIMING | ||
67 | hex "SDRAM_TIMING" | ||
68 | depends on ETRAX_ARCH_V32 | ||
69 | default "104a" | ||
70 | help | ||
71 | SDRAM timing parameters. The default value is ok for | ||
72 | most hardwares but large SDRAMs may require a faster | ||
73 | refresh (a.k.a 8K refresh). The default value implies | ||
74 | 100MHz clock and SDR mode. | ||
75 | |||
76 | config ETRAX_SDRAM_COMMAND | ||
77 | hex "SDRAM_COMMAND" | ||
78 | depends on ETRAX_ARCH_V32 | ||
79 | default "0" | ||
80 | help | ||
81 | SDRAM command. Should be 0 unless you really know what | ||
82 | you are doing (may be != 0 for unusual address line | ||
83 | mappings such as in a MCM).. | ||
84 | |||
85 | config ETRAX_DEF_GIO_PA_OE | ||
86 | hex "GIO_PA_OE" | ||
87 | depends on ETRAX_ARCH_V32 | ||
88 | default "1c" | ||
89 | help | ||
90 | Configures the direction of general port A bits. 1 is out, 0 is in. | ||
91 | This is often totally different depending on the product used. | ||
92 | There are some guidelines though - if you know that only LED's are | ||
93 | connected to port PA, then they are usually connected to bits 2-4 | ||
94 | and you can therefore use 1c. On other boards which don't have the | ||
95 | LED's at the general ports, these bits are used for all kinds of | ||
96 | stuff. If you don't know what to use, it is always safe to put all | ||
97 | as inputs, although floating inputs isn't good. | ||
98 | |||
99 | config ETRAX_DEF_GIO_PA_OUT | ||
100 | hex "GIO_PA_OUT" | ||
101 | depends on ETRAX_ARCH_V32 | ||
102 | default "00" | ||
103 | help | ||
104 | Configures the initial data for the general port A bits. Most | ||
105 | products should use 00 here. | ||
106 | |||
107 | config ETRAX_DEF_GIO_PB_OE | ||
108 | hex "GIO_PB_OE" | ||
109 | depends on ETRAX_ARCH_V32 | ||
110 | default "00000" | ||
111 | help | ||
112 | Configures the direction of general port B bits. 1 is out, 0 is in. | ||
113 | This is often totally different depending on the product used. | ||
114 | There are some guidelines though - if you know that only LED's are | ||
115 | connected to port PA, then they are usually connected to bits 2-4 | ||
116 | and you can therefore use 1c. On other boards which don't have the | ||
117 | LED's at the general ports, these bits are used for all kinds of | ||
118 | stuff. If you don't know what to use, it is always safe to put all | ||
119 | as inputs, although floating inputs isn't good. | ||
120 | |||
121 | config ETRAX_DEF_GIO_PB_OUT | ||
122 | hex "GIO_PB_OUT" | ||
123 | depends on ETRAX_ARCH_V32 | ||
124 | default "00000" | ||
125 | help | ||
126 | Configures the initial data for the general port B bits. Most | ||
127 | products should use 00000 here. | ||
128 | |||
129 | config ETRAX_DEF_GIO_PC_OE | ||
130 | hex "GIO_PC_OE" | ||
131 | depends on ETRAX_ARCH_V32 | ||
132 | default "00000" | ||
133 | help | ||
134 | Configures the direction of general port C bits. 1 is out, 0 is in. | ||
135 | This is often totally different depending on the product used. | ||
136 | There are some guidelines though - if you know that only LED's are | ||
137 | connected to port PA, then they are usually connected to bits 2-4 | ||
138 | and you can therefore use 1c. On other boards which don't have the | ||
139 | LED's at the general ports, these bits are used for all kinds of | ||
140 | stuff. If you don't know what to use, it is always safe to put all | ||
141 | as inputs, although floating inputs isn't good. | ||
142 | |||
143 | config ETRAX_DEF_GIO_PC_OUT | ||
144 | hex "GIO_PC_OUT" | ||
145 | depends on ETRAX_ARCH_V32 | ||
146 | default "00000" | ||
147 | help | ||
148 | Configures the initial data for the general port C bits. Most | ||
149 | products should use 00000 here. | ||
150 | |||
151 | config ETRAX_DEF_GIO_PD_OE | ||
152 | hex "GIO_PD_OE" | ||
153 | depends on ETRAX_ARCH_V32 | ||
154 | default "00000" | ||
155 | help | ||
156 | Configures the direction of general port D bits. 1 is out, 0 is in. | ||
157 | This is often totally different depending on the product used. | ||
158 | There are some guidelines though - if you know that only LED's are | ||
159 | connected to port PA, then they are usually connected to bits 2-4 | ||
160 | and you can therefore use 1c. On other boards which don't have the | ||
161 | LED's at the general ports, these bits are used for all kinds of | ||
162 | stuff. If you don't know what to use, it is always safe to put all | ||
163 | as inputs, although floating inputs isn't good. | ||
164 | |||
165 | config ETRAX_DEF_GIO_PD_OUT | ||
166 | hex "GIO_PD_OUT" | ||
167 | depends on ETRAX_ARCH_V32 | ||
168 | default "00000" | ||
169 | help | ||
170 | Configures the initial data for the general port D bits. Most | ||
171 | products should use 00000 here. | ||
172 | |||
173 | config ETRAX_DEF_GIO_PE_OE | ||
174 | hex "GIO_PE_OE" | ||
175 | depends on ETRAX_ARCH_V32 | ||
176 | default "00000" | ||
177 | help | ||
178 | Configures the direction of general port E bits. 1 is out, 0 is in. | ||
179 | This is often totally different depending on the product used. | ||
180 | There are some guidelines though - if you know that only LED's are | ||
181 | connected to port PA, then they are usually connected to bits 2-4 | ||
182 | and you can therefore use 1c. On other boards which don't have the | ||
183 | LED's at the general ports, these bits are used for all kinds of | ||
184 | stuff. If you don't know what to use, it is always safe to put all | ||
185 | as inputs, although floating inputs isn't good. | ||
186 | |||
187 | config ETRAX_DEF_GIO_PE_OUT | ||
188 | hex "GIO_PE_OUT" | ||
189 | depends on ETRAX_ARCH_V32 | ||
190 | default "00000" | ||
191 | help | ||
192 | Configures the initial data for the general port E bits. Most | ||
193 | products should use 00000 here. | ||
194 | |||
195 | config ETRAX_DEF_GIO_PV_OE | ||
196 | hex "GIO_PV_OE" | ||
197 | depends on ETRAX_VIRTUAL_GPIO | ||
198 | default "0000" | ||
199 | help | ||
200 | Configures the direction of virtual general port V bits. 1 is out, | ||
201 | 0 is in. This is often totally different depending on the product | ||
202 | used. These bits are used for all kinds of stuff. If you don't know | ||
203 | what to use, it is always safe to put all as inputs, although | ||
204 | floating inputs isn't good. | ||
205 | |||
206 | config ETRAX_DEF_GIO_PV_OUT | ||
207 | hex "GIO_PV_OUT" | ||
208 | depends on ETRAX_VIRTUAL_GPIO | ||
209 | default "0000" | ||
210 | help | ||
211 | Configures the initial data for the virtual general port V bits. | ||
212 | Most products should use 0000 here. | ||
213 | |||
214 | endmenu | ||
215 | |||
216 | endif | ||
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile new file mode 100644 index 000000000000..4ff407a1b931 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | obj-y := dma.o pinmux.o io.o arbiter.o | ||
7 | bj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o | ||
8 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
9 | |||
10 | clean: | ||
11 | |||
diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c new file mode 100644 index 000000000000..84d31bd7b692 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/arbiter.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * Memory arbiter functions. Allocates bandwidth through the | ||
3 | * arbiter and sets up arbiter breakpoints. | ||
4 | * | ||
5 | * The algorithm first assigns slots to the clients that has specified | ||
6 | * bandwidth (e.g. ethernet) and then the remaining slots are divided | ||
7 | * on all the active clients. | ||
8 | * | ||
9 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
10 | */ | ||
11 | |||
12 | #include <hwregs/reg_map.h> | ||
13 | #include <hwregs/reg_rdwr.h> | ||
14 | #include <hwregs/marb_defs.h> | ||
15 | #include <arbiter.h> | ||
16 | #include <hwregs/intr_vect.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/irq_regs.h> | ||
23 | |||
24 | struct crisv32_watch_entry { | ||
25 | unsigned long instance; | ||
26 | watch_callback *cb; | ||
27 | unsigned long start; | ||
28 | unsigned long end; | ||
29 | int used; | ||
30 | }; | ||
31 | |||
32 | #define NUMBER_OF_BP 4 | ||
33 | #define NBR_OF_CLIENTS 14 | ||
34 | #define NBR_OF_SLOTS 64 | ||
35 | #define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ | ||
36 | #define INTMEM_BANDWIDTH 400000000 | ||
37 | #define NBR_OF_REGIONS 2 | ||
38 | |||
39 | static struct crisv32_watch_entry watches[NUMBER_OF_BP] = { | ||
40 | {regi_marb_bp0}, | ||
41 | {regi_marb_bp1}, | ||
42 | {regi_marb_bp2}, | ||
43 | {regi_marb_bp3} | ||
44 | }; | ||
45 | |||
46 | static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
47 | static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
48 | static int max_bandwidth[NBR_OF_REGIONS] = | ||
49 | { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH }; | ||
50 | |||
51 | DEFINE_SPINLOCK(arbiter_lock); | ||
52 | |||
53 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id); | ||
54 | |||
55 | /* | ||
56 | * "I'm the arbiter, I know the score. | ||
57 | * From square one I'll be watching all 64." | ||
58 | * (memory arbiter slots, that is) | ||
59 | * | ||
60 | * Or in other words: | ||
61 | * Program the memory arbiter slots for "region" according to what's | ||
62 | * in requested_slots[] and active_clients[], while minimizing | ||
63 | * latency. A caller may pass a non-zero positive amount for | ||
64 | * "unused_slots", which must then be the unallocated, remaining | ||
65 | * number of slots, free to hand out to any client. | ||
66 | */ | ||
67 | |||
68 | static void crisv32_arbiter_config(int region, int unused_slots) | ||
69 | { | ||
70 | int slot; | ||
71 | int client; | ||
72 | int interval = 0; | ||
73 | |||
74 | /* | ||
75 | * This vector corresponds to the hardware arbiter slots (see | ||
76 | * the hardware documentation for semantics). We initialize | ||
77 | * each slot with a suitable sentinel value outside the valid | ||
78 | * range {0 .. NBR_OF_CLIENTS - 1} and replace them with | ||
79 | * client indexes. Then it's fed to the hardware. | ||
80 | */ | ||
81 | s8 val[NBR_OF_SLOTS]; | ||
82 | |||
83 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | ||
84 | val[slot] = -1; | ||
85 | |||
86 | for (client = 0; client < NBR_OF_CLIENTS; client++) { | ||
87 | int pos; | ||
88 | /* Allocate the requested non-zero number of slots, but | ||
89 | * also give clients with zero-requests one slot each | ||
90 | * while stocks last. We do the latter here, in client | ||
91 | * order. This makes sure zero-request clients are the | ||
92 | * first to get to any spare slots, else those slots | ||
93 | * could, when bandwidth is allocated close to the limit, | ||
94 | * all be allocated to low-index non-zero-request clients | ||
95 | * in the default-fill loop below. Another positive but | ||
96 | * secondary effect is a somewhat better spread of the | ||
97 | * zero-bandwidth clients in the vector, avoiding some of | ||
98 | * the latency that could otherwise be caused by the | ||
99 | * partitioning of non-zero-bandwidth clients at low | ||
100 | * indexes and zero-bandwidth clients at high | ||
101 | * indexes. (Note that this spreading can only affect the | ||
102 | * unallocated bandwidth.) All the above only matters for | ||
103 | * memory-intensive situations, of course. | ||
104 | */ | ||
105 | if (!requested_slots[region][client]) { | ||
106 | /* | ||
107 | * Skip inactive clients. Also skip zero-slot | ||
108 | * allocations in this pass when there are no known | ||
109 | * free slots. | ||
110 | */ | ||
111 | if (!active_clients[region][client] | ||
112 | || unused_slots <= 0) | ||
113 | continue; | ||
114 | |||
115 | unused_slots--; | ||
116 | |||
117 | /* Only allocate one slot for this client. */ | ||
118 | interval = NBR_OF_SLOTS; | ||
119 | } else | ||
120 | interval = | ||
121 | NBR_OF_SLOTS / requested_slots[region][client]; | ||
122 | |||
123 | pos = 0; | ||
124 | while (pos < NBR_OF_SLOTS) { | ||
125 | if (val[pos] >= 0) | ||
126 | pos++; | ||
127 | else { | ||
128 | val[pos] = client; | ||
129 | pos += interval; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | client = 0; | ||
135 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) { | ||
136 | /* | ||
137 | * Allocate remaining slots in round-robin | ||
138 | * client-number order for active clients. For this | ||
139 | * pass, we ignore requested bandwidth and previous | ||
140 | * allocations. | ||
141 | */ | ||
142 | if (val[slot] < 0) { | ||
143 | int first = client; | ||
144 | while (!active_clients[region][client]) { | ||
145 | client = (client + 1) % NBR_OF_CLIENTS; | ||
146 | if (client == first) | ||
147 | break; | ||
148 | } | ||
149 | val[slot] = client; | ||
150 | client = (client + 1) % NBR_OF_CLIENTS; | ||
151 | } | ||
152 | if (region == EXT_REGION) | ||
153 | REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, | ||
154 | val[slot]); | ||
155 | else if (region == INT_REGION) | ||
156 | REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, | ||
157 | val[slot]); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | extern char _stext, _etext; | ||
162 | |||
163 | static void crisv32_arbiter_init(void) | ||
164 | { | ||
165 | static int initialized; | ||
166 | |||
167 | if (initialized) | ||
168 | return; | ||
169 | |||
170 | initialized = 1; | ||
171 | |||
172 | /* | ||
173 | * CPU caches are always set to active, but with zero | ||
174 | * bandwidth allocated. It should be ok to allocate zero | ||
175 | * bandwidth for the caches, because DMA for other channels | ||
176 | * will supposedly finish, once their programmed amount is | ||
177 | * done, and then the caches will get access according to the | ||
178 | * "fixed scheme" for unclaimed slots. Though, if for some | ||
179 | * use-case somewhere, there's a maximum CPU latency for | ||
180 | * e.g. some interrupt, we have to start allocating specific | ||
181 | * bandwidth for the CPU caches too. | ||
182 | */ | ||
183 | active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; | ||
184 | crisv32_arbiter_config(EXT_REGION, 0); | ||
185 | crisv32_arbiter_config(INT_REGION, 0); | ||
186 | |||
187 | if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, | ||
188 | "arbiter", NULL)) | ||
189 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | ||
190 | |||
191 | #ifndef CONFIG_ETRAX_KGDB | ||
192 | /* Global watch for writes to kernel text segment. */ | ||
193 | crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext, | ||
194 | arbiter_all_clients, arbiter_all_write, NULL); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | /* Main entry for bandwidth allocation. */ | ||
199 | |||
200 | int crisv32_arbiter_allocate_bandwidth(int client, int region, | ||
201 | unsigned long bandwidth) | ||
202 | { | ||
203 | int i; | ||
204 | int total_assigned = 0; | ||
205 | int total_clients = 0; | ||
206 | int req; | ||
207 | |||
208 | crisv32_arbiter_init(); | ||
209 | |||
210 | for (i = 0; i < NBR_OF_CLIENTS; i++) { | ||
211 | total_assigned += requested_slots[region][i]; | ||
212 | total_clients += active_clients[region][i]; | ||
213 | } | ||
214 | |||
215 | /* Avoid division by 0 for 0-bandwidth requests. */ | ||
216 | req = bandwidth == 0 | ||
217 | ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); | ||
218 | |||
219 | /* | ||
220 | * We make sure that there are enough slots only for non-zero | ||
221 | * requests. Requesting 0 bandwidth *may* allocate slots, | ||
222 | * though if all bandwidth is allocated, such a client won't | ||
223 | * get any and will have to rely on getting memory access | ||
224 | * according to the fixed scheme that's the default when one | ||
225 | * of the slot-allocated clients doesn't claim their slot. | ||
226 | */ | ||
227 | if (total_assigned + req > NBR_OF_SLOTS) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | active_clients[region][client] = 1; | ||
231 | requested_slots[region][client] = req; | ||
232 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Main entry for bandwidth deallocation. | ||
239 | * | ||
240 | * Strictly speaking, for a somewhat constant set of clients where | ||
241 | * each client gets a constant bandwidth and is just enabled or | ||
242 | * disabled (somewhat dynamically), no action is necessary here to | ||
243 | * avoid starvation for non-zero-allocation clients, as the allocated | ||
244 | * slots will just be unused. However, handing out those unused slots | ||
245 | * to active clients avoids needless latency if the "fixed scheme" | ||
246 | * would give unclaimed slots to an eager low-index client. | ||
247 | */ | ||
248 | |||
249 | void crisv32_arbiter_deallocate_bandwidth(int client, int region) | ||
250 | { | ||
251 | int i; | ||
252 | int total_assigned = 0; | ||
253 | |||
254 | requested_slots[region][client] = 0; | ||
255 | active_clients[region][client] = 0; | ||
256 | |||
257 | for (i = 0; i < NBR_OF_CLIENTS; i++) | ||
258 | total_assigned += requested_slots[region][i]; | ||
259 | |||
260 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | ||
261 | } | ||
262 | |||
263 | int crisv32_arbiter_watch(unsigned long start, unsigned long size, | ||
264 | unsigned long clients, unsigned long accesses, | ||
265 | watch_callback *cb) | ||
266 | { | ||
267 | int i; | ||
268 | |||
269 | crisv32_arbiter_init(); | ||
270 | |||
271 | if (start > 0x80000000) { | ||
272 | printk(KERN_ERR "Arbiter: %lX doesn't look like a " | ||
273 | "physical address", start); | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | spin_lock(&arbiter_lock); | ||
278 | |||
279 | for (i = 0; i < NUMBER_OF_BP; i++) { | ||
280 | if (!watches[i].used) { | ||
281 | reg_marb_rw_intr_mask intr_mask = | ||
282 | REG_RD(marb, regi_marb, rw_intr_mask); | ||
283 | |||
284 | watches[i].used = 1; | ||
285 | watches[i].start = start; | ||
286 | watches[i].end = start + size; | ||
287 | watches[i].cb = cb; | ||
288 | |||
289 | REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, | ||
290 | watches[i].start); | ||
291 | REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, | ||
292 | watches[i].end); | ||
293 | REG_WR_INT(marb_bp, watches[i].instance, rw_op, | ||
294 | accesses); | ||
295 | REG_WR_INT(marb_bp, watches[i].instance, rw_clients, | ||
296 | clients); | ||
297 | |||
298 | if (i == 0) | ||
299 | intr_mask.bp0 = regk_marb_yes; | ||
300 | else if (i == 1) | ||
301 | intr_mask.bp1 = regk_marb_yes; | ||
302 | else if (i == 2) | ||
303 | intr_mask.bp2 = regk_marb_yes; | ||
304 | else if (i == 3) | ||
305 | intr_mask.bp3 = regk_marb_yes; | ||
306 | |||
307 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
308 | spin_unlock(&arbiter_lock); | ||
309 | |||
310 | return i; | ||
311 | } | ||
312 | } | ||
313 | spin_unlock(&arbiter_lock); | ||
314 | return -ENOMEM; | ||
315 | } | ||
316 | |||
317 | int crisv32_arbiter_unwatch(int id) | ||
318 | { | ||
319 | reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); | ||
320 | |||
321 | crisv32_arbiter_init(); | ||
322 | |||
323 | spin_lock(&arbiter_lock); | ||
324 | |||
325 | if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { | ||
326 | spin_unlock(&arbiter_lock); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); | ||
331 | |||
332 | if (id == 0) | ||
333 | intr_mask.bp0 = regk_marb_no; | ||
334 | else if (id == 1) | ||
335 | intr_mask.bp2 = regk_marb_no; | ||
336 | else if (id == 2) | ||
337 | intr_mask.bp2 = regk_marb_no; | ||
338 | else if (id == 3) | ||
339 | intr_mask.bp3 = regk_marb_no; | ||
340 | |||
341 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
342 | |||
343 | spin_unlock(&arbiter_lock); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | extern void show_registers(struct pt_regs *regs); | ||
348 | |||
349 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id) | ||
350 | { | ||
351 | reg_marb_r_masked_intr masked_intr = | ||
352 | REG_RD(marb, regi_marb, r_masked_intr); | ||
353 | reg_marb_bp_r_brk_clients r_clients; | ||
354 | reg_marb_bp_r_brk_addr r_addr; | ||
355 | reg_marb_bp_r_brk_op r_op; | ||
356 | reg_marb_bp_r_brk_first_client r_first; | ||
357 | reg_marb_bp_r_brk_size r_size; | ||
358 | reg_marb_bp_rw_ack ack = { 0 }; | ||
359 | reg_marb_rw_ack_intr ack_intr = { | ||
360 | .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 | ||
361 | }; | ||
362 | struct crisv32_watch_entry *watch; | ||
363 | |||
364 | if (masked_intr.bp0) { | ||
365 | watch = &watches[0]; | ||
366 | ack_intr.bp0 = regk_marb_yes; | ||
367 | } else if (masked_intr.bp1) { | ||
368 | watch = &watches[1]; | ||
369 | ack_intr.bp1 = regk_marb_yes; | ||
370 | } else if (masked_intr.bp2) { | ||
371 | watch = &watches[2]; | ||
372 | ack_intr.bp2 = regk_marb_yes; | ||
373 | } else if (masked_intr.bp3) { | ||
374 | watch = &watches[3]; | ||
375 | ack_intr.bp3 = regk_marb_yes; | ||
376 | } else { | ||
377 | return IRQ_NONE; | ||
378 | } | ||
379 | |||
380 | /* Retrieve all useful information and print it. */ | ||
381 | r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); | ||
382 | r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); | ||
383 | r_op = REG_RD(marb_bp, watch->instance, r_brk_op); | ||
384 | r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); | ||
385 | r_size = REG_RD(marb_bp, watch->instance, r_brk_size); | ||
386 | |||
387 | printk(KERN_INFO "Arbiter IRQ\n"); | ||
388 | printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n", | ||
389 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), | ||
390 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), | ||
391 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), | ||
392 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), | ||
393 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); | ||
394 | |||
395 | REG_WR(marb_bp, watch->instance, rw_ack, ack); | ||
396 | REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); | ||
397 | |||
398 | printk(KERN_INFO "IRQ occured at %lX\n", get_irq_regs()->erp); | ||
399 | |||
400 | if (watch->cb) | ||
401 | watch->cb(); | ||
402 | |||
403 | return IRQ_HANDLED; | ||
404 | } | ||
diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/arch/cris/arch-v32/mach-fs/cpufreq.c new file mode 100644 index 000000000000..d57631c0d8d1 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/cpufreq.c | |||
@@ -0,0 +1,146 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/cpufreq.h> | ||
4 | #include <hwregs/reg_map.h> | ||
5 | #include <asm/arch/hwregs/reg_rdwr.h> | ||
6 | #include <asm/arch/hwregs/config_defs.h> | ||
7 | #include <asm/arch/hwregs/bif_core_defs.h> | ||
8 | |||
9 | static int | ||
10 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
11 | void *data); | ||
12 | |||
13 | static struct notifier_block cris_sdram_freq_notifier_block = { | ||
14 | .notifier_call = cris_sdram_freq_notifier | ||
15 | }; | ||
16 | |||
17 | static struct cpufreq_frequency_table cris_freq_table[] = { | ||
18 | {0x01, 6000}, | ||
19 | {0x02, 200000}, | ||
20 | {0, CPUFREQ_TABLE_END}, | ||
21 | }; | ||
22 | |||
23 | static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) | ||
24 | { | ||
25 | reg_config_rw_clk_ctrl clk_ctrl; | ||
26 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | ||
27 | return clk_ctrl.pll ? 200000 : 6000; | ||
28 | } | ||
29 | |||
30 | static void cris_freq_set_cpu_state(unsigned int state) | ||
31 | { | ||
32 | int i; | ||
33 | struct cpufreq_freqs freqs; | ||
34 | reg_config_rw_clk_ctrl clk_ctrl; | ||
35 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | ||
36 | |||
37 | for_each_possible_cpu(i) { | ||
38 | freqs.old = cris_freq_get_cpu_frequency(i); | ||
39 | freqs.new = cris_freq_table[state].frequency; | ||
40 | freqs.cpu = i; | ||
41 | } | ||
42 | |||
43 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
44 | |||
45 | local_irq_disable(); | ||
46 | |||
47 | /* Even though we may be SMP they will share the same clock | ||
48 | * so all settings are made on CPU0. */ | ||
49 | if (cris_freq_table[state].frequency == 200000) | ||
50 | clk_ctrl.pll = 1; | ||
51 | else | ||
52 | clk_ctrl.pll = 0; | ||
53 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); | ||
54 | |||
55 | local_irq_enable(); | ||
56 | |||
57 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
58 | }; | ||
59 | |||
60 | static int cris_freq_verify(struct cpufreq_policy *policy) | ||
61 | { | ||
62 | return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]); | ||
63 | } | ||
64 | |||
65 | static int cris_freq_target(struct cpufreq_policy *policy, | ||
66 | unsigned int target_freq, unsigned int relation) | ||
67 | { | ||
68 | unsigned int newstate = 0; | ||
69 | |||
70 | if (cpufreq_frequency_table_target | ||
71 | (policy, cris_freq_table, target_freq, relation, &newstate)) | ||
72 | return -EINVAL; | ||
73 | |||
74 | cris_freq_set_cpu_state(newstate); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int cris_freq_cpu_init(struct cpufreq_policy *policy) | ||
80 | { | ||
81 | int result; | ||
82 | |||
83 | /* cpuinfo and default policy values */ | ||
84 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
85 | policy->cpuinfo.transition_latency = 1000000; /* 1ms */ | ||
86 | policy->cur = cris_freq_get_cpu_frequency(0); | ||
87 | |||
88 | result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table); | ||
89 | if (result) | ||
90 | return (result); | ||
91 | |||
92 | cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int cris_freq_cpu_exit(struct cpufreq_policy *policy) | ||
98 | { | ||
99 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static struct freq_attr *cris_freq_attr[] = { | ||
104 | &cpufreq_freq_attr_scaling_available_freqs, | ||
105 | NULL, | ||
106 | }; | ||
107 | |||
108 | static struct cpufreq_driver cris_freq_driver = { | ||
109 | .get = cris_freq_get_cpu_frequency, | ||
110 | .verify = cris_freq_verify, | ||
111 | .target = cris_freq_target, | ||
112 | .init = cris_freq_cpu_init, | ||
113 | .exit = cris_freq_cpu_exit, | ||
114 | .name = "cris_freq", | ||
115 | .owner = THIS_MODULE, | ||
116 | .attr = cris_freq_attr, | ||
117 | }; | ||
118 | |||
119 | static int __init cris_freq_init(void) | ||
120 | { | ||
121 | int ret; | ||
122 | ret = cpufreq_register_driver(&cris_freq_driver); | ||
123 | cpufreq_register_notifier(&cris_sdram_freq_notifier_block, | ||
124 | CPUFREQ_TRANSITION_NOTIFIER); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | static int | ||
129 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
130 | void *data) | ||
131 | { | ||
132 | int i; | ||
133 | struct cpufreq_freqs *freqs = data; | ||
134 | if (val == CPUFREQ_PRECHANGE) { | ||
135 | reg_bif_core_rw_sdram_timing timing = | ||
136 | REG_RD(bif_core, regi_bif_core, rw_sdram_timing); | ||
137 | timing.cpd = (freqs->new == 200000 ? 0 : 1); | ||
138 | |||
139 | if (freqs->new == 200000) | ||
140 | for (i = 0; i < 50000; i++) ; | ||
141 | REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing); | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | module_init(cris_freq_init); | ||
diff --git a/arch/cris/arch-v32/kernel/dma.c b/arch/cris/arch-v32/mach-fs/dma.c index 570e19128ffd..a6acf4e6345c 100644 --- a/arch/cris/arch-v32/kernel/dma.c +++ b/arch/cris/arch-v32/mach-fs/dma.c | |||
@@ -3,49 +3,54 @@ | |||
3 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
4 | #include <linux/spinlock.h> | 4 | #include <linux/spinlock.h> |
5 | #include <asm/dma.h> | 5 | #include <asm/dma.h> |
6 | #include <asm/arch/hwregs/reg_map.h> | 6 | #include <hwregs/reg_map.h> |
7 | #include <asm/arch/hwregs/reg_rdwr.h> | 7 | #include <hwregs/reg_rdwr.h> |
8 | #include <asm/arch/hwregs/marb_defs.h> | 8 | #include <hwregs/marb_defs.h> |
9 | #include <asm/arch/hwregs/config_defs.h> | 9 | #include <hwregs/config_defs.h> |
10 | #include <asm/arch/hwregs/strmux_defs.h> | 10 | #include <hwregs/strmux_defs.h> |
11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
12 | #include <asm/system.h> | 12 | #include <asm/system.h> |
13 | #include <asm/arch/arbiter.h> | 13 | #include <asm/arch/mach/arbiter.h> |
14 | 14 | ||
15 | static char used_dma_channels[MAX_DMA_CHANNELS]; | 15 | static char used_dma_channels[MAX_DMA_CHANNELS]; |
16 | static const char * used_dma_channels_users[MAX_DMA_CHANNELS]; | 16 | static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; |
17 | 17 | ||
18 | static DEFINE_SPINLOCK(dma_lock); | 18 | static DEFINE_SPINLOCK(dma_lock); |
19 | 19 | ||
20 | int crisv32_request_dma(unsigned int dmanr, const char * device_id, | 20 | int crisv32_request_dma(unsigned int dmanr, const char *device_id, |
21 | unsigned options, unsigned int bandwidth, | 21 | unsigned options, unsigned int bandwidth, |
22 | enum dma_owner owner) | 22 | enum dma_owner owner) |
23 | { | 23 | { |
24 | unsigned long flags; | 24 | unsigned long flags; |
25 | reg_config_rw_clk_ctrl clk_ctrl; | 25 | reg_config_rw_clk_ctrl clk_ctrl; |
26 | reg_strmux_rw_cfg strmux_cfg; | 26 | reg_strmux_rw_cfg strmux_cfg; |
27 | 27 | ||
28 | if (crisv32_arbiter_allocate_bandwidth(dmanr, | 28 | if (crisv32_arbiter_allocate_bandwidth(dmanr, |
29 | options & DMA_INT_MEM ? INT_REGION : EXT_REGION, | 29 | options & DMA_INT_MEM ? |
30 | bandwidth)) | 30 | INT_REGION : EXT_REGION, |
31 | return -ENOMEM; | 31 | bandwidth)) |
32 | return -ENOMEM; | ||
32 | 33 | ||
33 | spin_lock_irqsave(&dma_lock, flags); | 34 | spin_lock_irqsave(&dma_lock, flags); |
34 | 35 | ||
35 | if (used_dma_channels[dmanr]) { | 36 | if (used_dma_channels[dmanr]) { |
36 | spin_unlock_irqrestore(&dma_lock, flags); | 37 | spin_unlock_irqrestore(&dma_lock, flags); |
37 | if (options & DMA_VERBOSE_ON_ERROR) { | 38 | if (options & DMA_VERBOSE_ON_ERROR) { |
38 | printk("Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]); | 39 | printk(KERN_ERR "Failed to request DMA %i for %s, " |
40 | "already allocated by %s\n", | ||
41 | dmanr, | ||
42 | device_id, | ||
43 | used_dma_channels_users[dmanr]); | ||
39 | } | 44 | } |
40 | if (options & DMA_PANIC_ON_ERROR) | 45 | if (options & DMA_PANIC_ON_ERROR) |
41 | panic("request_dma error!"); | 46 | panic("request_dma error!"); |
47 | spin_unlock_irqrestore(&dma_lock, flags); | ||
42 | return -EBUSY; | 48 | return -EBUSY; |
43 | } | 49 | } |
44 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | 50 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); |
45 | strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); | 51 | strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); |
46 | 52 | ||
47 | switch(dmanr) | 53 | switch (dmanr) { |
48 | { | ||
49 | case 0: | 54 | case 0: |
50 | case 1: | 55 | case 1: |
51 | clk_ctrl.dma01_eth0 = 1; | 56 | clk_ctrl.dma01_eth0 = 1; |
@@ -72,7 +77,9 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id, | |||
72 | default: | 77 | default: |
73 | spin_unlock_irqrestore(&dma_lock, flags); | 78 | spin_unlock_irqrestore(&dma_lock, flags); |
74 | if (options & DMA_VERBOSE_ON_ERROR) { | 79 | if (options & DMA_VERBOSE_ON_ERROR) { |
75 | printk("Failed to request DMA %i for %s, only 0-%i valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1); | 80 | printk(KERN_ERR "Failed to request DMA %i for %s, " |
81 | "only 0-%i valid)\n", | ||
82 | dmanr, device_id, MAX_DMA_CHANNELS - 1); | ||
76 | } | 83 | } |
77 | 84 | ||
78 | if (options & DMA_PANIC_ON_ERROR) | 85 | if (options & DMA_PANIC_ON_ERROR) |
@@ -80,8 +87,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id, | |||
80 | return -EINVAL; | 87 | return -EINVAL; |
81 | } | 88 | } |
82 | 89 | ||
83 | switch(owner) | 90 | switch (owner) { |
84 | { | ||
85 | case dma_eth0: | 91 | case dma_eth0: |
86 | if (dmanr == 0) | 92 | if (dmanr == 0) |
87 | strmux_cfg.dma0 = regk_strmux_eth0; | 93 | strmux_cfg.dma0 = regk_strmux_eth0; |
@@ -212,7 +218,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id, | |||
212 | used_dma_channels_users[dmanr] = device_id; | 218 | used_dma_channels_users[dmanr] = device_id; |
213 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); | 219 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); |
214 | REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); | 220 | REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); |
215 | spin_unlock_irqrestore(&dma_lock,flags); | 221 | spin_unlock_irqrestore(&dma_lock, flags); |
216 | return 0; | 222 | return 0; |
217 | } | 223 | } |
218 | 224 | ||
diff --git a/arch/cris/arch-v32/lib/dram_init.S b/arch/cris/arch-v32/mach-fs/dram_init.S index 218fbe259ee5..6fbad336527b 100644 --- a/arch/cris/arch-v32/lib/dram_init.S +++ b/arch/cris/arch-v32/mach-fs/dram_init.S | |||
@@ -1,23 +1,22 @@ | |||
1 | /* $Id: dram_init.S,v 1.4 2005/04/24 18:48:32 starvik Exp $ | 1 | /* |
2 | * | ||
3 | * DRAM/SDRAM initialization - alter with care | 2 | * DRAM/SDRAM initialization - alter with care |
4 | * This file is intended to be included from other assembler files | 3 | * This file is intended to be included from other assembler files |
5 | * | 4 | * |
6 | * Note: This file may not modify r8 or r9 because they are used to | 5 | * Note: This file may not modify r8 or r9 because they are used to |
7 | * carry information from the decompresser to the kernel | 6 | * carry information from the decompresser to the kernel |
8 | * | 7 | * |
9 | * Copyright (C) 2000-2003 Axis Communications AB | 8 | * Copyright (C) 2000-2007 Axis Communications AB |
10 | * | 9 | * |
11 | * Authors: Mikael Starvik (starvik@axis.com) | 10 | * Authors: Mikael Starvik <starvik@axis.com> |
12 | */ | 11 | */ |
13 | 12 | ||
14 | /* Just to be certain the config file is included, we include it here | 13 | /* Just to be certain the config file is included, we include it here |
15 | * explicitly instead of depending on it being included in the file that | 14 | * explicitely instead of depending on it being included in the file that |
16 | * uses this code. | 15 | * uses this code. |
17 | */ | 16 | */ |
18 | 17 | ||
19 | #include <asm/arch/hwregs/asm/reg_map_asm.h> | 18 | #include <hwregs/asm/reg_map_asm.h> |
20 | #include <asm/arch/hwregs/asm/bif_core_defs_asm.h> | 19 | #include <hwregs/asm/bif_core_defs_asm.h> |
21 | 20 | ||
22 | ;; WARNING! The registers r8 and r9 are used as parameters carrying | 21 | ;; WARNING! The registers r8 and r9 are used as parameters carrying |
23 | ;; information from the decompressor (if the kernel was compressed). | 22 | ;; information from the decompressor (if the kernel was compressed). |
@@ -46,7 +45,7 @@ | |||
46 | 45 | ||
47 | move.d 0x40, $r4 ; Assume 32 bits and CAS latency = 2 | 46 | move.d 0x40, $r4 ; Assume 32 bits and CAS latency = 2 |
48 | move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 | 47 | move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 |
49 | and.d 0x07, $r1 ; Get CAS latency | 48 | and.d 0x07, $r1 ; Get CAS latency |
50 | cmpq 2, $r1 ; CL = 2 ? | 49 | cmpq 2, $r1 ; CL = 2 ? |
51 | beq _bw_check | 50 | beq _bw_check |
52 | nop | 51 | nop |
@@ -80,12 +79,10 @@ _set_timing: | |||
80 | subq 1, $r2 | 79 | subq 1, $r2 |
81 | 80 | ||
82 | ; Issue initialization command sequence | 81 | ; Issue initialization command sequence |
83 | move.d _sdram_commands_start, $r2 | 82 | lapc _sdram_commands_start, $r2 |
84 | and.d 0x000fffff, $r2 ; Make sure commands are read from flash | 83 | lapc _sdram_commands_end, $r3 |
85 | move.d _sdram_commands_end, $r3 | ||
86 | and.d 0x000fffff, $r3 | ||
87 | 1: clear.d $r6 | 84 | 1: clear.d $r6 |
88 | move.b [$r2+], $r6 ; Load command | 85 | move.b [$r2+], $r6 ; Load command |
89 | or.d $r4, $r6 ; Add calculated mrs | 86 | or.d $r4, $r6 ; Add calculated mrs |
90 | move.d $r6, [$r5] ; Write rw_sdram_cmd | 87 | move.d $r6, [$r5] ; Write rw_sdram_cmd |
91 | ; Wait 80 ns between each command | 88 | ; Wait 80 ns between each command |
diff --git a/arch/cris/arch-v32/lib/hw_settings.S b/arch/cris/arch-v32/mach-fs/hw_settings.S index fff9443513d1..8bde93c36214 100644 --- a/arch/cris/arch-v32/lib/hw_settings.S +++ b/arch/cris/arch-v32/mach-fs/hw_settings.S | |||
@@ -1,18 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: hw_settings.S,v 1.3 2005/04/24 18:36:57 starvik Exp $ | ||
3 | * | ||
4 | * This table is used by some tools to extract hardware parameters. | 2 | * This table is used by some tools to extract hardware parameters. |
5 | * The table should be included in the kernel and the decompressor. | 3 | * The table should be included in the kernel and the decompressor. |
6 | * Don't forget to update the tools if you change this table. | 4 | * Don't forget to update the tools if you change this table. |
7 | * | 5 | * |
8 | * Copyright (C) 2001 Axis Communications AB | 6 | * Copyright (C) 2001-2007 Axis Communications AB |
9 | * | 7 | * |
10 | * Authors: Mikael Starvik (starvik@axis.com) | 8 | * Authors: Mikael Starvik <starvik@axis.com> |
11 | */ | 9 | */ |
12 | 10 | ||
13 | #include <asm/arch/hwregs/asm/reg_map_asm.h> | 11 | #include <hwregs/asm/reg_map_asm.h> |
14 | #include <asm/arch/hwregs/asm/bif_core_defs_asm.h> | 12 | #include <hwregs/asm/bif_core_defs_asm.h> |
15 | #include <asm/arch/hwregs/asm/gio_defs_asm.h> | 13 | #include <hwregs/asm/gio_defs_asm.h> |
16 | 14 | ||
17 | .ascii "HW_PARAM_MAGIC" ; Magic number | 15 | .ascii "HW_PARAM_MAGIC" ; Magic number |
18 | .dword 0xc0004000 ; Kernel start address | 16 | .dword 0xc0004000 ; Kernel start address |
diff --git a/arch/cris/arch-v32/mach-fs/io.c b/arch/cris/arch-v32/mach-fs/io.c new file mode 100644 index 000000000000..a03a3ad3a188 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/io.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * Helper functions for I/O pins. | ||
3 | * | ||
4 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
5 | */ | ||
6 | |||
7 | #include <linux/types.h> | ||
8 | #include <linux/errno.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/arch/pinmux.h> | ||
16 | #include <asm/arch/hwregs/gio_defs.h> | ||
17 | |||
18 | #ifndef DEBUG | ||
19 | #define DEBUG(x) | ||
20 | #endif | ||
21 | |||
22 | struct crisv32_ioport crisv32_ioports[] = { | ||
23 | { | ||
24 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe), | ||
25 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout), | ||
26 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din), | ||
27 | 8 | ||
28 | }, | ||
29 | { | ||
30 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe), | ||
31 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout), | ||
32 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din), | ||
33 | 18 | ||
34 | }, | ||
35 | { | ||
36 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe), | ||
37 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout), | ||
38 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din), | ||
39 | 18 | ||
40 | }, | ||
41 | { | ||
42 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_oe), | ||
43 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_dout), | ||
44 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pd_din), | ||
45 | 18 | ||
46 | }, | ||
47 | { | ||
48 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_oe), | ||
49 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_dout), | ||
50 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pe_din), | ||
51 | 18 | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | #define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport) | ||
56 | |||
57 | struct crisv32_iopin crisv32_led_net0_green; | ||
58 | struct crisv32_iopin crisv32_led_net0_red; | ||
59 | struct crisv32_iopin crisv32_led_net1_green; | ||
60 | struct crisv32_iopin crisv32_led_net1_red; | ||
61 | struct crisv32_iopin crisv32_led2_green; | ||
62 | struct crisv32_iopin crisv32_led2_red; | ||
63 | struct crisv32_iopin crisv32_led3_green; | ||
64 | struct crisv32_iopin crisv32_led3_red; | ||
65 | |||
66 | /* Dummy port used when green LED and red LED is on the same bit */ | ||
67 | static unsigned long io_dummy; | ||
68 | static struct crisv32_ioport dummy_port = { | ||
69 | &io_dummy, | ||
70 | &io_dummy, | ||
71 | &io_dummy, | ||
72 | 18 | ||
73 | }; | ||
74 | static struct crisv32_iopin dummy_led = { | ||
75 | &dummy_port, | ||
76 | 0 | ||
77 | }; | ||
78 | |||
79 | static int __init crisv32_io_init(void) | ||
80 | { | ||
81 | int ret = 0; | ||
82 | |||
83 | u32 i; | ||
84 | |||
85 | /* Locks *should* be dynamically initialized. */ | ||
86 | for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++) | ||
87 | spin_lock_init(&crisv32_ioports[i].lock); | ||
88 | spin_lock_init(&dummy_port.lock); | ||
89 | |||
90 | /* Initialize LEDs */ | ||
91 | #if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) | ||
92 | ret += | ||
93 | crisv32_io_get_name(&crisv32_led_net0_green, | ||
94 | CONFIG_ETRAX_LED_G_NET0); | ||
95 | crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out); | ||
96 | if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) { | ||
97 | ret += | ||
98 | crisv32_io_get_name(&crisv32_led_net0_red, | ||
99 | CONFIG_ETRAX_LED_R_NET0); | ||
100 | crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out); | ||
101 | } else | ||
102 | crisv32_led_net0_red = dummy_led; | ||
103 | #endif | ||
104 | |||
105 | #ifdef CONFIG_ETRAX_NBR_LED_GRP_TWO | ||
106 | ret += | ||
107 | crisv32_io_get_name(&crisv32_led_net1_green, | ||
108 | CONFIG_ETRAX_LED_G_NET1); | ||
109 | crisv32_io_set_dir(&crisv32_led_net1_green, crisv32_io_dir_out); | ||
110 | if (strcmp(CONFIG_ETRAX_LED_G_NET1, CONFIG_ETRAX_LED_R_NET1)) { | ||
111 | crisv32_io_get_name(&crisv32_led_net1_red, | ||
112 | CONFIG_ETRAX_LED_R_NET1); | ||
113 | crisv32_io_set_dir(&crisv32_led_net1_red, crisv32_io_dir_out); | ||
114 | } else | ||
115 | crisv32_led_net1_red = dummy_led; | ||
116 | #endif | ||
117 | |||
118 | ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G); | ||
119 | ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R); | ||
120 | ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G); | ||
121 | ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R); | ||
122 | |||
123 | crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); | ||
124 | crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); | ||
125 | crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); | ||
126 | crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | __initcall(crisv32_io_init); | ||
132 | |||
133 | int crisv32_io_get(struct crisv32_iopin *iopin, | ||
134 | unsigned int port, unsigned int pin) | ||
135 | { | ||
136 | if (port > NBR_OF_PORTS) | ||
137 | return -EINVAL; | ||
138 | if (port > crisv32_ioports[port].pin_count) | ||
139 | return -EINVAL; | ||
140 | |||
141 | iopin->bit = 1 << pin; | ||
142 | iopin->port = &crisv32_ioports[port]; | ||
143 | |||
144 | /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ | ||
145 | /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ | ||
146 | if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) | ||
147 | return -EIO; | ||
148 | DEBUG(printk(KERN_DEBUG "crisv32_io_get: Allocated pin %d on port %d\n", | ||
149 | pin, port)); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name) | ||
155 | { | ||
156 | int port; | ||
157 | int pin; | ||
158 | |||
159 | if (toupper(*name) == 'P') | ||
160 | name++; | ||
161 | |||
162 | if (toupper(*name) < 'A' || toupper(*name) > 'E') | ||
163 | return -EINVAL; | ||
164 | |||
165 | port = toupper(*name) - 'A'; | ||
166 | name++; | ||
167 | pin = simple_strtoul(name, NULL, 10); | ||
168 | |||
169 | if (pin < 0 || pin > crisv32_ioports[port].pin_count) | ||
170 | return -EINVAL; | ||
171 | |||
172 | iopin->bit = 1 << pin; | ||
173 | iopin->port = &crisv32_ioports[port]; | ||
174 | |||
175 | /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ | ||
176 | /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ | ||
177 | if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) | ||
178 | return -EIO; | ||
179 | |||
180 | DEBUG(printk(KERN_DEBUG | ||
181 | "crisv32_io_get_name: Allocated pin %d on port %d\n", | ||
182 | pin, port)); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | #ifdef CONFIG_PCI | ||
188 | /* PCI I/O access stuff */ | ||
189 | struct cris_io_operations *cris_iops = NULL; | ||
190 | EXPORT_SYMBOL(cris_iops); | ||
191 | #endif | ||
diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c new file mode 100644 index 000000000000..d722ad9ae626 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/pinmux.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Allocator for I/O pins. All pins are allocated to GPIO at bootup. | ||
3 | * Unassigned pins and GPIO pins can be allocated to a fixed interface | ||
4 | * or the I/O processor instead. | ||
5 | * | ||
6 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <hwregs/reg_map.h> | ||
15 | #include <hwregs/reg_rdwr.h> | ||
16 | #include <pinmux.h> | ||
17 | #include <hwregs/pinmux_defs.h> | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #define PORT_PINS 18 | ||
22 | #define PORTS 4 | ||
23 | |||
24 | static char pins[PORTS][PORT_PINS]; | ||
25 | static DEFINE_SPINLOCK(pinmux_lock); | ||
26 | |||
27 | static void crisv32_pinmux_set(int port); | ||
28 | |||
29 | int crisv32_pinmux_init(void) | ||
30 | { | ||
31 | static int initialized; | ||
32 | |||
33 | if (!initialized) { | ||
34 | reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa); | ||
35 | initialized = 1; | ||
36 | REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0); | ||
37 | pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 = | ||
38 | pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes; | ||
39 | REG_WR(pinmux, regi_pinmux, rw_pa, pa); | ||
40 | crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); | ||
41 | crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); | ||
42 | crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); | ||
43 | crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); | ||
44 | } | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | int | ||
50 | crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) | ||
51 | { | ||
52 | int i; | ||
53 | unsigned long flags; | ||
54 | |||
55 | crisv32_pinmux_init(); | ||
56 | |||
57 | if (port > PORTS) | ||
58 | return -EINVAL; | ||
59 | |||
60 | spin_lock_irqsave(&pinmux_lock, flags); | ||
61 | |||
62 | for (i = first_pin; i <= last_pin; i++) { | ||
63 | if ((pins[port][i] != pinmux_none) | ||
64 | && (pins[port][i] != pinmux_gpio) | ||
65 | && (pins[port][i] != mode)) { | ||
66 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
67 | #ifdef DEBUG | ||
68 | panic("Pinmux alloc failed!\n"); | ||
69 | #endif | ||
70 | return -EPERM; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | for (i = first_pin; i <= last_pin; i++) | ||
75 | pins[port][i] = mode; | ||
76 | |||
77 | crisv32_pinmux_set(port); | ||
78 | |||
79 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int crisv32_pinmux_alloc_fixed(enum fixed_function function) | ||
85 | { | ||
86 | int ret = -EINVAL; | ||
87 | char saved[sizeof pins]; | ||
88 | unsigned long flags; | ||
89 | |||
90 | spin_lock_irqsave(&pinmux_lock, flags); | ||
91 | |||
92 | /* Save internal data for recovery */ | ||
93 | memcpy(saved, pins, sizeof pins); | ||
94 | |||
95 | crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ | ||
96 | |||
97 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
98 | |||
99 | switch (function) { | ||
100 | case pinmux_ser1: | ||
101 | ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); | ||
102 | hwprot.ser1 = regk_pinmux_yes; | ||
103 | break; | ||
104 | case pinmux_ser2: | ||
105 | ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); | ||
106 | hwprot.ser2 = regk_pinmux_yes; | ||
107 | break; | ||
108 | case pinmux_ser3: | ||
109 | ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); | ||
110 | hwprot.ser3 = regk_pinmux_yes; | ||
111 | break; | ||
112 | case pinmux_sser0: | ||
113 | ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); | ||
114 | ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | ||
115 | hwprot.sser0 = regk_pinmux_yes; | ||
116 | break; | ||
117 | case pinmux_sser1: | ||
118 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | ||
119 | hwprot.sser1 = regk_pinmux_yes; | ||
120 | break; | ||
121 | case pinmux_ata0: | ||
122 | ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); | ||
123 | ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); | ||
124 | hwprot.ata0 = regk_pinmux_yes; | ||
125 | break; | ||
126 | case pinmux_ata1: | ||
127 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | ||
128 | ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); | ||
129 | hwprot.ata1 = regk_pinmux_yes; | ||
130 | break; | ||
131 | case pinmux_ata2: | ||
132 | ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); | ||
133 | ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); | ||
134 | hwprot.ata2 = regk_pinmux_yes; | ||
135 | break; | ||
136 | case pinmux_ata3: | ||
137 | ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); | ||
138 | ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); | ||
139 | hwprot.ata2 = regk_pinmux_yes; | ||
140 | break; | ||
141 | case pinmux_ata: | ||
142 | ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); | ||
143 | ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); | ||
144 | hwprot.ata = regk_pinmux_yes; | ||
145 | break; | ||
146 | case pinmux_eth1: | ||
147 | ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); | ||
148 | hwprot.eth1 = regk_pinmux_yes; | ||
149 | hwprot.eth1_mgm = regk_pinmux_yes; | ||
150 | break; | ||
151 | case pinmux_timer: | ||
152 | ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | ||
153 | hwprot.timer = regk_pinmux_yes; | ||
154 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | if (!ret) | ||
159 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
160 | else | ||
161 | memcpy(pins, saved, sizeof pins); | ||
162 | |||
163 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | void crisv32_pinmux_set(int port) | ||
169 | { | ||
170 | int i; | ||
171 | int gpio_val = 0; | ||
172 | int iop_val = 0; | ||
173 | |||
174 | for (i = 0; i < PORT_PINS; i++) { | ||
175 | if (pins[port][i] == pinmux_gpio) | ||
176 | gpio_val |= (1 << i); | ||
177 | else if (pins[port][i] == pinmux_iop) | ||
178 | iop_val |= (1 << i); | ||
179 | } | ||
180 | |||
181 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port, | ||
182 | gpio_val); | ||
183 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port, | ||
184 | iop_val); | ||
185 | |||
186 | #ifdef DEBUG | ||
187 | crisv32_pinmux_dump(); | ||
188 | #endif | ||
189 | } | ||
190 | |||
191 | int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) | ||
192 | { | ||
193 | int i; | ||
194 | unsigned long flags; | ||
195 | |||
196 | crisv32_pinmux_init(); | ||
197 | |||
198 | if (port > PORTS) | ||
199 | return -EINVAL; | ||
200 | |||
201 | spin_lock_irqsave(&pinmux_lock, flags); | ||
202 | |||
203 | for (i = first_pin; i <= last_pin; i++) | ||
204 | pins[port][i] = pinmux_none; | ||
205 | |||
206 | crisv32_pinmux_set(port); | ||
207 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int crisv32_pinmux_dealloc_fixed(enum fixed_function function) | ||
213 | { | ||
214 | int ret = -EINVAL; | ||
215 | char saved[sizeof pins]; | ||
216 | unsigned long flags; | ||
217 | |||
218 | spin_lock_irqsave(&pinmux_lock, flags); | ||
219 | |||
220 | /* Save internal data for recovery */ | ||
221 | memcpy(saved, pins, sizeof pins); | ||
222 | |||
223 | crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ | ||
224 | |||
225 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
226 | |||
227 | switch (function) { | ||
228 | case pinmux_ser1: | ||
229 | ret = crisv32_pinmux_dealloc(PORT_C, 4, 7); | ||
230 | hwprot.ser1 = regk_pinmux_no; | ||
231 | break; | ||
232 | case pinmux_ser2: | ||
233 | ret = crisv32_pinmux_dealloc(PORT_C, 8, 11); | ||
234 | hwprot.ser2 = regk_pinmux_no; | ||
235 | break; | ||
236 | case pinmux_ser3: | ||
237 | ret = crisv32_pinmux_dealloc(PORT_C, 12, 15); | ||
238 | hwprot.ser3 = regk_pinmux_no; | ||
239 | break; | ||
240 | case pinmux_sser0: | ||
241 | ret = crisv32_pinmux_dealloc(PORT_C, 0, 3); | ||
242 | ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16); | ||
243 | hwprot.sser0 = regk_pinmux_no; | ||
244 | break; | ||
245 | case pinmux_sser1: | ||
246 | ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); | ||
247 | hwprot.sser1 = regk_pinmux_no; | ||
248 | break; | ||
249 | case pinmux_ata0: | ||
250 | ret = crisv32_pinmux_dealloc(PORT_D, 5, 7); | ||
251 | ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17); | ||
252 | hwprot.ata0 = regk_pinmux_no; | ||
253 | break; | ||
254 | case pinmux_ata1: | ||
255 | ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); | ||
256 | ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17); | ||
257 | hwprot.ata1 = regk_pinmux_no; | ||
258 | break; | ||
259 | case pinmux_ata2: | ||
260 | ret = crisv32_pinmux_dealloc(PORT_C, 11, 15); | ||
261 | ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3); | ||
262 | hwprot.ata2 = regk_pinmux_no; | ||
263 | break; | ||
264 | case pinmux_ata3: | ||
265 | ret = crisv32_pinmux_dealloc(PORT_C, 8, 10); | ||
266 | ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2); | ||
267 | hwprot.ata2 = regk_pinmux_no; | ||
268 | break; | ||
269 | case pinmux_ata: | ||
270 | ret = crisv32_pinmux_dealloc(PORT_B, 0, 15); | ||
271 | ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15); | ||
272 | hwprot.ata = regk_pinmux_no; | ||
273 | break; | ||
274 | case pinmux_eth1: | ||
275 | ret = crisv32_pinmux_dealloc(PORT_E, 0, 17); | ||
276 | hwprot.eth1 = regk_pinmux_no; | ||
277 | hwprot.eth1_mgm = regk_pinmux_no; | ||
278 | break; | ||
279 | case pinmux_timer: | ||
280 | ret = crisv32_pinmux_dealloc(PORT_C, 16, 16); | ||
281 | hwprot.timer = regk_pinmux_no; | ||
282 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | if (!ret) | ||
287 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
288 | else | ||
289 | memcpy(pins, saved, sizeof pins); | ||
290 | |||
291 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | void crisv32_pinmux_dump(void) | ||
297 | { | ||
298 | int i, j; | ||
299 | |||
300 | crisv32_pinmux_init(); | ||
301 | |||
302 | for (i = 0; i < PORTS; i++) { | ||
303 | printk(KERN_DEBUG "Port %c\n", 'B' + i); | ||
304 | for (j = 0; j < PORT_PINS; j++) | ||
305 | printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | __initcall(crisv32_pinmux_init); | ||
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c new file mode 100644 index 000000000000..593b10f07ef1 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/vcs_hook.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Call simulator hook. This is the part running in the | ||
3 | * simulated program. | ||
4 | */ | ||
5 | |||
6 | #include "vcs_hook.h" | ||
7 | #include <stdarg.h> | ||
8 | #include <asm/arch-v32/hwregs/reg_map.h> | ||
9 | #include <asm/arch-v32/hwregs/intr_vect_defs.h> | ||
10 | |||
11 | #define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */ | ||
12 | #define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */ | ||
13 | |||
14 | #define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset] | ||
15 | #define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset] | ||
16 | #define HOOK_TRIG(funcid) \ | ||
17 | do { \ | ||
18 | *((unsigned *) HOOK_TRIG_ADDR) = funcid; \ | ||
19 | } while (0) | ||
20 | #define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset] | ||
21 | |||
22 | int hook_call(unsigned id, unsigned pcnt, ...) | ||
23 | { | ||
24 | va_list ap; | ||
25 | unsigned i; | ||
26 | unsigned ret; | ||
27 | #ifdef USING_SOS | ||
28 | PREEMPT_OFF_SAVE(); | ||
29 | #endif | ||
30 | |||
31 | /* pass parameters */ | ||
32 | HOOK_DATA(0) = id; | ||
33 | |||
34 | /* Have to make hook_print_str a special case since we call with a | ||
35 | * parameter of byte type. Should perhaps be a separate | ||
36 | * hook_call. */ | ||
37 | |||
38 | if (id == hook_print_str) { | ||
39 | int i; | ||
40 | char *str; | ||
41 | |||
42 | HOOK_DATA(1) = pcnt; | ||
43 | |||
44 | va_start(ap, pcnt); | ||
45 | str = (char *)va_arg(ap, unsigned); | ||
46 | |||
47 | for (i = 0; i != pcnt; i++) | ||
48 | HOOK_DATA_BYTE(8 + i) = str[i]; | ||
49 | |||
50 | HOOK_DATA_BYTE(8 + i) = 0; /* null byte */ | ||
51 | } else { | ||
52 | va_start(ap, pcnt); | ||
53 | for (i = 1; i <= pcnt; i++) | ||
54 | HOOK_DATA(i) = va_arg(ap, unsigned); | ||
55 | va_end(ap); | ||
56 | } | ||
57 | |||
58 | /* read from mem to make sure data has propagated to memory before | ||
59 | * trigging */ | ||
60 | ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR); | ||
61 | |||
62 | /* trigger hook */ | ||
63 | HOOK_TRIG(id); | ||
64 | |||
65 | /* wait for call to finish */ | ||
66 | while (VHOOK_DATA(0) > 0) ; | ||
67 | |||
68 | /* extract return value */ | ||
69 | |||
70 | ret = VHOOK_DATA(1); | ||
71 | |||
72 | #ifdef USING_SOS | ||
73 | PREEMPT_RESTORE(); | ||
74 | #endif | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | unsigned hook_buf(unsigned i) | ||
79 | { | ||
80 | return (HOOK_DATA(i)); | ||
81 | } | ||
82 | |||
83 | void print_str(const char *str) | ||
84 | { | ||
85 | int i; | ||
86 | /* find null at end of string */ | ||
87 | for (i = 1; str[i]; i++) ; | ||
88 | hook_call(hook_print_str, i, str); | ||
89 | } | ||
90 | |||
91 | void CPU_KICK_DOG(void) | ||
92 | { | ||
93 | (void)hook_call(hook_kick_dog, 0); | ||
94 | } | ||
95 | |||
96 | void CPU_WATCHDOG_TIMEOUT(unsigned t) | ||
97 | { | ||
98 | (void)hook_call(hook_dog_timeout, 1, t); | ||
99 | } | ||
100 | |||
diff --git a/arch/cris/arch-v32/kernel/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h index 7d73709e3cc6..c000b9fece41 100644 --- a/arch/cris/arch-v32/kernel/vcs_hook.h +++ b/arch/cris/arch-v32/mach-fs/vcs_hook.h | |||
@@ -1,11 +1,11 @@ | |||
1 | // $Id: vcs_hook.h,v 1.1 2003/08/12 12:01:06 starvik Exp $ | 1 | /* |
2 | // | 2 | * Call simulator hook functions |
3 | // Call simulator hook functions | 3 | */ |
4 | 4 | ||
5 | #ifndef HOOK_H | 5 | #ifndef HOOK_H |
6 | #define HOOK_H | 6 | #define HOOK_H |
7 | 7 | ||
8 | int hook_call( unsigned id, unsigned pcnt, ...); | 8 | int hook_call(unsigned id, unsigned pcnt, ...); |
9 | 9 | ||
10 | enum hook_ids { | 10 | enum hook_ids { |
11 | hook_debug_on = 1, | 11 | hook_debug_on = 1, |
diff --git a/arch/cris/arch-v32/mm/Makefile b/arch/cris/arch-v32/mm/Makefile index 9146f88484b1..0b801f2964ac 100644 --- a/arch/cris/arch-v32/mm/Makefile +++ b/arch/cris/arch-v32/mm/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | # Makefile for the Linux/cris parts of the memory manager. | 1 | # Makefile for the Linux/cris parts of the memory manager. |
2 | 2 | ||
3 | obj-y := mmu.o init.o tlb.o intmem.o | 3 | obj-y += mmu.o init.o tlb.o intmem.o |
4 | obj-$(CONFIG_ETRAX_L2CACHE) += l2cache.o | ||
diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c index a84ba7ff22d2..5a9ac5834647 100644 --- a/arch/cris/arch-v32/mm/init.c +++ b/arch/cris/arch-v32/mm/init.c | |||
@@ -65,7 +65,7 @@ cris_mmu_init(void) | |||
65 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) | | 65 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) | |
66 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) | | 66 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) | |
67 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) | | 67 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) | |
68 | #ifndef CONFIG_ETRAXFS_SIM | 68 | #ifndef CONFIG_ETRAX_VCS_SIM |
69 | REG_STATE(mmu, rw_mm_cfg, seg_a, page) | | 69 | REG_STATE(mmu, rw_mm_cfg, seg_a, page) | |
70 | #else | 70 | #else |
71 | REG_STATE(mmu, rw_mm_cfg, seg_a, linear) | | 71 | REG_STATE(mmu, rw_mm_cfg, seg_a, linear) | |
@@ -84,13 +84,9 @@ cris_mmu_init(void) | |||
84 | mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) | | 84 | mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) | |
85 | REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) | | 85 | REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) | |
86 | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) | | 86 | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) | |
87 | #ifndef CONFIG_ETRAXFS_SIM | ||
88 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) | | 87 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) | |
89 | #else | ||
90 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x0) | | ||
91 | #endif | ||
92 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) | | 88 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) | |
93 | #ifndef CONFIG_ETRAXFS_SIM | 89 | #ifndef CONFIG_ETRAX_VCS_SIM |
94 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) | | 90 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) | |
95 | #else | 91 | #else |
96 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) | | 92 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) | |
diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c index 41ee7f7997fd..9e8b69cdf19e 100644 --- a/arch/cris/arch-v32/mm/intmem.c +++ b/arch/cris/arch-v32/mm/intmem.c | |||
@@ -7,11 +7,17 @@ | |||
7 | #include <linux/list.h> | 7 | #include <linux/list.h> |
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <asm/io.h> | 9 | #include <asm/io.h> |
10 | #include <asm/arch/memmap.h> | 10 | #include <memmap.h> |
11 | 11 | ||
12 | #define STATUS_FREE 0 | 12 | #define STATUS_FREE 0 |
13 | #define STATUS_ALLOCATED 1 | 13 | #define STATUS_ALLOCATED 1 |
14 | 14 | ||
15 | #ifdef CONFIG_ETRAX_L2CACHE | ||
16 | #define RESERVED_SIZE 66*1024 | ||
17 | #else | ||
18 | #define RESERVED_SIZE 0 | ||
19 | #endif | ||
20 | |||
15 | struct intmem_allocation { | 21 | struct intmem_allocation { |
16 | struct list_head entry; | 22 | struct list_head entry; |
17 | unsigned int size; | 23 | unsigned int size; |
@@ -30,9 +36,10 @@ static void crisv32_intmem_init(void) | |||
30 | struct intmem_allocation* alloc = | 36 | struct intmem_allocation* alloc = |
31 | (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL); | 37 | (struct intmem_allocation*)kmalloc(sizeof *alloc, GFP_KERNEL); |
32 | INIT_LIST_HEAD(&intmem_allocations); | 38 | INIT_LIST_HEAD(&intmem_allocations); |
33 | intmem_virtual = ioremap(MEM_INTMEM_START, MEM_INTMEM_SIZE); | 39 | intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE, |
40 | MEM_INTMEM_SIZE - RESERVED_SIZE); | ||
34 | initiated = 1; | 41 | initiated = 1; |
35 | alloc->size = MEM_INTMEM_SIZE; | 42 | alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE; |
36 | alloc->offset = 0; | 43 | alloc->offset = 0; |
37 | alloc->status = STATUS_FREE; | 44 | alloc->status = STATUS_FREE; |
38 | list_add_tail(&alloc->entry, &intmem_allocations); | 45 | list_add_tail(&alloc->entry, &intmem_allocations); |
@@ -59,19 +66,23 @@ void* crisv32_intmem_alloc(unsigned size, unsigned align) | |||
59 | (struct intmem_allocation*) | 66 | (struct intmem_allocation*) |
60 | kmalloc(sizeof *alloc, GFP_ATOMIC); | 67 | kmalloc(sizeof *alloc, GFP_ATOMIC); |
61 | alloc->status = STATUS_FREE; | 68 | alloc->status = STATUS_FREE; |
62 | alloc->size = allocation->size - size - alignment; | 69 | alloc->size = allocation->size - size - |
63 | alloc->offset = allocation->offset + size; | 70 | alignment; |
71 | alloc->offset = allocation->offset + size + | ||
72 | alignment; | ||
64 | list_add(&alloc->entry, &allocation->entry); | 73 | list_add(&alloc->entry, &allocation->entry); |
65 | 74 | ||
66 | if (alignment) { | 75 | if (alignment) { |
67 | struct intmem_allocation* tmp; | 76 | struct intmem_allocation *tmp; |
68 | tmp = (struct intmem_allocation*) | 77 | tmp = (struct intmem_allocation *) |
69 | kmalloc(sizeof *tmp, GFP_ATOMIC); | 78 | kmalloc(sizeof *tmp, |
79 | GFP_ATOMIC); | ||
70 | tmp->offset = allocation->offset; | 80 | tmp->offset = allocation->offset; |
71 | tmp->size = alignment; | 81 | tmp->size = alignment; |
72 | tmp->status = STATUS_FREE; | 82 | tmp->status = STATUS_FREE; |
73 | allocation->offset += alignment; | 83 | allocation->offset += alignment; |
74 | list_add_tail(&tmp->entry, &allocation->entry); | 84 | list_add_tail(&tmp->entry, |
85 | &allocation->entry); | ||
75 | } | 86 | } |
76 | } | 87 | } |
77 | allocation->status = STATUS_ALLOCATED; | 88 | allocation->status = STATUS_ALLOCATED; |
@@ -96,22 +107,24 @@ void crisv32_intmem_free(void* addr) | |||
96 | 107 | ||
97 | list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { | 108 | list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { |
98 | if (allocation->offset == (int)(addr - intmem_virtual)) { | 109 | if (allocation->offset == (int)(addr - intmem_virtual)) { |
99 | struct intmem_allocation* prev = | 110 | struct intmem_allocation *prev = |
100 | list_entry(allocation->entry.prev, | 111 | list_entry(allocation->entry.prev, |
101 | struct intmem_allocation, entry); | 112 | struct intmem_allocation, entry); |
102 | struct intmem_allocation* next = | 113 | struct intmem_allocation *next = |
103 | list_entry(allocation->entry.next, | 114 | list_entry(allocation->entry.next, |
104 | struct intmem_allocation, entry); | 115 | struct intmem_allocation, entry); |
105 | 116 | ||
106 | allocation->status = STATUS_FREE; | 117 | allocation->status = STATUS_FREE; |
107 | /* Join with prev and/or next if also free */ | 118 | /* Join with prev and/or next if also free */ |
108 | if (prev->status == STATUS_FREE) { | 119 | if ((prev != &intmem_allocations) && |
120 | (prev->status == STATUS_FREE)) { | ||
109 | prev->size += allocation->size; | 121 | prev->size += allocation->size; |
110 | list_del(&allocation->entry); | 122 | list_del(&allocation->entry); |
111 | kfree(allocation); | 123 | kfree(allocation); |
112 | allocation = prev; | 124 | allocation = prev; |
113 | } | 125 | } |
114 | if (next->status == STATUS_FREE) { | 126 | if ((next != &intmem_allocations) && |
127 | (next->status == STATUS_FREE)) { | ||
115 | allocation->size += next->size; | 128 | allocation->size += next->size; |
116 | list_del(&next->entry); | 129 | list_del(&next->entry); |
117 | kfree(next); | 130 | kfree(next); |
@@ -125,15 +138,16 @@ void crisv32_intmem_free(void* addr) | |||
125 | 138 | ||
126 | void* crisv32_intmem_phys_to_virt(unsigned long addr) | 139 | void* crisv32_intmem_phys_to_virt(unsigned long addr) |
127 | { | 140 | { |
128 | return (void*)(addr - MEM_INTMEM_START+ | 141 | return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) + |
129 | (unsigned long)intmem_virtual); | 142 | (unsigned long)intmem_virtual); |
130 | } | 143 | } |
131 | 144 | ||
132 | unsigned long crisv32_intmem_virt_to_phys(void* addr) | 145 | unsigned long crisv32_intmem_virt_to_phys(void* addr) |
133 | { | 146 | { |
134 | return (unsigned long)((unsigned long )addr - | 147 | return (unsigned long)((unsigned long )addr - |
135 | (unsigned long)intmem_virtual + MEM_INTMEM_START); | 148 | (unsigned long)intmem_virtual + MEM_INTMEM_START + |
149 | RESERVED_SIZE); | ||
136 | } | 150 | } |
137 | 151 | ||
138 | 152 | module_init(crisv32_intmem_init); | |
139 | 153 | ||
diff --git a/arch/cris/arch-v32/mm/l2cache.c b/arch/cris/arch-v32/mm/l2cache.c new file mode 100644 index 000000000000..332ff10dcc6b --- /dev/null +++ b/arch/cris/arch-v32/mm/l2cache.c | |||
@@ -0,0 +1,29 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/string.h> | ||
4 | #include <memmap.h> | ||
5 | #include <hwregs/reg_map.h> | ||
6 | #include <hwregs/reg_rdwr.h> | ||
7 | #include <hwregs/l2cache_defs.h> | ||
8 | #include <asm/io.h> | ||
9 | |||
10 | #define L2CACHE_SIZE 64 | ||
11 | |||
12 | int __init l2cache_init(void) | ||
13 | { | ||
14 | reg_l2cache_rw_ctrl ctrl = {0}; | ||
15 | reg_l2cache_rw_cfg cfg = {.en = regk_l2cache_yes}; | ||
16 | |||
17 | ctrl.csize = L2CACHE_SIZE; | ||
18 | ctrl.cbase = L2CACHE_SIZE / 4 + (L2CACHE_SIZE % 4 ? 1 : 0); | ||
19 | REG_WR(l2cache, regi_l2cache, rw_ctrl, ctrl); | ||
20 | |||
21 | /* Flush the tag memory */ | ||
22 | memset((void *)(MEM_INTMEM_START | MEM_NON_CACHEABLE), 0, 2*1024); | ||
23 | |||
24 | /* Enable the cache */ | ||
25 | REG_WR(l2cache, regi_l2cache, rw_cfg, cfg); | ||
26 | |||
27 | return 0; | ||
28 | } | ||
29 | |||
diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S index 27b70e5006af..2238d154bde3 100644 --- a/arch/cris/arch-v32/mm/mmu.S +++ b/arch/cris/arch-v32/mm/mmu.S | |||
@@ -1,3 +1,5 @@ | |||
1 | ; WARNING : The refill handler has been modified, see below !!! | ||
2 | |||
1 | /* | 3 | /* |
2 | * Copyright (C) 2003 Axis Communications AB | 4 | * Copyright (C) 2003 Axis Communications AB |
3 | * | 5 | * |
@@ -61,6 +63,14 @@ | |||
61 | ; Note that the code is optimized to minimize stalls (makes the code harder | 63 | ; Note that the code is optimized to minimize stalls (makes the code harder |
62 | ; to read). | 64 | ; to read). |
63 | ; | 65 | ; |
66 | ; WARNING !!! | ||
67 | ; Modified by Mikael Asker 060725: added a workaround for strange TLB | ||
68 | ; behavior. If the same PTE is present in more than one set, the TLB | ||
69 | ; doesn't recognize it and we get stuck in a loop of refill exceptions. | ||
70 | ; The workaround detects such loops and exits them by flushing | ||
71 | ; the TLB contents. The problem and workaround were verified | ||
72 | ; in VCS by Mikael Starvik. | ||
73 | ; | ||
64 | ; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each | 74 | ; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each |
65 | ; PMD holds 16 MB of virtual memory. | 75 | ; PMD holds 16 MB of virtual memory. |
66 | ; Bits 0-12 : Offset within a page | 76 | ; Bits 0-12 : Offset within a page |
@@ -68,6 +78,11 @@ | |||
68 | ; Bits 24-31 : PMD offset within the PGD | 78 | ; Bits 24-31 : PMD offset within the PGD |
69 | 79 | ||
70 | .macro MMU_REFILL_HANDLER handler, mmu | 80 | .macro MMU_REFILL_HANDLER handler, mmu |
81 | .data | ||
82 | 1: .dword 0 ; refill_count | ||
83 | ; == 0 <=> last_refill_cause is invalid | ||
84 | 2: .dword 0 ; last_refill_cause | ||
85 | .text | ||
71 | .globl \handler | 86 | .globl \handler |
72 | \handler: | 87 | \handler: |
73 | subq 4, $sp | 88 | subq 4, $sp |
@@ -76,42 +91,96 @@ | |||
76 | subq 4, $sp | 91 | subq 4, $sp |
77 | move \mmu, $srs ; Select MMU support register bank | 92 | move \mmu, $srs ; Select MMU support register bank |
78 | move.d $acr, [$sp] | 93 | move.d $acr, [$sp] |
79 | subq 4, $sp | 94 | subq 12, $sp |
80 | move.d $r0, [$sp] | 95 | move.d 1b, $acr ; Point to refill_count |
96 | movem $r2, [$sp] | ||
97 | |||
98 | test.d [$acr] ; refill_count == 0 ? | ||
99 | beq 5f ; yes, last_refill_cause is invalid | ||
100 | move.d $acr, $r1 | ||
101 | |||
102 | ; last_refill_cause is valid, investigate cause | ||
103 | addq 4, $r1 ; Point to last_refill_cause | ||
104 | move $s3, $r0 ; Get rw_mm_cause | ||
105 | move.d [$r1], $r2 ; Get last_refill_cause | ||
106 | cmp.d $r0, $r2 ; rw_mm_cause == last_refill_cause ? | ||
107 | beq 6f ; yes, increment count | ||
108 | moveq 1, $r2 | ||
109 | |||
110 | ; rw_mm_cause != last_refill_cause | ||
111 | move.d $r2, [$acr] ; refill_count = 1 | ||
112 | move.d $r0, [$r1] ; last_refill_cause = rw_mm_cause | ||
113 | |||
114 | 3: ; Probably not in a loop, continue normal processing | ||
81 | #ifdef CONFIG_SMP | 115 | #ifdef CONFIG_SMP |
82 | move $s7, $acr ; PGD | 116 | move $s7, $acr ; PGD |
83 | #else | 117 | #else |
84 | move.d per_cpu__current_pgd, $acr ; PGD | 118 | move.d per_cpu__current_pgd, $acr ; PGD |
85 | #endif | 119 | #endif |
86 | ; Look up PMD in PGD | 120 | ; Look up PMD in PGD |
87 | move $s3, $r0 ; rw_mm_cause | ||
88 | lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) | 121 | lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) |
89 | move.d [$acr], $acr ; PGD for the current process | 122 | move.d [$acr], $acr ; PGD for the current process |
90 | addi $r0.d, $acr, $acr | 123 | addi $r0.d, $acr, $acr |
91 | move $s3, $r0 ; rw_mm_cause | 124 | move $s3, $r0 ; rw_mm_cause |
92 | move.d [$acr], $acr ; Get PMD | 125 | move.d [$acr], $acr ; Get PMD |
93 | beq 1f | 126 | beq 8f |
94 | ; Look up PTE in PMD | 127 | ; Look up PTE in PMD |
95 | lsrq PAGE_SHIFT, $r0 | 128 | lsrq PAGE_SHIFT, $r0 |
96 | and.w PAGE_MASK, $acr ; Remove PMD flags | 129 | and.w PAGE_MASK, $acr ; Remove PMD flags |
97 | and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23) | 130 | and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23) |
98 | addi $r0.d, $acr, $acr | 131 | addi $r0.d, $acr, $acr |
99 | move.d [$acr], $acr ; Get PTE | 132 | move.d [$acr], $acr ; Get PTE |
100 | beq 2f | 133 | beq 9f |
101 | move.d [$sp+], $r0 ; Pop r0 in delayslot | 134 | movem [$sp], $r2 ; Restore r0-r2 in delay slot |
135 | addq 12, $sp | ||
102 | ; Store in TLB | 136 | ; Store in TLB |
103 | move $acr, $s5 | 137 | move $acr, $s5 |
104 | ; Return | 138 | 4: ; Return |
105 | move.d [$sp+], $acr | 139 | move.d [$sp+], $acr |
106 | move [$sp], $srs | 140 | move [$sp], $srs |
107 | addq 4, $sp | 141 | addq 4, $sp |
108 | rete | 142 | rete |
109 | rfe | 143 | rfe |
110 | 1: ; PMD missing, let the mm subsystem fix it up. | 144 | |
111 | move.d [$sp+], $r0 ; Pop r0 | 145 | 5: ; last_refill_cause is invalid |
112 | 2: ; PTE missing, let the mm subsystem fix it up. | 146 | moveq 1, $r2 |
147 | addq 4, $r1 ; Point to last_refill_cause | ||
148 | move.d $r2, [$acr] ; refill_count = 1 | ||
149 | move $s3, $r0 ; Get rw_mm_cause | ||
150 | ba 3b ; Continue normal processing | ||
151 | move.d $r0,[$r1] ; last_refill_cause = rw_mm_cause | ||
152 | |||
153 | 6: ; rw_mm_cause == last_refill_cause | ||
154 | move.d [$acr], $r2 ; Get refill_count | ||
155 | cmpq 4, $r2 ; refill_count > 4 ? | ||
156 | bhi 7f ; yes | ||
157 | addq 1, $r2 ; refill_count++ | ||
158 | ba 3b ; Continue normal processing | ||
159 | move.d $r2, [$acr] | ||
160 | |||
161 | 7: ; refill_count > 4, error | ||
162 | move.d $acr, $r0 ; Save pointer to refill_count | ||
163 | clear.d [$r0] ; refill_count = 0 | ||
164 | |||
165 | ;; rewind the short stack | ||
166 | movem [$sp], $r2 ; Restore r0-r2 | ||
167 | addq 12, $sp | ||
168 | move.d [$sp+], $acr | ||
169 | move [$sp], $srs | ||
170 | addq 4, $sp | ||
171 | ;; Keep it simple (slow), save all the regs. | ||
172 | SAVE_ALL | ||
173 | jsr __flush_tlb_all | ||
174 | nop | ||
175 | ba ret_from_intr ; Return | ||
176 | nop | ||
177 | |||
178 | 8: ; PMD missing, let the mm subsystem fix it up. | ||
179 | movem [$sp], $r2 ; Restore r0-r2 | ||
180 | 9: ; PTE missing, let the mm subsystem fix it up. | ||
181 | addq 12, $sp | ||
113 | move.d [$sp+], $acr | 182 | move.d [$sp+], $acr |
114 | move [$sp], $srs | 183 | move [$sp], $srs |
115 | addq 4, $sp | 184 | addq 4, $sp |
116 | SAVE_ALL | 185 | SAVE_ALL |
117 | move \mmu, $srs | 186 | move \mmu, $srs |
diff --git a/arch/cris/arch-v32/mm/tlb.c b/arch/cris/arch-v32/mm/tlb.c index a076ef6e9389..eda5ebcaea54 100644 --- a/arch/cris/arch-v32/mm/tlb.c +++ b/arch/cris/arch-v32/mm/tlb.c | |||
@@ -13,8 +13,8 @@ | |||
13 | #include <asm/arch/hwregs/supp_reg.h> | 13 | #include <asm/arch/hwregs/supp_reg.h> |
14 | 14 | ||
15 | #define UPDATE_TLB_SEL_IDX(val) \ | 15 | #define UPDATE_TLB_SEL_IDX(val) \ |
16 | do { \ | 16 | do { \ |
17 | unsigned long tlb_sel; \ | 17 | unsigned long tlb_sel; \ |
18 | \ | 18 | \ |
19 | tlb_sel = REG_FIELD(mmu, rw_mm_tlb_sel, idx, val); \ | 19 | tlb_sel = REG_FIELD(mmu, rw_mm_tlb_sel, idx, val); \ |
20 | SUPP_REG_WR(RW_MM_TLB_SEL, tlb_sel); \ | 20 | SUPP_REG_WR(RW_MM_TLB_SEL, tlb_sel); \ |
@@ -30,8 +30,8 @@ do { \ | |||
30 | * The TLB can host up to 256 different mm contexts at the same time. The running | 30 | * The TLB can host up to 256 different mm contexts at the same time. The running |
31 | * context is found in the PID register. Each TLB entry contains a page_id that | 31 | * context is found in the PID register. Each TLB entry contains a page_id that |
32 | * has to match the PID register to give a hit. page_id_map keeps track of which | 32 | * has to match the PID register to give a hit. page_id_map keeps track of which |
33 | * mm is assigned to which page_id, making sure it's known when to invalidate TLB | 33 | * mm's is assigned to which page_id's, making sure it's known when to |
34 | * entries. | 34 | * invalidate TLB entries. |
35 | * | 35 | * |
36 | * The last page_id is never running, it is used as an invalid page_id so that | 36 | * The last page_id is never running, it is used as an invalid page_id so that |
37 | * it's possible to make TLB entries that will nerver match. | 37 | * it's possible to make TLB entries that will nerver match. |
@@ -179,29 +179,29 @@ void | |||
179 | switch_mm(struct mm_struct *prev, struct mm_struct *next, | 179 | switch_mm(struct mm_struct *prev, struct mm_struct *next, |
180 | struct task_struct *tsk) | 180 | struct task_struct *tsk) |
181 | { | 181 | { |
182 | int cpu = smp_processor_id(); | 182 | if (prev != next) { |
183 | 183 | int cpu = smp_processor_id(); | |
184 | /* Make sure there is a MMU context. */ | 184 | |
185 | spin_lock(&mmu_context_lock); | 185 | /* Make sure there is a MMU context. */ |
186 | get_mmu_context(next); | 186 | spin_lock(&mmu_context_lock); |
187 | cpu_set(cpu, next->cpu_vm_mask); | 187 | get_mmu_context(next); |
188 | spin_unlock(&mmu_context_lock); | 188 | cpu_set(cpu, next->cpu_vm_mask); |
189 | 189 | spin_unlock(&mmu_context_lock); | |
190 | /* | 190 | |
191 | * Remember the pgd for the fault handlers. Keep a separate copy of it | 191 | /* |
192 | * because current and active_mm might be invalid at points where | 192 | * Remember the pgd for the fault handlers. Keep a seperate |
193 | * there's still a need to derefer the pgd. | 193 | * copy of it because current and active_mm might be invalid |
194 | */ | 194 | * at points where * there's still a need to derefer the pgd. |
195 | per_cpu(current_pgd, cpu) = next->pgd; | 195 | */ |
196 | 196 | per_cpu(current_pgd, cpu) = next->pgd; | |
197 | /* Switch context in the MMU. */ | 197 | |
198 | if (tsk && task_thread_info(tsk)) | 198 | /* Switch context in the MMU. */ |
199 | { | 199 | if (tsk && task_thread_info(tsk)) { |
200 | SPEC_REG_WR(SPEC_REG_PID, next->context.page_id | task_thread_info(tsk)->tls); | 200 | SPEC_REG_WR(SPEC_REG_PID, next->context.page_id | |
201 | } | 201 | task_thread_info(tsk)->tls); |
202 | else | 202 | } else { |
203 | { | 203 | SPEC_REG_WR(SPEC_REG_PID, next->context.page_id); |
204 | SPEC_REG_WR(SPEC_REG_PID, next->context.page_id); | 204 | } |
205 | } | 205 | } |
206 | } | 206 | } |
207 | 207 | ||
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S index fead8c59ea63..d5f28e40717c 100644 --- a/arch/cris/arch-v32/vmlinux.lds.S +++ b/arch/cris/arch-v32/vmlinux.lds.S | |||
@@ -9,6 +9,13 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <asm-generic/vmlinux.lds.h> | 11 | #include <asm-generic/vmlinux.lds.h> |
12 | #include <asm/page.h> | ||
13 | |||
14 | #ifdef CONFIG_ETRAX_VMEM_SIZE | ||
15 | #define __CONFIG_ETRAX_VMEM_SIZE CONFIG_ETRAX_VMEM_SIZE | ||
16 | #else | ||
17 | #define __CONFIG_ETRAX_VMEM_SIZE 0 | ||
18 | #endif | ||
12 | 19 | ||
13 | jiffies = jiffies_64; | 20 | jiffies = jiffies_64; |
14 | SECTIONS | 21 | SECTIONS |
@@ -17,18 +24,19 @@ SECTIONS | |||
17 | dram_start = .; | 24 | dram_start = .; |
18 | ebp_start = .; | 25 | ebp_start = .; |
19 | 26 | ||
20 | /* The boot section is only necessary until the VCS top level testbench */ | 27 | /* The boot section is only necessary until the VCS top */ |
21 | /* includes both flash and DRAM. */ | 28 | /* level testbench includes both flash and DRAM. */ |
22 | .boot : { *(.boot) } | 29 | .boot : { *(.boot) } |
23 | 30 | ||
24 | . = DRAM_VIRTUAL_BASE + 0x4000; /* See head.S and pages reserved at the start. */ | 31 | /* See head.S and pages reserved at the start. */ |
32 | . = DRAM_VIRTUAL_BASE + 0x4000; | ||
25 | 33 | ||
26 | _text = .; /* Text and read-only data. */ | 34 | _text = .; /* Text and read-only data. */ |
27 | text_start = .; /* Lots of aliases. */ | 35 | text_start = .; /* Lots of aliases. */ |
28 | _stext = .; | 36 | _stext = .; |
29 | __stext = .; | 37 | __stext = .; |
30 | .text : { | 38 | .text : { |
31 | *(.text) | 39 | TEXT_TEXT |
32 | SCHED_TEXT | 40 | SCHED_TEXT |
33 | LOCK_TEXT | 41 | LOCK_TEXT |
34 | *(.fixup) | 42 | *(.fixup) |
@@ -39,9 +47,9 @@ SECTIONS | |||
39 | __etext = .; | 47 | __etext = .; |
40 | 48 | ||
41 | . = ALIGN(4); /* Exception table. */ | 49 | . = ALIGN(4); /* Exception table. */ |
42 | __start___ex_table = .; | 50 | __start___ex_table = .; |
43 | __ex_table : { *(__ex_table) } | 51 | __ex_table : { *(__ex_table) } |
44 | __stop___ex_table = .; | 52 | __stop___ex_table = .; |
45 | 53 | ||
46 | RODATA | 54 | RODATA |
47 | 55 | ||
@@ -54,33 +62,27 @@ SECTIONS | |||
54 | __edata = . ; /* End of data section. */ | 62 | __edata = . ; /* End of data section. */ |
55 | _edata = . ; | 63 | _edata = . ; |
56 | 64 | ||
57 | . = ALIGN(8192); /* init_task and stack, must be aligned. */ | 65 | . = ALIGN(PAGE_SIZE); /* init_task and stack, must be aligned. */ |
58 | .data.init_task : { *(.data.init_task) } | 66 | .data.init_task : { *(.data.init_task) } |
59 | 67 | ||
60 | . = ALIGN(8192); /* Init code and data. */ | 68 | . = ALIGN(PAGE_SIZE); /* Init code and data. */ |
61 | __init_begin = .; | 69 | __init_begin = .; |
62 | .init.text : { | 70 | .init.text : { |
63 | _sinittext = .; | 71 | _sinittext = .; |
64 | INIT_TEXT | 72 | INIT_TEXT |
65 | _einittext = .; | 73 | _einittext = .; |
66 | } | 74 | } |
67 | .init.data : { INIT_DATA } | 75 | .init.data : { INIT_DATA } |
68 | . = ALIGN(16); | 76 | . = ALIGN(16); |
69 | __setup_start = .; | 77 | __setup_start = .; |
70 | .init.setup : { *(.init.setup) } | 78 | .init.setup : { *(.init.setup) } |
71 | __setup_end = .; | 79 | __setup_end = .; |
72 | __start___param = .; | 80 | __start___param = .; |
73 | __param : { *(__param) } | 81 | __param : { *(__param) } |
74 | __stop___param = .; | 82 | __stop___param = .; |
75 | .initcall.init : { | 83 | .initcall.init : { |
76 | __initcall_start = .; | 84 | __initcall_start = .; |
77 | *(.initcall1.init); | 85 | INITCALLS |
78 | *(.initcall2.init); | ||
79 | *(.initcall3.init); | ||
80 | *(.initcall4.init); | ||
81 | *(.initcall5.init); | ||
82 | *(.initcall6.init); | ||
83 | *(.initcall7.init); | ||
84 | __initcall_end = .; | 86 | __initcall_end = .; |
85 | } | 87 | } |
86 | 88 | ||
@@ -91,25 +93,23 @@ SECTIONS | |||
91 | } | 93 | } |
92 | SECURITY_INIT | 94 | SECURITY_INIT |
93 | 95 | ||
94 | PERCPU(8192) | 96 | __vmlinux_end = .; /* Last address of the physical file. */ |
97 | PERCPU(PAGE_SIZE) | ||
95 | 98 | ||
96 | #ifdef CONFIG_BLK_DEV_INITRD | ||
97 | .init.ramfs : { | 99 | .init.ramfs : { |
98 | __initramfs_start = .; | 100 | __initramfs_start = .; |
99 | *(.init.ramfs) | 101 | *(.init.ramfs) |
100 | __initramfs_end = .; | 102 | __initramfs_end = .; |
101 | /* | ||
102 | * We fill to the next page, so we can discard all init | ||
103 | * pages without needing to consider what payload might be | ||
104 | * appended to the kernel image. | ||
105 | */ | ||
106 | FILL (0); | ||
107 | . = ALIGN (8192); | ||
108 | } | 103 | } |
109 | #endif | ||
110 | 104 | ||
111 | __vmlinux_end = .; /* Last address of the physical file. */ | 105 | /* |
112 | __init_end = .; | 106 | * We fill to the next page, so we can discard all init |
107 | * pages without needing to consider what payload might be | ||
108 | * appended to the kernel image. | ||
109 | */ | ||
110 | . = ALIGN (PAGE_SIZE); | ||
111 | |||
112 | __init_end = .; | ||
113 | 113 | ||
114 | __data_end = . ; /* Move to _edata? */ | 114 | __data_end = . ; /* Move to _edata? */ |
115 | __bss_start = .; /* BSS. */ | 115 | __bss_start = .; /* BSS. */ |
@@ -123,11 +123,11 @@ SECTIONS | |||
123 | __end = .; | 123 | __end = .; |
124 | 124 | ||
125 | /* Sections to be discarded */ | 125 | /* Sections to be discarded */ |
126 | /DISCARD/ : { | 126 | /DISCARD/ : { |
127 | EXIT_TEXT | 127 | EXIT_TEXT |
128 | EXIT_DATA | 128 | EXIT_DATA |
129 | *(.exitcall.exit) | 129 | *(.exitcall.exit) |
130 | } | 130 | } |
131 | 131 | ||
132 | dram_end = dram_start + CONFIG_ETRAX_DRAM_SIZE*1024*1024; | 132 | dram_end = dram_start + (CONFIG_ETRAX_DRAM_SIZE - __CONFIG_ETRAX_VMEM_SIZE)*1024*1024; |
133 | } | 133 | } |