aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/c6x/clocks.txt40
-rw-r--r--Documentation/devicetree/bindings/c6x/dscr.txt127
-rw-r--r--Documentation/devicetree/bindings/c6x/emifa.txt62
-rw-r--r--Documentation/devicetree/bindings/c6x/interrupt.txt104
-rw-r--r--Documentation/devicetree/bindings/c6x/soc.txt28
-rw-r--r--Documentation/devicetree/bindings/c6x/timer64.txt26
-rw-r--r--MAINTAINERS8
-rw-r--r--arch/c6x/Kconfig174
-rw-r--r--arch/c6x/Makefile60
-rw-r--r--arch/c6x/boot/Makefile30
-rw-r--r--arch/c6x/boot/dts/dsk6455.dts62
-rw-r--r--arch/c6x/boot/dts/evmc6457.dts48
-rw-r--r--arch/c6x/boot/dts/evmc6472.dts73
-rw-r--r--arch/c6x/boot/dts/evmc6474.dts58
-rw-r--r--arch/c6x/boot/dts/tms320c6455.dtsi96
-rw-r--r--arch/c6x/boot/dts/tms320c6457.dtsi68
-rw-r--r--arch/c6x/boot/dts/tms320c6472.dtsi134
-rw-r--r--arch/c6x/boot/dts/tms320c6474.dtsi89
-rw-r--r--arch/c6x/boot/linked_dtb.S2
-rw-r--r--arch/c6x/configs/dsk6455_defconfig44
-rw-r--r--arch/c6x/configs/evmc6457_defconfig41
-rw-r--r--arch/c6x/configs/evmc6472_defconfig42
-rw-r--r--arch/c6x/configs/evmc6474_defconfig42
-rw-r--r--arch/c6x/include/asm/Kbuild54
-rw-r--r--arch/c6x/include/asm/asm-offsets.h1
-rw-r--r--arch/c6x/include/asm/bitops.h105
-rw-r--r--arch/c6x/include/asm/byteorder.h12
-rw-r--r--arch/c6x/include/asm/cache.h90
-rw-r--r--arch/c6x/include/asm/cacheflush.h65
-rw-r--r--arch/c6x/include/asm/checksum.h34
-rw-r--r--arch/c6x/include/asm/clkdev.h22
-rw-r--r--arch/c6x/include/asm/clock.h148
-rw-r--r--arch/c6x/include/asm/delay.h67
-rw-r--r--arch/c6x/include/asm/dma-mapping.h91
-rw-r--r--arch/c6x/include/asm/dscr.h34
-rw-r--r--arch/c6x/include/asm/elf.h113
-rw-r--r--arch/c6x/include/asm/ftrace.h6
-rw-r--r--arch/c6x/include/asm/hardirq.h20
-rw-r--r--arch/c6x/include/asm/irq.h302
-rw-r--r--arch/c6x/include/asm/irqflags.h72
-rw-r--r--arch/c6x/include/asm/linkage.h30
-rw-r--r--arch/c6x/include/asm/megamod-pic.h9
-rw-r--r--arch/c6x/include/asm/mmu.h18
-rw-r--r--arch/c6x/include/asm/module.h33
-rw-r--r--arch/c6x/include/asm/mutex.h6
-rw-r--r--arch/c6x/include/asm/page.h11
-rw-r--r--arch/c6x/include/asm/pgtable.h81
-rw-r--r--arch/c6x/include/asm/processor.h132
-rw-r--r--arch/c6x/include/asm/procinfo.h28
-rw-r--r--arch/c6x/include/asm/prom.h1
-rw-r--r--arch/c6x/include/asm/ptrace.h174
-rw-r--r--arch/c6x/include/asm/sections.h12
-rw-r--r--arch/c6x/include/asm/setup.h32
-rw-r--r--arch/c6x/include/asm/sigcontext.h80
-rw-r--r--arch/c6x/include/asm/signal.h17
-rw-r--r--arch/c6x/include/asm/soc.h35
-rw-r--r--arch/c6x/include/asm/string.h21
-rw-r--r--arch/c6x/include/asm/swab.h54
-rw-r--r--arch/c6x/include/asm/syscall.h123
-rw-r--r--arch/c6x/include/asm/syscalls.h55
-rw-r--r--arch/c6x/include/asm/system.h168
-rw-r--r--arch/c6x/include/asm/thread_info.h121
-rw-r--r--arch/c6x/include/asm/timer64.h6
-rw-r--r--arch/c6x/include/asm/timex.h33
-rw-r--r--arch/c6x/include/asm/tlb.h8
-rw-r--r--arch/c6x/include/asm/traps.h36
-rw-r--r--arch/c6x/include/asm/uaccess.h107
-rw-r--r--arch/c6x/include/asm/unaligned.h170
-rw-r--r--arch/c6x/include/asm/unistd.h26
-rw-r--r--arch/c6x/kernel/Makefile12
-rw-r--r--arch/c6x/kernel/asm-offsets.c123
-rw-r--r--arch/c6x/kernel/c6x_ksyms.c66
-rw-r--r--arch/c6x/kernel/devicetree.c53
-rw-r--r--arch/c6x/kernel/dma.c153
-rw-r--r--arch/c6x/kernel/entry.S803
-rw-r--r--arch/c6x/kernel/head.S84
-rw-r--r--arch/c6x/kernel/irq.c728
-rw-r--r--arch/c6x/kernel/module.c123
-rw-r--r--arch/c6x/kernel/process.c265
-rw-r--r--arch/c6x/kernel/ptrace.c187
-rw-r--r--arch/c6x/kernel/setup.c510
-rw-r--r--arch/c6x/kernel/signal.c377
-rw-r--r--arch/c6x/kernel/soc.c91
-rw-r--r--arch/c6x/kernel/switch_to.S74
-rw-r--r--arch/c6x/kernel/sys_c6x.c74
-rw-r--r--arch/c6x/kernel/time.c65
-rw-r--r--arch/c6x/kernel/traps.c423
-rw-r--r--arch/c6x/kernel/vectors.S81
-rw-r--r--arch/c6x/kernel/vmlinux.lds.S162
-rw-r--r--arch/c6x/lib/Makefile7
-rw-r--r--arch/c6x/lib/checksum.c36
-rw-r--r--arch/c6x/lib/csum_64plus.S419
-rw-r--r--arch/c6x/lib/divi.S53
-rw-r--r--arch/c6x/lib/divremi.S46
-rw-r--r--arch/c6x/lib/divremu.S87
-rw-r--r--arch/c6x/lib/divu.S98
-rw-r--r--arch/c6x/lib/llshl.S37
-rw-r--r--arch/c6x/lib/llshr.S38
-rw-r--r--arch/c6x/lib/llshru.S38
-rw-r--r--arch/c6x/lib/memcpy_64plus.S46
-rw-r--r--arch/c6x/lib/mpyll.S49
-rw-r--r--arch/c6x/lib/negll.S31
-rw-r--r--arch/c6x/lib/pop_rts.S32
-rw-r--r--arch/c6x/lib/push_rts.S31
-rw-r--r--arch/c6x/lib/remi.S64
-rw-r--r--arch/c6x/lib/remu.S82
-rw-r--r--arch/c6x/lib/strasgi.S89
-rw-r--r--arch/c6x/lib/strasgi_64plus.S39
-rw-r--r--arch/c6x/mm/Makefile5
-rw-r--r--arch/c6x/mm/dma-coherent.c143
-rw-r--r--arch/c6x/mm/init.c113
-rw-r--r--arch/c6x/platforms/Kconfig16
-rw-r--r--arch/c6x/platforms/Makefile12
-rw-r--r--arch/c6x/platforms/cache.c445
-rw-r--r--arch/c6x/platforms/dscr.c598
-rw-r--r--arch/c6x/platforms/emif.c87
-rw-r--r--arch/c6x/platforms/megamod-pic.c349
-rw-r--r--arch/c6x/platforms/platform.c17
-rw-r--r--arch/c6x/platforms/pll.c444
-rw-r--r--arch/c6x/platforms/plldata.c404
-rw-r--r--arch/c6x/platforms/timer64.c244
-rw-r--r--include/asm-generic/io.h2
-rw-r--r--include/asm-generic/page.h10
-rw-r--r--include/asm-generic/uaccess.h7
-rw-r--r--include/linux/elf-em.h1
125 files changed, 12989 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/c6x/clocks.txt b/Documentation/devicetree/bindings/c6x/clocks.txt
new file mode 100644
index 000000000000..a04f5fd30122
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/clocks.txt
@@ -0,0 +1,40 @@
1C6X PLL Clock Controllers
2-------------------------
3
4This is a first-cut support for the SoC clock controllers. This is still
5under development and will probably change as the common device tree
6clock support is added to the kernel.
7
8Required properties:
9
10- compatible: "ti,c64x+pll"
11 May also have SoC-specific value to support SoC-specific initialization
12 in the driver. One of:
13 "ti,c6455-pll"
14 "ti,c6457-pll"
15 "ti,c6472-pll"
16 "ti,c6474-pll"
17
18- reg: base address and size of register area
19- clock-frequency: input clock frequency in hz
20
21
22Optional properties:
23
24- ti,c64x+pll-bypass-delay: CPU cycles to delay when entering bypass mode
25
26- ti,c64x+pll-reset-delay: CPU cycles to delay after PLL reset
27
28- ti,c64x+pll-lock-delay: CPU cycles to delay after PLL frequency change
29
30Example:
31
32 clock-controller@29a0000 {
33 compatible = "ti,c6472-pll", "ti,c64x+pll";
34 reg = <0x029a0000 0x200>;
35 clock-frequency = <25000000>;
36
37 ti,c64x+pll-bypass-delay = <200>;
38 ti,c64x+pll-reset-delay = <12000>;
39 ti,c64x+pll-lock-delay = <80000>;
40 };
diff --git a/Documentation/devicetree/bindings/c6x/dscr.txt b/Documentation/devicetree/bindings/c6x/dscr.txt
new file mode 100644
index 000000000000..d847758f2b20
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/dscr.txt
@@ -0,0 +1,127 @@
1Device State Configuration Registers
2------------------------------------
3
4TI C6X SoCs contain a region of miscellaneous registers which provide various
5function for SoC control or status. Details vary considerably among from SoC
6to SoC with no two being alike.
7
8In general, the Device State Configuraion Registers (DSCR) will provide one or
9more configuration registers often protected by a lock register where one or
10more key values must be written to a lock register in order to unlock the
11configuration register for writes. These configuration register may be used to
12enable (and disable in some cases) SoC pin drivers, select peripheral clock
13sources (internal or pin), etc. In some cases, a configuration register is
14write once or the individual bits are write once. In addition to device config,
15the DSCR block may provide registers which which are used to reset peripherals,
16provide device ID information, provide ethernet MAC addresses, as well as other
17miscellaneous functions.
18
19For device state control (enable/disable), each device control is assigned an
20id which is used by individual device drivers to control the state as needed.
21
22Required properties:
23
24- compatible: must be "ti,c64x+dscr"
25- reg: register area base and size
26
27Optional properties:
28
29 NOTE: These are optional in that not all SoCs will have all properties. For
30 SoCs which do support a given property, leaving the property out of the
31 device tree will result in reduced functionality or possibly driver
32 failure.
33
34- ti,dscr-devstat
35 offset of the devstat register
36
37- ti,dscr-silicon-rev
38 offset, start bit, and bitsize of silicon revision field
39
40- ti,dscr-rmii-resets
41 offset and bitmask of RMII reset field. May have multiple tuples if more
42 than one ethernet port is available.
43
44- ti,dscr-locked-regs
45 possibly multiple tuples describing registers which are write protected by
46 a lock register. Each tuple consists of the register offset, lock register
47 offsset, and the key value used to unlock the register.
48
49- ti,dscr-kick-regs
50 offset and key values of two "kick" registers used to write protect other
51 registers in DSCR. On SoCs using kick registers, the first key must be
52 written to the first kick register and the second key must be written to
53 the second register before other registers in the area are write-enabled.
54
55- ti,dscr-mac-fuse-regs
56 MAC addresses are contained in two registers. Each element of a MAC address
57 is contained in a single byte. This property has two tuples. Each tuple has
58 a register offset and four cells representing bytes in the register from
59 most significant to least. The value of these four cells is the MAC byte
60 index (1-6) of the byte within the register. A value of 0 means the byte
61 is unused in the MAC address.
62
63- ti,dscr-devstate-ctl-regs
64 This property describes the bitfields used to control the state of devices.
65 Each tuple describes a range of identical bitfields used to control one or
66 more devices (one bitfield per device). The layout of each tuple is:
67
68 start_id num_ids reg enable disable start_bit nbits
69
70 Where:
71 start_id is device id for the first device control in the range
72 num_ids is the number of device controls in the range
73 reg is the offset of the register holding the control bits
74 enable is the value to enable a device
75 disable is the value to disable a device (0xffffffff if cannot disable)
76 start_bit is the bit number of the first bit in the range
77 nbits is the number of bits per device control
78
79- ti,dscr-devstate-stat-regs
80 This property describes the bitfields used to provide device state status
81 for device states controlled by the DSCR. Each tuple describes a range of
82 identical bitfields used to provide status for one or more devices (one
83 bitfield per device). The layout of each tuple is:
84
85 start_id num_ids reg enable disable start_bit nbits
86
87 Where:
88 start_id is device id for the first device status in the range
89 num_ids is the number of devices covered by the range
90 reg is the offset of the register holding the status bits
91 enable is the value indicating device is enabled
92 disable is the value indicating device is disabled
93 start_bit is the bit number of the first bit in the range
94 nbits is the number of bits per device status
95
96- ti,dscr-privperm
97 Offset and default value for register used to set access privilege for
98 some SoC devices.
99
100
101Example:
102
103 device-state-config-regs@2a80000 {
104 compatible = "ti,c64x+dscr";
105 reg = <0x02a80000 0x41000>;
106
107 ti,dscr-devstat = <0>;
108 ti,dscr-silicon-rev = <8 28 0xf>;
109 ti,dscr-rmii-resets = <0x40020 0x00040000>;
110
111 ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
112 ti,dscr-devstate-ctl-regs =
113 <0 12 0x40008 1 0 0 2
114 12 1 0x40008 3 0 30 2
115 13 2 0x4002c 1 0xffffffff 0 1>;
116 ti,dscr-devstate-stat-regs =
117 <0 10 0x40014 1 0 0 3
118 10 2 0x40018 1 0 0 3>;
119
120 ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
121 0x704 5 6 0 0>;
122
123 ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
124
125 ti,dscr-kick-regs = <0x38 0x83E70B13
126 0x3c 0x95A4F1E0>;
127 };
diff --git a/Documentation/devicetree/bindings/c6x/emifa.txt b/Documentation/devicetree/bindings/c6x/emifa.txt
new file mode 100644
index 000000000000..0ff6e9b9a13f
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/emifa.txt
@@ -0,0 +1,62 @@
1External Memory Interface
2-------------------------
3
4The emifa node describes a simple external bus controller found on some C6X
5SoCs. This interface provides external busses with a number of chip selects.
6
7Required properties:
8
9- compatible: must be "ti,c64x+emifa", "simple-bus"
10- reg: register area base and size
11- #address-cells: must be 2 (chip-select + offset)
12- #size-cells: must be 1
13- ranges: mapping from EMIFA space to parent space
14
15
16Optional properties:
17
18- ti,dscr-dev-enable: Device ID if EMIF is enabled/disabled from DSCR
19
20- ti,emifa-burst-priority:
21 Number of memory transfers after which the EMIF will elevate the priority
22 of the oldest command in the command FIFO. Setting this field to 255
23 disables this feature, thereby allowing old commands to stay in the FIFO
24 indefinitely.
25
26- ti,emifa-ce-config:
27 Configuration values for each of the supported chip selects.
28
29Example:
30
31 emifa@70000000 {
32 compatible = "ti,c64x+emifa", "simple-bus";
33 #address-cells = <2>;
34 #size-cells = <1>;
35 reg = <0x70000000 0x100>;
36 ranges = <0x2 0x0 0xa0000000 0x00000008
37 0x3 0x0 0xb0000000 0x00400000
38 0x4 0x0 0xc0000000 0x10000000
39 0x5 0x0 0xD0000000 0x10000000>;
40
41 ti,dscr-dev-enable = <13>;
42 ti,emifa-burst-priority = <255>;
43 ti,emifa-ce-config = <0x00240120
44 0x00240120
45 0x00240122
46 0x00240122>;
47
48 flash@3,0 {
49 #address-cells = <1>;
50 #size-cells = <1>;
51 compatible = "cfi-flash";
52 reg = <0x3 0x0 0x400000>;
53 bank-width = <1>;
54 device-width = <1>;
55 partition@0 {
56 reg = <0x0 0x400000>;
57 label = "NOR";
58 };
59 };
60 };
61
62This shows a flash chip attached to chip select 3.
diff --git a/Documentation/devicetree/bindings/c6x/interrupt.txt b/Documentation/devicetree/bindings/c6x/interrupt.txt
new file mode 100644
index 000000000000..42bb796cc4ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/interrupt.txt
@@ -0,0 +1,104 @@
1C6X Interrupt Chips
2-------------------
3
4* C64X+ Core Interrupt Controller
5
6 The core interrupt controller provides 16 prioritized interrupts to the
7 C64X+ core. Priority 0 and 1 are used for reset and NMI respectively.
8 Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt
9 sources coming from outside the core.
10
11 Required properties:
12 --------------------
13 - compatible: Should be "ti,c64x+core-pic";
14 - #interrupt-cells: <1>
15
16 Interrupt Specifier Definition
17 ------------------------------
18 Single cell specifying the core interrupt priority level (4-15) where
19 4 is highest priority and 15 is lowest priority.
20
21 Example
22 -------
23 core_pic: interrupt-controller@0 {
24 interrupt-controller;
25 #interrupt-cells = <1>;
26 compatible = "ti,c64x+core-pic";
27 };
28
29
30
31* C64x+ Megamodule Interrupt Controller
32
33 The megamodule PIC consists of four interrupt mupliplexers each of which
34 combine up to 32 interrupt inputs into a single interrupt output which
35 may be cascaded into the core interrupt controller. The megamodule PIC
36 has a total of 12 outputs cascading into the core interrupt controller.
37 One for each core interrupt priority level. In addition to the combined
38 interrupt sources, individual megamodule interrupts may be cascaded to
39 the core interrupt controller. When an individual interrupt is cascaded,
40 it is no longer handled through a megamodule interrupt combiner and is
41 considered to have the core interrupt controller as the parent.
42
43 Required properties:
44 --------------------
45 - compatible: "ti,c64x+megamod-pic"
46 - interrupt-controller
47 - #interrupt-cells: <1>
48 - reg: base address and size of register area
49 - interrupt-parent: must be core interrupt controller
50 - interrupts: This should have four cells; one for each interrupt combiner.
51 The cells contain the core priority interrupt to which the
52 corresponding combiner output is wired.
53
54 Optional properties:
55 --------------------
56 - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core
57 priority interrupts. The first cell corresponds to
58 core priority 4 and the last cell corresponds to
59 core priority 15. The value of each cell is the
60 megamodule interrupt source which is MUXed to
61 the core interrupt corresponding to the cell
62 position. Allowed values are 4 - 127. Mapping for
63 interrupts 0 - 3 (combined interrupt sources) are
64 ignored.
65
66 Interrupt Specifier Definition
67 ------------------------------
68 Single cell specifying the megamodule interrupt source (4-127). Note that
69 interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will
70 use the core interrupt controller as their parent and the specifier will
71 be the core priority level, not the megamodule interrupt number.
72
73 Examples
74 --------
75 megamod_pic: interrupt-controller@1800000 {
76 compatible = "ti,c64x+megamod-pic";
77 interrupt-controller;
78 #interrupt-cells = <1>;
79 reg = <0x1800000 0x1000>;
80 interrupt-parent = <&core_pic>;
81 interrupts = < 12 13 14 15 >;
82 };
83
84 This is a minimal example where all individual interrupts go through a
85 combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped
86 to interrupt 13, etc.
87
88
89 megamod_pic: interrupt-controller@1800000 {
90 compatible = "ti,c64x+megamod-pic";
91 interrupt-controller;
92 #interrupt-cells = <1>;
93 reg = <0x1800000 0x1000>;
94 interrupt-parent = <&core_pic>;
95 interrupts = < 12 13 14 15 >;
96 ti,c64x+megamod-pic-mux = < 0 0 0 0
97 32 0 0 0
98 0 0 0 0 >;
99 };
100
101 This the same as the first example except that megamodule interrupt 32 is
102 mapped directly to core priority interrupt 8. The node using this interrupt
103 must set the core controller as its interrupt parent and use 8 in the
104 interrupt specifier value.
diff --git a/Documentation/devicetree/bindings/c6x/soc.txt b/Documentation/devicetree/bindings/c6x/soc.txt
new file mode 100644
index 000000000000..b1e4973b5769
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/soc.txt
@@ -0,0 +1,28 @@
1C6X System-on-Chip
2------------------
3
4Required properties:
5
6- compatible: "simple-bus"
7- #address-cells: must be 1
8- #size-cells: must be 1
9- ranges
10
11Optional properties:
12
13- model: specific SoC model
14
15- nodes for IP blocks within SoC
16
17
18Example:
19
20 soc {
21 compatible = "simple-bus";
22 model = "tms320c6455";
23 #address-cells = <1>;
24 #size-cells = <1>;
25 ranges;
26
27 ...
28 };
diff --git a/Documentation/devicetree/bindings/c6x/timer64.txt b/Documentation/devicetree/bindings/c6x/timer64.txt
new file mode 100644
index 000000000000..95911fe70224
--- /dev/null
+++ b/Documentation/devicetree/bindings/c6x/timer64.txt
@@ -0,0 +1,26 @@
1Timer64
2-------
3
4The timer64 node describes C6X event timers.
5
6Required properties:
7
8- compatible: must be "ti,c64x+timer64"
9- reg: base address and size of register region
10- interrupt-parent: interrupt controller
11- interrupts: interrupt id
12
13Optional properties:
14
15- ti,dscr-dev-enable: Device ID used to enable timer IP through DSCR interface.
16
17- ti,core-mask: on multi-core SoCs, bitmask of cores allowed to use this timer.
18
19Example:
20 timer0: timer@25e0000 {
21 compatible = "ti,c64x+timer64";
22 ti,core-mask = < 0x01 >;
23 reg = <0x25e0000 0x40>;
24 interrupt-parent = <&megamod_pic>;
25 interrupts = < 16 >;
26 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 0460f6550e4b..311b0c405572 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1645,6 +1645,14 @@ T: git git://git.alsa-project.org/alsa-kernel.git
1645S: Maintained 1645S: Maintained
1646F: sound/pci/oxygen/ 1646F: sound/pci/oxygen/
1647 1647
1648C6X ARCHITECTURE
1649M: Mark Salter <msalter@redhat.com>
1650M: Aurelien Jacquiot <a-jacquiot@ti.com>
1651L: linux-c6x-dev@linux-c6x.org
1652W: http://www.linux-c6x.org/wiki/index.php/Main_Page
1653S: Maintained
1654F: arch/c6x/
1655
1648CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS 1656CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
1649M: David Howells <dhowells@redhat.com> 1657M: David Howells <dhowells@redhat.com>
1650L: linux-cachefs@redhat.com 1658L: linux-cachefs@redhat.com
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
new file mode 100644
index 000000000000..26e67f0f0051
--- /dev/null
+++ b/arch/c6x/Kconfig
@@ -0,0 +1,174 @@
1#
2# For a description of the syntax of this configuration file,
3# see Documentation/kbuild/kconfig-language.txt.
4#
5
6config TMS320C6X
7 def_bool y
8 select CLKDEV_LOOKUP
9 select GENERIC_IRQ_SHOW
10 select HAVE_ARCH_TRACEHOOK
11 select HAVE_DMA_API_DEBUG
12 select HAVE_GENERIC_HARDIRQS
13 select HAVE_MEMBLOCK
14 select HAVE_SPARSE_IRQ
15 select OF
16 select OF_EARLY_FLATTREE
17
18config MMU
19 def_bool n
20
21config ZONE_DMA
22 def_bool y
23
24config FPU
25 def_bool n
26
27config HIGHMEM
28 def_bool n
29
30config NUMA
31 def_bool n
32
33config RWSEM_GENERIC_SPINLOCK
34 def_bool y
35
36config RWSEM_XCHGADD_ALGORITHM
37 def_bool n
38
39config GENERIC_CALIBRATE_DELAY
40 def_bool y
41
42config GENERIC_HWEIGHT
43 def_bool y
44
45config GENERIC_CLOCKEVENTS
46 def_bool y
47
48config GENERIC_CLOCKEVENTS_BROADCAST
49 bool
50
51config GENERIC_BUG
52 def_bool y
53
54config COMMON_CLKDEV
55 def_bool y
56
57config C6X_BIG_KERNEL
58 bool "Build a big kernel"
59 help
60 The C6X function call instruction has a limited range of +/- 2MiB.
61 This is sufficient for most kernels, but some kernel configurations
62 with lots of compiled-in functionality may require a larger range
63 for function calls. Use this option to have the compiler generate
64 function calls with 32-bit range. This will make the kernel both
65 larger and slower.
66
67 If unsure, say N.
68
69source "init/Kconfig"
70
71# Use the generic interrupt handling code in kernel/irq/
72
73source "kernel/Kconfig.freezer"
74
75config CMDLINE_BOOL
76 bool "Default bootloader kernel arguments"
77
78config CMDLINE
79 string "Kernel command line"
80 depends on CMDLINE_BOOL
81 default "console=ttyS0,57600"
82 help
83 On some architectures there is currently no way for the boot loader
84 to pass arguments to the kernel. For these architectures, you should
85 supply some command-line options at build time by entering them
86 here.
87
88config CMDLINE_FORCE
89 bool "Force default kernel command string"
90 depends on CMDLINE_BOOL
91 default n
92 help
93 Set this to have arguments from the default kernel command string
94 override those passed by the boot loader.
95
96config CPU_BIG_ENDIAN
97 bool "Build big-endian kernel"
98 default n
99 help
100 Say Y if you plan on running a kernel in big-endian mode.
101 Note that your board must be properly built and your board
102 port must properly enable any big-endian related features
103 of your chipset/board/processor.
104
105config FORCE_MAX_ZONEORDER
106 int "Maximum zone order"
107 default "13"
108 help
109 The kernel memory allocator divides physically contiguous memory
110 blocks into "zones", where each zone is a power of two number of
111 pages. This option selects the largest power of two that the kernel
112 keeps in the memory allocator. If you need to allocate very large
113 blocks of physically contiguous memory, then you may need to
114 increase this value.
115
116 This config option is actually maximum order plus one. For example,
117 a value of 11 means that the largest free memory block is 2^10 pages.
118
119menu "Processor type and features"
120
121source "arch/c6x/platforms/Kconfig"
122
123config TMS320C6X_CACHES_ON
124 bool "L2 cache support"
125 default y
126
127config KERNEL_RAM_BASE_ADDRESS
128 hex "Virtual address of memory base"
129 default 0xe0000000 if SOC_TMS320C6455
130 default 0xe0000000 if SOC_TMS320C6457
131 default 0xe0000000 if SOC_TMS320C6472
132 default 0x80000000
133
134source "mm/Kconfig"
135
136source "kernel/Kconfig.preempt"
137
138source "kernel/Kconfig.hz"
139source "kernel/time/Kconfig"
140
141endmenu
142
143menu "Executable file formats"
144
145source "fs/Kconfig.binfmt"
146
147endmenu
148
149source "net/Kconfig"
150
151source "drivers/Kconfig"
152
153source "fs/Kconfig"
154
155source "security/Kconfig"
156
157source "crypto/Kconfig"
158
159source "lib/Kconfig"
160
161menu "Kernel hacking"
162
163source "lib/Kconfig.debug"
164
165config ACCESS_CHECK
166 bool "Check the user pointer address"
167 default y
168 help
169 Usually the pointer transfer from user space is checked to see if its
170 address is in the kernel space.
171
172 Say N here to disable that check to improve the performance.
173
174endmenu
diff --git a/arch/c6x/Makefile b/arch/c6x/Makefile
new file mode 100644
index 000000000000..1d08dd070277
--- /dev/null
+++ b/arch/c6x/Makefile
@@ -0,0 +1,60 @@
1#
2# linux/arch/c6x/Makefile
3#
4# This file is subject to the terms and conditions of the GNU General Public
5# License. See the file "COPYING" in the main directory of this archive
6# for more details.
7#
8
9cflags-y += -mno-dsbt -msdata=none
10
11cflags-$(CONFIG_C6X_BIG_KERNEL) += -mlong-calls
12
13CFLAGS_MODULE += -mlong-calls -mno-dsbt -msdata=none
14
15CHECKFLAGS +=
16
17KBUILD_CFLAGS += $(cflags-y)
18KBUILD_AFLAGS += $(cflags-y)
19
20ifdef CONFIG_CPU_BIG_ENDIAN
21KBUILD_CFLAGS += -mbig-endian
22KBUILD_AFLAGS += -mbig-endian
23LINKFLAGS += -mbig-endian
24KBUILD_LDFLAGS += -mbig-endian
25LDFLAGS += -EB
26endif
27
28head-y := arch/c6x/kernel/head.o
29core-y += arch/c6x/kernel/ arch/c6x/mm/ arch/c6x/platforms/
30libs-y += arch/c6x/lib/
31
32# Default to vmlinux.bin, override when needed
33all: vmlinux.bin
34
35boot := arch/$(ARCH)/boot
36
37# Are we making a dtbImage.<boardname> target? If so, crack out the boardname
38DTB:=$(subst dtbImage.,,$(filter dtbImage.%, $(MAKECMDGOALS)))
39export DTB
40
41ifneq ($(DTB),)
42core-y += $(boot)/
43endif
44
45# With make 3.82 we cannot mix normal and wildcard targets
46
47vmlinux.bin: vmlinux
48 $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
49
50dtbImage.%: vmlinux
51 $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
52
53archclean:
54 $(Q)$(MAKE) $(clean)=$(boot)
55
56define archhelp
57 @echo ' vmlinux.bin - Binary kernel image (arch/$(ARCH)/boot/vmlinux.bin)'
58 @echo ' dtbImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in'
59 @echo ' - stripped elf with fdt blob'
60endef
diff --git a/arch/c6x/boot/Makefile b/arch/c6x/boot/Makefile
new file mode 100644
index 000000000000..ecca820e6041
--- /dev/null
+++ b/arch/c6x/boot/Makefile
@@ -0,0 +1,30 @@
1#
2# Makefile for bootable kernel images
3#
4
5OBJCOPYFLAGS_vmlinux.bin := -O binary
6$(obj)/vmlinux.bin: vmlinux FORCE
7 $(call if_changed,objcopy)
8
9DTC_FLAGS ?= -p 1024
10
11ifneq ($(DTB),)
12obj-y += linked_dtb.o
13endif
14
15$(obj)/%.dtb: $(src)/dts/%.dts FORCE
16 $(call cmd,dtc)
17
18quiet_cmd_cp = CP $< $@$2
19 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false)
20
21# Generate builtin.dtb from $(DTB).dtb
22$(obj)/builtin.dtb: $(obj)/$(DTB).dtb
23 $(call if_changed,cp)
24
25$(obj)/linked_dtb.o: $(obj)/builtin.dtb
26
27$(obj)/dtbImage.%: vmlinux
28 $(call if_changed,objcopy)
29
30clean-files := $(obj)/*.dtb
diff --git a/arch/c6x/boot/dts/dsk6455.dts b/arch/c6x/boot/dts/dsk6455.dts
new file mode 100644
index 000000000000..2b71f800618d
--- /dev/null
+++ b/arch/c6x/boot/dts/dsk6455.dts
@@ -0,0 +1,62 @@
1/*
2 * arch/c6x/boot/dts/dsk6455.dts
3 *
4 * DSK6455 Evaluation Platform For TMS320C6455
5 * Copyright (C) 2011 Texas Instruments Incorporated
6 *
7 * Author: Mark Salter <msalter@redhat.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 */
15
16/dts-v1/;
17
18/include/ "tms320c6455.dtsi"
19
20/ {
21 model = "Spectrum Digital DSK6455";
22 compatible = "spectrum-digital,dsk6455";
23
24 chosen {
25 bootargs = "root=/dev/nfs ip=dhcp rw";
26 };
27
28 memory {
29 device_type = "memory";
30 reg = <0xE0000000 0x08000000>;
31 };
32
33 soc {
34 megamod_pic: interrupt-controller@1800000 {
35 interrupts = < 12 13 14 15 >;
36 };
37
38 emifa@70000000 {
39 flash@3,0 {
40 #address-cells = <1>;
41 #size-cells = <1>;
42 compatible = "cfi-flash";
43 reg = <0x3 0x0 0x400000>;
44 bank-width = <1>;
45 device-width = <1>;
46 partition@0 {
47 reg = <0x0 0x400000>;
48 label = "NOR";
49 };
50 };
51 };
52
53 timer1: timer@2980000 {
54 interrupt-parent = <&megamod_pic>;
55 interrupts = < 69 >;
56 };
57
58 clock-controller@029a0000 {
59 clock-frequency = <50000000>;
60 };
61 };
62};
diff --git a/arch/c6x/boot/dts/evmc6457.dts b/arch/c6x/boot/dts/evmc6457.dts
new file mode 100644
index 000000000000..0301eb9a8ff8
--- /dev/null
+++ b/arch/c6x/boot/dts/evmc6457.dts
@@ -0,0 +1,48 @@
1/*
2 * arch/c6x/boot/dts/evmc6457.dts
3 *
4 * EVMC6457 Evaluation Platform For TMS320C6457
5 *
6 * Copyright (C) 2011 Texas Instruments Incorporated
7 *
8 * Author: Mark Salter <msalter@redhat.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 */
16
17/dts-v1/;
18
19/include/ "tms320c6457.dtsi"
20
21/ {
22 model = "eInfochips EVMC6457";
23 compatible = "einfochips,evmc6457";
24
25 chosen {
26 bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
27 };
28
29 memory {
30 device_type = "memory";
31 reg = <0xE0000000 0x10000000>;
32 };
33
34 soc {
35 megamod_pic: interrupt-controller@1800000 {
36 interrupts = < 12 13 14 15 >;
37 };
38
39 timer0: timer@2940000 {
40 interrupt-parent = <&megamod_pic>;
41 interrupts = < 67 >;
42 };
43
44 clock-controller@29a0000 {
45 clock-frequency = <60000000>;
46 };
47 };
48};
diff --git a/arch/c6x/boot/dts/evmc6472.dts b/arch/c6x/boot/dts/evmc6472.dts
new file mode 100644
index 000000000000..3e207b449a93
--- /dev/null
+++ b/arch/c6x/boot/dts/evmc6472.dts
@@ -0,0 +1,73 @@
1/*
2 * arch/c6x/boot/dts/evmc6472.dts
3 *
4 * EVMC6472 Evaluation Platform For TMS320C6472
5 *
6 * Copyright (C) 2011 Texas Instruments Incorporated
7 *
8 * Author: Mark Salter <msalter@redhat.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 */
16
17/dts-v1/;
18
19/include/ "tms320c6472.dtsi"
20
21/ {
22 model = "eInfochips EVMC6472";
23 compatible = "einfochips,evmc6472";
24
25 chosen {
26 bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
27 };
28
29 memory {
30 device_type = "memory";
31 reg = <0xE0000000 0x10000000>;
32 };
33
34 soc {
35 megamod_pic: interrupt-controller@1800000 {
36 interrupts = < 12 13 14 15 >;
37 };
38
39 timer0: timer@25e0000 {
40 interrupt-parent = <&megamod_pic>;
41 interrupts = < 16 >;
42 };
43
44 timer1: timer@25f0000 {
45 interrupt-parent = <&megamod_pic>;
46 interrupts = < 16 >;
47 };
48
49 timer2: timer@2600000 {
50 interrupt-parent = <&megamod_pic>;
51 interrupts = < 16 >;
52 };
53
54 timer3: timer@2610000 {
55 interrupt-parent = <&megamod_pic>;
56 interrupts = < 16 >;
57 };
58
59 timer4: timer@2620000 {
60 interrupt-parent = <&megamod_pic>;
61 interrupts = < 16 >;
62 };
63
64 timer5: timer@2630000 {
65 interrupt-parent = <&megamod_pic>;
66 interrupts = < 16 >;
67 };
68
69 clock-controller@29a0000 {
70 clock-frequency = <25000000>;
71 };
72 };
73};
diff --git a/arch/c6x/boot/dts/evmc6474.dts b/arch/c6x/boot/dts/evmc6474.dts
new file mode 100644
index 000000000000..4dc291292bc4
--- /dev/null
+++ b/arch/c6x/boot/dts/evmc6474.dts
@@ -0,0 +1,58 @@
1/*
2 * arch/c6x/boot/dts/evmc6474.dts
3 *
4 * EVMC6474 Evaluation Platform For TMS320C6474
5 *
6 * Copyright (C) 2011 Texas Instruments Incorporated
7 *
8 * Author: Mark Salter <msalter@redhat.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 */
16
17/dts-v1/;
18
19/include/ "tms320c6474.dtsi"
20
21/ {
22 model = "Spectrum Digital EVMC6474";
23 compatible = "spectrum-digital,evmc6474";
24
25 chosen {
26 bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
27 };
28
29 memory {
30 device_type = "memory";
31 reg = <0x80000000 0x08000000>;
32 };
33
34 soc {
35 megamod_pic: interrupt-controller@1800000 {
36 interrupts = < 12 13 14 15 >;
37 };
38
39 timer3: timer@2940000 {
40 interrupt-parent = <&megamod_pic>;
41 interrupts = < 39 >;
42 };
43
44 timer4: timer@2950000 {
45 interrupt-parent = <&megamod_pic>;
46 interrupts = < 41 >;
47 };
48
49 timer5: timer@2960000 {
50 interrupt-parent = <&megamod_pic>;
51 interrupts = < 43 >;
52 };
53
54 clock-controller@29a0000 {
55 clock-frequency = <50000000>;
56 };
57 };
58};
diff --git a/arch/c6x/boot/dts/tms320c6455.dtsi b/arch/c6x/boot/dts/tms320c6455.dtsi
new file mode 100644
index 000000000000..a804ec1e018b
--- /dev/null
+++ b/arch/c6x/boot/dts/tms320c6455.dtsi
@@ -0,0 +1,96 @@
1
2/ {
3 #address-cells = <1>;
4 #size-cells = <1>;
5
6 cpus {
7 #address-cells = <1>;
8 #size-cells = <0>;
9
10 cpu@0 {
11 device_type = "cpu";
12 model = "ti,c64x+";
13 reg = <0>;
14 };
15 };
16
17 soc {
18 compatible = "simple-bus";
19 model = "tms320c6455";
20 #address-cells = <1>;
21 #size-cells = <1>;
22 ranges;
23
24 core_pic: interrupt-controller {
25 interrupt-controller;
26 #interrupt-cells = <1>;
27 compatible = "ti,c64x+core-pic";
28 };
29
30 /*
31 * Megamodule interrupt controller
32 */
33 megamod_pic: interrupt-controller@1800000 {
34 compatible = "ti,c64x+megamod-pic";
35 interrupt-controller;
36 #interrupt-cells = <1>;
37 reg = <0x1800000 0x1000>;
38 interrupt-parent = <&core_pic>;
39 };
40
41 cache-controller@1840000 {
42 compatible = "ti,c64x+cache";
43 reg = <0x01840000 0x8400>;
44 };
45
46 emifa@70000000 {
47 compatible = "ti,c64x+emifa", "simple-bus";
48 #address-cells = <2>;
49 #size-cells = <1>;
50 reg = <0x70000000 0x100>;
51 ranges = <0x2 0x0 0xa0000000 0x00000008
52 0x3 0x0 0xb0000000 0x00400000
53 0x4 0x0 0xc0000000 0x10000000
54 0x5 0x0 0xD0000000 0x10000000>;
55
56 ti,dscr-dev-enable = <13>;
57 ti,emifa-burst-priority = <255>;
58 ti,emifa-ce-config = <0x00240120
59 0x00240120
60 0x00240122
61 0x00240122>;
62 };
63
64 timer1: timer@2980000 {
65 compatible = "ti,c64x+timer64";
66 reg = <0x2980000 0x40>;
67 ti,dscr-dev-enable = <4>;
68 };
69
70 clock-controller@029a0000 {
71 compatible = "ti,c6455-pll", "ti,c64x+pll";
72 reg = <0x029a0000 0x200>;
73 ti,c64x+pll-bypass-delay = <1440>;
74 ti,c64x+pll-reset-delay = <15360>;
75 ti,c64x+pll-lock-delay = <24000>;
76 };
77
78 device-state-config-regs@2a80000 {
79 compatible = "ti,c64x+dscr";
80 reg = <0x02a80000 0x41000>;
81
82 ti,dscr-devstat = <0>;
83 ti,dscr-silicon-rev = <8 28 0xf>;
84 ti,dscr-rmii-resets = <0 0x40020 0x00040000>;
85
86 ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
87 ti,dscr-devstate-ctl-regs =
88 <0 12 0x40008 1 0 0 2
89 12 1 0x40008 3 0 30 2
90 13 2 0x4002c 1 0xffffffff 0 1>;
91 ti,dscr-devstate-stat-regs =
92 <0 10 0x40014 1 0 0 3
93 10 2 0x40018 1 0 0 3>;
94 };
95 };
96};
diff --git a/arch/c6x/boot/dts/tms320c6457.dtsi b/arch/c6x/boot/dts/tms320c6457.dtsi
new file mode 100644
index 000000000000..35f40709a719
--- /dev/null
+++ b/arch/c6x/boot/dts/tms320c6457.dtsi
@@ -0,0 +1,68 @@
1
2/ {
3 #address-cells = <1>;
4 #size-cells = <1>;
5
6 cpus {
7 #address-cells = <1>;
8 #size-cells = <0>;
9
10 cpu@0 {
11 device_type = "cpu";
12 model = "ti,c64x+";
13 reg = <0>;
14 };
15 };
16
17 soc {
18 compatible = "simple-bus";
19 model = "tms320c6457";
20 #address-cells = <1>;
21 #size-cells = <1>;
22 ranges;
23
24 core_pic: interrupt-controller {
25 interrupt-controller;
26 #interrupt-cells = <1>;
27 compatible = "ti,c64x+core-pic";
28 };
29
30 megamod_pic: interrupt-controller@1800000 {
31 compatible = "ti,c64x+megamod-pic";
32 interrupt-controller;
33 #interrupt-cells = <1>;
34 interrupt-parent = <&core_pic>;
35 reg = <0x1800000 0x1000>;
36 };
37
38 cache-controller@1840000 {
39 compatible = "ti,c64x+cache";
40 reg = <0x01840000 0x8400>;
41 };
42
43 device-state-controller@2880800 {
44 compatible = "ti,c64x+dscr";
45 reg = <0x02880800 0x400>;
46
47 ti,dscr-devstat = <0x20>;
48 ti,dscr-silicon-rev = <0x18 28 0xf>;
49 ti,dscr-mac-fuse-regs = <0x114 3 4 5 6
50 0x118 0 0 1 2>;
51 ti,dscr-kick-regs = <0x38 0x83E70B13
52 0x3c 0x95A4F1E0>;
53 };
54
55 timer0: timer@2940000 {
56 compatible = "ti,c64x+timer64";
57 reg = <0x2940000 0x40>;
58 };
59
60 clock-controller@29a0000 {
61 compatible = "ti,c6457-pll", "ti,c64x+pll";
62 reg = <0x029a0000 0x200>;
63 ti,c64x+pll-bypass-delay = <300>;
64 ti,c64x+pll-reset-delay = <24000>;
65 ti,c64x+pll-lock-delay = <50000>;
66 };
67 };
68};
diff --git a/arch/c6x/boot/dts/tms320c6472.dtsi b/arch/c6x/boot/dts/tms320c6472.dtsi
new file mode 100644
index 000000000000..b488aaec65c0
--- /dev/null
+++ b/arch/c6x/boot/dts/tms320c6472.dtsi
@@ -0,0 +1,134 @@
1
2/ {
3 #address-cells = <1>;
4 #size-cells = <1>;
5
6 cpus {
7 #address-cells = <1>;
8 #size-cells = <0>;
9
10 cpu@0 {
11 device_type = "cpu";
12 reg = <0>;
13 model = "ti,c64x+";
14 };
15 cpu@1 {
16 device_type = "cpu";
17 reg = <1>;
18 model = "ti,c64x+";
19 };
20 cpu@2 {
21 device_type = "cpu";
22 reg = <2>;
23 model = "ti,c64x+";
24 };
25 cpu@3 {
26 device_type = "cpu";
27 reg = <3>;
28 model = "ti,c64x+";
29 };
30 cpu@4 {
31 device_type = "cpu";
32 reg = <4>;
33 model = "ti,c64x+";
34 };
35 cpu@5 {
36 device_type = "cpu";
37 reg = <5>;
38 model = "ti,c64x+";
39 };
40 };
41
42 soc {
43 compatible = "simple-bus";
44 model = "tms320c6472";
45 #address-cells = <1>;
46 #size-cells = <1>;
47 ranges;
48
49 core_pic: interrupt-controller {
50 compatible = "ti,c64x+core-pic";
51 interrupt-controller;
52 #interrupt-cells = <1>;
53 };
54
55 megamod_pic: interrupt-controller@1800000 {
56 compatible = "ti,c64x+megamod-pic";
57 interrupt-controller;
58 #interrupt-cells = <1>;
59 reg = <0x1800000 0x1000>;
60 interrupt-parent = <&core_pic>;
61 };
62
63 cache-controller@1840000 {
64 compatible = "ti,c64x+cache";
65 reg = <0x01840000 0x8400>;
66 };
67
68 timer0: timer@25e0000 {
69 compatible = "ti,c64x+timer64";
70 ti,core-mask = < 0x01 >;
71 reg = <0x25e0000 0x40>;
72 };
73
74 timer1: timer@25f0000 {
75 compatible = "ti,c64x+timer64";
76 ti,core-mask = < 0x02 >;
77 reg = <0x25f0000 0x40>;
78 };
79
80 timer2: timer@2600000 {
81 compatible = "ti,c64x+timer64";
82 ti,core-mask = < 0x04 >;
83 reg = <0x2600000 0x40>;
84 };
85
86 timer3: timer@2610000 {
87 compatible = "ti,c64x+timer64";
88 ti,core-mask = < 0x08 >;
89 reg = <0x2610000 0x40>;
90 };
91
92 timer4: timer@2620000 {
93 compatible = "ti,c64x+timer64";
94 ti,core-mask = < 0x10 >;
95 reg = <0x2620000 0x40>;
96 };
97
98 timer5: timer@2630000 {
99 compatible = "ti,c64x+timer64";
100 ti,core-mask = < 0x20 >;
101 reg = <0x2630000 0x40>;
102 };
103
104 clock-controller@29a0000 {
105 compatible = "ti,c6472-pll", "ti,c64x+pll";
106 reg = <0x029a0000 0x200>;
107 ti,c64x+pll-bypass-delay = <200>;
108 ti,c64x+pll-reset-delay = <12000>;
109 ti,c64x+pll-lock-delay = <80000>;
110 };
111
112 device-state-controller@2a80000 {
113 compatible = "ti,c64x+dscr";
114 reg = <0x02a80000 0x1000>;
115
116 ti,dscr-devstat = <0>;
117 ti,dscr-silicon-rev = <0x70c 16 0xff>;
118
119 ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
120 0x704 5 6 0 0>;
121
122 ti,dscr-rmii-resets = <0x208 1
123 0x20c 1>;
124
125 ti,dscr-locked-regs = <0x200 0x204 0x0a1e183a
126 0x40c 0x420 0xbea7
127 0x41c 0x420 0xbea7>;
128
129 ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
130
131 ti,dscr-devstate-ctl-regs = <0 13 0x200 1 0 0 1>;
132 };
133 };
134};
diff --git a/arch/c6x/boot/dts/tms320c6474.dtsi b/arch/c6x/boot/dts/tms320c6474.dtsi
new file mode 100644
index 000000000000..cc601bf348a1
--- /dev/null
+++ b/arch/c6x/boot/dts/tms320c6474.dtsi
@@ -0,0 +1,89 @@
1
2/ {
3 #address-cells = <1>;
4 #size-cells = <1>;
5
6 cpus {
7 #address-cells = <1>;
8 #size-cells = <0>;
9
10 cpu@0 {
11 device_type = "cpu";
12 reg = <0>;
13 model = "ti,c64x+";
14 };
15 cpu@1 {
16 device_type = "cpu";
17 reg = <1>;
18 model = "ti,c64x+";
19 };
20 cpu@2 {
21 device_type = "cpu";
22 reg = <2>;
23 model = "ti,c64x+";
24 };
25 };
26
27 soc {
28 compatible = "simple-bus";
29 model = "tms320c6474";
30 #address-cells = <1>;
31 #size-cells = <1>;
32 ranges;
33
34 core_pic: interrupt-controller {
35 interrupt-controller;
36 #interrupt-cells = <1>;
37 compatible = "ti,c64x+core-pic";
38 };
39
40 megamod_pic: interrupt-controller@1800000 {
41 compatible = "ti,c64x+megamod-pic";
42 interrupt-controller;
43 #interrupt-cells = <1>;
44 reg = <0x1800000 0x1000>;
45 interrupt-parent = <&core_pic>;
46 };
47
48 cache-controller@1840000 {
49 compatible = "ti,c64x+cache";
50 reg = <0x01840000 0x8400>;
51 };
52
53 timer3: timer@2940000 {
54 compatible = "ti,c64x+timer64";
55 ti,core-mask = < 0x04 >;
56 reg = <0x2940000 0x40>;
57 };
58
59 timer4: timer@2950000 {
60 compatible = "ti,c64x+timer64";
61 ti,core-mask = < 0x02 >;
62 reg = <0x2950000 0x40>;
63 };
64
65 timer5: timer@2960000 {
66 compatible = "ti,c64x+timer64";
67 ti,core-mask = < 0x01 >;
68 reg = <0x2960000 0x40>;
69 };
70
71 device-state-controller@2880800 {
72 compatible = "ti,c64x+dscr";
73 reg = <0x02880800 0x400>;
74
75 ti,dscr-devstat = <0x004>;
76 ti,dscr-silicon-rev = <0x014 28 0xf>;
77 ti,dscr-mac-fuse-regs = <0x34 3 4 5 6
78 0x38 0 0 1 2>;
79 };
80
81 clock-controller@29a0000 {
82 compatible = "ti,c6474-pll", "ti,c64x+pll";
83 reg = <0x029a0000 0x200>;
84 ti,c64x+pll-bypass-delay = <120>;
85 ti,c64x+pll-reset-delay = <30000>;
86 ti,c64x+pll-lock-delay = <60000>;
87 };
88 };
89};
diff --git a/arch/c6x/boot/linked_dtb.S b/arch/c6x/boot/linked_dtb.S
new file mode 100644
index 000000000000..57a4454eaec3
--- /dev/null
+++ b/arch/c6x/boot/linked_dtb.S
@@ -0,0 +1,2 @@
1.section __fdt_blob,"a"
2.incbin "arch/c6x/boot/builtin.dtb"
diff --git a/arch/c6x/configs/dsk6455_defconfig b/arch/c6x/configs/dsk6455_defconfig
new file mode 100644
index 000000000000..4663487c67a1
--- /dev/null
+++ b/arch/c6x/configs/dsk6455_defconfig
@@ -0,0 +1,44 @@
1CONFIG_SOC_TMS320C6455=y
2CONFIG_EXPERIMENTAL=y
3# CONFIG_LOCALVERSION_AUTO is not set
4CONFIG_SYSVIPC=y
5CONFIG_SPARSE_IRQ=y
6CONFIG_LOG_BUF_SHIFT=14
7CONFIG_NAMESPACES=y
8# CONFIG_UTS_NS is not set
9# CONFIG_USER_NS is not set
10# CONFIG_PID_NS is not set
11CONFIG_BLK_DEV_INITRD=y
12CONFIG_CC_OPTIMIZE_FOR_SIZE=y
13CONFIG_EXPERT=y
14# CONFIG_FUTEX is not set
15# CONFIG_SLUB_DEBUG is not set
16CONFIG_MODULES=y
17CONFIG_MODULE_FORCE_LOAD=y
18CONFIG_MODULE_UNLOAD=y
19CONFIG_MODULE_FORCE_UNLOAD=y
20CONFIG_CMDLINE_BOOL=y
21CONFIG_CMDLINE=""
22CONFIG_NO_HZ=y
23CONFIG_HIGH_RES_TIMERS=y
24CONFIG_BLK_DEV_LOOP=y
25CONFIG_BLK_DEV_RAM=y
26CONFIG_BLK_DEV_RAM_COUNT=2
27CONFIG_BLK_DEV_RAM_SIZE=17000
28CONFIG_MISC_DEVICES=y
29# CONFIG_INPUT is not set
30# CONFIG_SERIO is not set
31# CONFIG_VT is not set
32# CONFIG_HW_RANDOM is not set
33# CONFIG_HWMON is not set
34# CONFIG_USB_SUPPORT is not set
35# CONFIG_IOMMU_SUPPORT is not set
36# CONFIG_MISC_FILESYSTEMS is not set
37CONFIG_CRC16=y
38# CONFIG_ENABLE_MUST_CHECK is not set
39# CONFIG_SCHED_DEBUG is not set
40# CONFIG_DEBUG_BUGVERBOSE is not set
41CONFIG_MTD=y
42CONFIG_MTD_CFI=y
43CONFIG_MTD_CFI_AMDSTD=y
44CONFIG_MTD_PHYSMAP_OF=y
diff --git a/arch/c6x/configs/evmc6457_defconfig b/arch/c6x/configs/evmc6457_defconfig
new file mode 100644
index 000000000000..bba40e195ec4
--- /dev/null
+++ b/arch/c6x/configs/evmc6457_defconfig
@@ -0,0 +1,41 @@
1CONFIG_SOC_TMS320C6457=y
2CONFIG_EXPERIMENTAL=y
3# CONFIG_LOCALVERSION_AUTO is not set
4CONFIG_SYSVIPC=y
5CONFIG_SPARSE_IRQ=y
6CONFIG_LOG_BUF_SHIFT=14
7CONFIG_NAMESPACES=y
8# CONFIG_UTS_NS is not set
9# CONFIG_USER_NS is not set
10# CONFIG_PID_NS is not set
11CONFIG_BLK_DEV_INITRD=y
12CONFIG_CC_OPTIMIZE_FOR_SIZE=y
13CONFIG_EXPERT=y
14# CONFIG_FUTEX is not set
15# CONFIG_SLUB_DEBUG is not set
16CONFIG_MODULES=y
17CONFIG_MODULE_FORCE_LOAD=y
18CONFIG_MODULE_UNLOAD=y
19CONFIG_MODULE_FORCE_UNLOAD=y
20CONFIG_CMDLINE_BOOL=y
21CONFIG_CMDLINE=""
22CONFIG_BOARD_EVM6457=y
23CONFIG_NO_HZ=y
24CONFIG_HIGH_RES_TIMERS=y
25CONFIG_BLK_DEV_LOOP=y
26CONFIG_BLK_DEV_RAM=y
27CONFIG_BLK_DEV_RAM_COUNT=2
28CONFIG_BLK_DEV_RAM_SIZE=17000
29CONFIG_MISC_DEVICES=y
30# CONFIG_INPUT is not set
31# CONFIG_SERIO is not set
32# CONFIG_VT is not set
33# CONFIG_HW_RANDOM is not set
34# CONFIG_HWMON is not set
35# CONFIG_USB_SUPPORT is not set
36# CONFIG_IOMMU_SUPPORT is not set
37# CONFIG_MISC_FILESYSTEMS is not set
38CONFIG_CRC16=y
39# CONFIG_ENABLE_MUST_CHECK is not set
40# CONFIG_SCHED_DEBUG is not set
41# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/configs/evmc6472_defconfig b/arch/c6x/configs/evmc6472_defconfig
new file mode 100644
index 000000000000..8c46155f6d31
--- /dev/null
+++ b/arch/c6x/configs/evmc6472_defconfig
@@ -0,0 +1,42 @@
1CONFIG_SOC_TMS320C6472=y
2CONFIG_EXPERIMENTAL=y
3# CONFIG_LOCALVERSION_AUTO is not set
4CONFIG_SYSVIPC=y
5CONFIG_SPARSE_IRQ=y
6CONFIG_LOG_BUF_SHIFT=14
7CONFIG_NAMESPACES=y
8# CONFIG_UTS_NS is not set
9# CONFIG_USER_NS is not set
10# CONFIG_PID_NS is not set
11CONFIG_BLK_DEV_INITRD=y
12CONFIG_CC_OPTIMIZE_FOR_SIZE=y
13CONFIG_EXPERT=y
14# CONFIG_FUTEX is not set
15# CONFIG_SLUB_DEBUG is not set
16CONFIG_MODULES=y
17CONFIG_MODULE_FORCE_LOAD=y
18CONFIG_MODULE_UNLOAD=y
19CONFIG_MODULE_FORCE_UNLOAD=y
20CONFIG_CMDLINE_BOOL=y
21CONFIG_CMDLINE=""
22# CONFIG_CMDLINE_FORCE is not set
23CONFIG_BOARD_EVM6472=y
24CONFIG_NO_HZ=y
25CONFIG_HIGH_RES_TIMERS=y
26CONFIG_BLK_DEV_LOOP=y
27CONFIG_BLK_DEV_RAM=y
28CONFIG_BLK_DEV_RAM_COUNT=2
29CONFIG_BLK_DEV_RAM_SIZE=17000
30CONFIG_MISC_DEVICES=y
31# CONFIG_INPUT is not set
32# CONFIG_SERIO is not set
33# CONFIG_VT is not set
34# CONFIG_HW_RANDOM is not set
35# CONFIG_HWMON is not set
36# CONFIG_USB_SUPPORT is not set
37# CONFIG_IOMMU_SUPPORT is not set
38# CONFIG_MISC_FILESYSTEMS is not set
39CONFIG_CRC16=y
40# CONFIG_ENABLE_MUST_CHECK is not set
41# CONFIG_SCHED_DEBUG is not set
42# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/configs/evmc6474_defconfig b/arch/c6x/configs/evmc6474_defconfig
new file mode 100644
index 000000000000..15533f632313
--- /dev/null
+++ b/arch/c6x/configs/evmc6474_defconfig
@@ -0,0 +1,42 @@
1CONFIG_SOC_TMS320C6474=y
2CONFIG_EXPERIMENTAL=y
3# CONFIG_LOCALVERSION_AUTO is not set
4CONFIG_SYSVIPC=y
5CONFIG_SPARSE_IRQ=y
6CONFIG_LOG_BUF_SHIFT=14
7CONFIG_NAMESPACES=y
8# CONFIG_UTS_NS is not set
9# CONFIG_USER_NS is not set
10# CONFIG_PID_NS is not set
11CONFIG_BLK_DEV_INITRD=y
12CONFIG_CC_OPTIMIZE_FOR_SIZE=y
13CONFIG_EXPERT=y
14# CONFIG_FUTEX is not set
15# CONFIG_SLUB_DEBUG is not set
16CONFIG_MODULES=y
17CONFIG_MODULE_FORCE_LOAD=y
18CONFIG_MODULE_UNLOAD=y
19CONFIG_MODULE_FORCE_UNLOAD=y
20CONFIG_CMDLINE_BOOL=y
21CONFIG_CMDLINE=""
22# CONFIG_CMDLINE_FORCE is not set
23CONFIG_BOARD_EVM6474=y
24CONFIG_NO_HZ=y
25CONFIG_HIGH_RES_TIMERS=y
26CONFIG_BLK_DEV_LOOP=y
27CONFIG_BLK_DEV_RAM=y
28CONFIG_BLK_DEV_RAM_COUNT=2
29CONFIG_BLK_DEV_RAM_SIZE=17000
30CONFIG_MISC_DEVICES=y
31# CONFIG_INPUT is not set
32# CONFIG_SERIO is not set
33# CONFIG_VT is not set
34# CONFIG_HW_RANDOM is not set
35# CONFIG_HWMON is not set
36# CONFIG_USB_SUPPORT is not set
37# CONFIG_IOMMU_SUPPORT is not set
38# CONFIG_MISC_FILESYSTEMS is not set
39CONFIG_CRC16=y
40# CONFIG_ENABLE_MUST_CHECK is not set
41# CONFIG_SCHED_DEBUG is not set
42# CONFIG_DEBUG_BUGVERBOSE is not set
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
new file mode 100644
index 000000000000..13dcf78adf91
--- /dev/null
+++ b/arch/c6x/include/asm/Kbuild
@@ -0,0 +1,54 @@
1include include/asm-generic/Kbuild.asm
2
3generic-y += atomic.h
4generic-y += auxvec.h
5generic-y += bitsperlong.h
6generic-y += bug.h
7generic-y += bugs.h
8generic-y += cputime.h
9generic-y += current.h
10generic-y += device.h
11generic-y += div64.h
12generic-y += dma.h
13generic-y += emergency-restart.h
14generic-y += errno.h
15generic-y += fb.h
16generic-y += fcntl.h
17generic-y += futex.h
18generic-y += hw_irq.h
19generic-y += io.h
20generic-y += ioctl.h
21generic-y += ioctls.h
22generic-y += ipcbuf.h
23generic-y += irq_regs.h
24generic-y += kdebug.h
25generic-y += kmap_types.h
26generic-y += local.h
27generic-y += mman.h
28generic-y += mmu_context.h
29generic-y += msgbuf.h
30generic-y += param.h
31generic-y += pci.h
32generic-y += percpu.h
33generic-y += pgalloc.h
34generic-y += poll.h
35generic-y += posix_types.h
36generic-y += resource.h
37generic-y += scatterlist.h
38generic-y += segment.h
39generic-y += sembuf.h
40generic-y += shmbuf.h
41generic-y += shmparam.h
42generic-y += siginfo.h
43generic-y += socket.h
44generic-y += sockios.h
45generic-y += stat.h
46generic-y += statfs.h
47generic-y += termbits.h
48generic-y += termios.h
49generic-y += tlbflush.h
50generic-y += topology.h
51generic-y += types.h
52generic-y += ucontext.h
53generic-y += user.h
54generic-y += vga.h
diff --git a/arch/c6x/include/asm/asm-offsets.h b/arch/c6x/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/c6x/include/asm/asm-offsets.h
@@ -0,0 +1 @@
#include <generated/asm-offsets.h>
diff --git a/arch/c6x/include/asm/bitops.h b/arch/c6x/include/asm/bitops.h
new file mode 100644
index 000000000000..39ab7e874d96
--- /dev/null
+++ b/arch/c6x/include/asm/bitops.h
@@ -0,0 +1,105 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_BITOPS_H
12#define _ASM_C6X_BITOPS_H
13
14#ifdef __KERNEL__
15
16#include <linux/bitops.h>
17
18#include <asm/system.h>
19#include <asm/byteorder.h>
20
21/*
22 * clear_bit() doesn't provide any barrier for the compiler.
23 */
24#define smp_mb__before_clear_bit() barrier()
25#define smp_mb__after_clear_bit() barrier()
26
27/*
28 * We are lucky, DSP is perfect for bitops: do it in 3 cycles
29 */
30
31/**
32 * __ffs - find first bit in word.
33 * @word: The word to search
34 *
35 * Undefined if no bit exists, so code should check against 0 first.
36 * Note __ffs(0) = undef, __ffs(1) = 0, __ffs(0x80000000) = 31.
37 *
38 */
39static inline unsigned long __ffs(unsigned long x)
40{
41 asm (" bitr .M1 %0,%0\n"
42 " nop\n"
43 " lmbd .L1 1,%0,%0\n"
44 : "+a"(x));
45
46 return x;
47}
48
49/*
50 * ffz - find first zero in word.
51 * @word: The word to search
52 *
53 * Undefined if no zero exists, so code should check against ~0UL first.
54 */
55#define ffz(x) __ffs(~(x))
56
57/**
58 * fls - find last (most-significant) bit set
59 * @x: the word to search
60 *
61 * This is defined the same way as ffs.
62 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
63 */
64static inline int fls(int x)
65{
66 if (!x)
67 return 0;
68
69 asm (" lmbd .L1 1,%0,%0\n" : "+a"(x));
70
71 return 32 - x;
72}
73
74/**
75 * ffs - find first bit set
76 * @x: the word to search
77 *
78 * This is defined the same way as
79 * the libc and compiler builtin ffs routines, therefore
80 * differs in spirit from the above ffz (man ffs).
81 * Note ffs(0) = 0, ffs(1) = 1, ffs(0x80000000) = 32.
82 */
83static inline int ffs(int x)
84{
85 if (!x)
86 return 0;
87
88 return __ffs(x) + 1;
89}
90
91#include <asm-generic/bitops/__fls.h>
92#include <asm-generic/bitops/fls64.h>
93#include <asm-generic/bitops/find.h>
94
95#include <asm-generic/bitops/sched.h>
96#include <asm-generic/bitops/hweight.h>
97#include <asm-generic/bitops/lock.h>
98
99#include <asm-generic/bitops/atomic.h>
100#include <asm-generic/bitops/non-atomic.h>
101#include <asm-generic/bitops/le.h>
102#include <asm-generic/bitops/ext2-atomic.h>
103
104#endif /* __KERNEL__ */
105#endif /* _ASM_C6X_BITOPS_H */
diff --git a/arch/c6x/include/asm/byteorder.h b/arch/c6x/include/asm/byteorder.h
new file mode 100644
index 000000000000..166038db342b
--- /dev/null
+++ b/arch/c6x/include/asm/byteorder.h
@@ -0,0 +1,12 @@
1#ifndef _ASM_C6X_BYTEORDER_H
2#define _ASM_C6X_BYTEORDER_H
3
4#include <asm/types.h>
5
6#ifdef _BIG_ENDIAN
7#include <linux/byteorder/big_endian.h>
8#else /* _BIG_ENDIAN */
9#include <linux/byteorder/little_endian.h>
10#endif /* _BIG_ENDIAN */
11
12#endif /* _ASM_BYTEORDER_H */
diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h
new file mode 100644
index 000000000000..6d521d96d941
--- /dev/null
+++ b/arch/c6x/include/asm/cache.h
@@ -0,0 +1,90 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_CACHE_H
12#define _ASM_C6X_CACHE_H
13
14#include <linux/irqflags.h>
15
16/*
17 * Cache line size
18 */
19#define L1D_CACHE_BYTES 64
20#define L1P_CACHE_BYTES 32
21#define L2_CACHE_BYTES 128
22
23/*
24 * L2 used as cache
25 */
26#define L2MODE_SIZE L2MODE_256K_CACHE
27
28/*
29 * For practical reasons the L1_CACHE_BYTES defines should not be smaller than
30 * the L2 line size
31 */
32#define L1_CACHE_BYTES L2_CACHE_BYTES
33
34#define L2_CACHE_ALIGN_LOW(x) \
35 (((x) & ~(L2_CACHE_BYTES - 1)))
36#define L2_CACHE_ALIGN_UP(x) \
37 (((x) + (L2_CACHE_BYTES - 1)) & ~(L2_CACHE_BYTES - 1))
38#define L2_CACHE_ALIGN_CNT(x) \
39 (((x) + (sizeof(int) - 1)) & ~(sizeof(int) - 1))
40
41#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
42#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES
43
44/*
45 * This is the granularity of hardware cacheability control.
46 */
47#define CACHEABILITY_ALIGN 0x01000000
48
49/*
50 * Align a physical address to MAR regions
51 */
52#define CACHE_REGION_START(v) \
53 (((u32) (v)) & ~(CACHEABILITY_ALIGN - 1))
54#define CACHE_REGION_END(v) \
55 (((u32) (v) + (CACHEABILITY_ALIGN - 1)) & ~(CACHEABILITY_ALIGN - 1))
56
57extern void __init c6x_cache_init(void);
58
59extern void enable_caching(unsigned long start, unsigned long end);
60extern void disable_caching(unsigned long start, unsigned long end);
61
62extern void L1_cache_off(void);
63extern void L1_cache_on(void);
64
65extern void L1P_cache_global_invalidate(void);
66extern void L1D_cache_global_invalidate(void);
67extern void L1D_cache_global_writeback(void);
68extern void L1D_cache_global_writeback_invalidate(void);
69extern void L2_cache_set_mode(unsigned int mode);
70extern void L2_cache_global_writeback_invalidate(void);
71extern void L2_cache_global_writeback(void);
72
73extern void L1P_cache_block_invalidate(unsigned int start, unsigned int end);
74extern void L1D_cache_block_invalidate(unsigned int start, unsigned int end);
75extern void L1D_cache_block_writeback_invalidate(unsigned int start,
76 unsigned int end);
77extern void L1D_cache_block_writeback(unsigned int start, unsigned int end);
78extern void L2_cache_block_invalidate(unsigned int start, unsigned int end);
79extern void L2_cache_block_writeback(unsigned int start, unsigned int end);
80extern void L2_cache_block_writeback_invalidate(unsigned int start,
81 unsigned int end);
82extern void L2_cache_block_invalidate_nowait(unsigned int start,
83 unsigned int end);
84extern void L2_cache_block_writeback_nowait(unsigned int start,
85 unsigned int end);
86
87extern void L2_cache_block_writeback_invalidate_nowait(unsigned int start,
88 unsigned int end);
89
90#endif /* _ASM_C6X_CACHE_H */
diff --git a/arch/c6x/include/asm/cacheflush.h b/arch/c6x/include/asm/cacheflush.h
new file mode 100644
index 000000000000..df5db90dbe56
--- /dev/null
+++ b/arch/c6x/include/asm/cacheflush.h
@@ -0,0 +1,65 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_CACHEFLUSH_H
12#define _ASM_C6X_CACHEFLUSH_H
13
14#include <linux/spinlock.h>
15
16#include <asm/setup.h>
17#include <asm/cache.h>
18#include <asm/mman.h>
19#include <asm/page.h>
20#include <asm/string.h>
21
22/*
23 * virtually-indexed cache management (our cache is physically indexed)
24 */
25#define flush_cache_all() do {} while (0)
26#define flush_cache_mm(mm) do {} while (0)
27#define flush_cache_dup_mm(mm) do {} while (0)
28#define flush_cache_range(mm, start, end) do {} while (0)
29#define flush_cache_page(vma, vmaddr, pfn) do {} while (0)
30#define flush_cache_vmap(start, end) do {} while (0)
31#define flush_cache_vunmap(start, end) do {} while (0)
32#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
33#define flush_dcache_page(page) do {} while (0)
34#define flush_dcache_mmap_lock(mapping) do {} while (0)
35#define flush_dcache_mmap_unlock(mapping) do {} while (0)
36
37/*
38 * physically-indexed cache management
39 */
40#define flush_icache_range(s, e) \
41do { \
42 L1D_cache_block_writeback((s), (e)); \
43 L1P_cache_block_invalidate((s), (e)); \
44} while (0)
45
46#define flush_icache_page(vma, page) \
47do { \
48 if ((vma)->vm_flags & PROT_EXEC) \
49 L1D_cache_block_writeback_invalidate(page_address(page), \
50 (unsigned long) page_address(page) + PAGE_SIZE)); \
51 L1P_cache_block_invalidate(page_address(page), \
52 (unsigned long) page_address(page) + PAGE_SIZE)); \
53} while (0)
54
55
56#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
57do { \
58 memcpy(dst, src, len); \
59 flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
60} while (0)
61
62#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
63 memcpy(dst, src, len)
64
65#endif /* _ASM_C6X_CACHEFLUSH_H */
diff --git a/arch/c6x/include/asm/checksum.h b/arch/c6x/include/asm/checksum.h
new file mode 100644
index 000000000000..7246816d6e4d
--- /dev/null
+++ b/arch/c6x/include/asm/checksum.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#ifndef _ASM_C6X_CHECKSUM_H
10#define _ASM_C6X_CHECKSUM_H
11
12static inline __wsum
13csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
14 unsigned short proto, __wsum sum)
15{
16 unsigned long long tmp;
17
18 asm ("add .d1 %1,%5,%1\n"
19 "|| addu .l1 %3,%4,%0\n"
20 "addu .l1 %2,%0,%0\n"
21#ifndef CONFIG_CPU_BIG_ENDIAN
22 "|| shl .s1 %1,8,%1\n"
23#endif
24 "addu .l1 %1,%0,%0\n"
25 "add .l1 %P0,%p0,%2\n"
26 : "=&a"(tmp), "+a"(len), "+a"(sum)
27 : "a" (saddr), "a" (daddr), "a" (proto));
28 return sum;
29}
30#define csum_tcpudp_nofold csum_tcpudp_nofold
31
32#include <asm-generic/checksum.h>
33
34#endif /* _ASM_C6X_CHECKSUM_H */
diff --git a/arch/c6x/include/asm/clkdev.h b/arch/c6x/include/asm/clkdev.h
new file mode 100644
index 000000000000..76a070b1c2e5
--- /dev/null
+++ b/arch/c6x/include/asm/clkdev.h
@@ -0,0 +1,22 @@
1#ifndef _ASM_CLKDEV_H
2#define _ASM_CLKDEV_H
3
4#include <linux/slab.h>
5
6struct clk;
7
8static inline int __clk_get(struct clk *clk)
9{
10 return 1;
11}
12
13static inline void __clk_put(struct clk *clk)
14{
15}
16
17static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
18{
19 return kzalloc(size, GFP_KERNEL);
20}
21
22#endif /* _ASM_CLKDEV_H */
diff --git a/arch/c6x/include/asm/clock.h b/arch/c6x/include/asm/clock.h
new file mode 100644
index 000000000000..bcf42b2b4b1e
--- /dev/null
+++ b/arch/c6x/include/asm/clock.h
@@ -0,0 +1,148 @@
1/*
2 * TI C64X clock definitions
3 *
4 * Copyright (C) 2010, 2011 Texas Instruments.
5 * Contributed by: Mark Salter <msalter@redhat.com>
6 *
7 * Copied heavily from arm/mach-davinci/clock.h, so:
8 *
9 * Copyright (C) 2006-2007 Texas Instruments.
10 * Copyright (C) 2008-2009 Deep Root Systems, LLC
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#ifndef _ASM_C6X_CLOCK_H
18#define _ASM_C6X_CLOCK_H
19
20#ifndef __ASSEMBLER__
21
22#include <linux/list.h>
23
24/* PLL/Reset register offsets */
25#define PLLCTL 0x100
26#define PLLM 0x110
27#define PLLPRE 0x114
28#define PLLDIV1 0x118
29#define PLLDIV2 0x11c
30#define PLLDIV3 0x120
31#define PLLPOST 0x128
32#define PLLCMD 0x138
33#define PLLSTAT 0x13c
34#define PLLALNCTL 0x140
35#define PLLDCHANGE 0x144
36#define PLLCKEN 0x148
37#define PLLCKSTAT 0x14c
38#define PLLSYSTAT 0x150
39#define PLLDIV4 0x160
40#define PLLDIV5 0x164
41#define PLLDIV6 0x168
42#define PLLDIV7 0x16c
43#define PLLDIV8 0x170
44#define PLLDIV9 0x174
45#define PLLDIV10 0x178
46#define PLLDIV11 0x17c
47#define PLLDIV12 0x180
48#define PLLDIV13 0x184
49#define PLLDIV14 0x188
50#define PLLDIV15 0x18c
51#define PLLDIV16 0x190
52
53/* PLLM register bits */
54#define PLLM_PLLM_MASK 0xff
55#define PLLM_VAL(x) ((x) - 1)
56
57/* PREDIV register bits */
58#define PLLPREDIV_EN BIT(15)
59#define PLLPREDIV_VAL(x) ((x) - 1)
60
61/* PLLCTL register bits */
62#define PLLCTL_PLLEN BIT(0)
63#define PLLCTL_PLLPWRDN BIT(1)
64#define PLLCTL_PLLRST BIT(3)
65#define PLLCTL_PLLDIS BIT(4)
66#define PLLCTL_PLLENSRC BIT(5)
67#define PLLCTL_CLKMODE BIT(8)
68
69/* PLLCMD register bits */
70#define PLLCMD_GOSTAT BIT(0)
71
72/* PLLSTAT register bits */
73#define PLLSTAT_GOSTAT BIT(0)
74
75/* PLLDIV register bits */
76#define PLLDIV_EN BIT(15)
77#define PLLDIV_RATIO_MASK 0x1f
78#define PLLDIV_RATIO(x) ((x) - 1)
79
80struct pll_data;
81
82struct clk {
83 struct list_head node;
84 struct module *owner;
85 const char *name;
86 unsigned long rate;
87 int usecount;
88 u32 flags;
89 struct clk *parent;
90 struct list_head children; /* list of children */
91 struct list_head childnode; /* parent's child list node */
92 struct pll_data *pll_data;
93 u32 div;
94 unsigned long (*recalc) (struct clk *);
95 int (*set_rate) (struct clk *clk, unsigned long rate);
96 int (*round_rate) (struct clk *clk, unsigned long rate);
97};
98
99/* Clock flags: SoC-specific flags start at BIT(16) */
100#define ALWAYS_ENABLED BIT(1)
101#define CLK_PLL BIT(2) /* PLL-derived clock */
102#define PRE_PLL BIT(3) /* source is before PLL mult/div */
103#define FIXED_DIV_PLL BIT(4) /* fixed divisor from PLL */
104#define FIXED_RATE_PLL BIT(5) /* fixed ouput rate PLL */
105
106#define MAX_PLL_SYSCLKS 16
107
108struct pll_data {
109 void __iomem *base;
110 u32 num;
111 u32 flags;
112 u32 input_rate;
113 u32 bypass_delay; /* in loops */
114 u32 reset_delay; /* in loops */
115 u32 lock_delay; /* in loops */
116 struct clk sysclks[MAX_PLL_SYSCLKS + 1];
117};
118
119/* pll_data flag bit */
120#define PLL_HAS_PRE BIT(0)
121#define PLL_HAS_MUL BIT(1)
122#define PLL_HAS_POST BIT(2)
123
124#define CLK(dev, con, ck) \
125 { \
126 .dev_id = dev, \
127 .con_id = con, \
128 .clk = ck, \
129 } \
130
131extern void c6x_clks_init(struct clk_lookup *clocks);
132extern int clk_register(struct clk *clk);
133extern void clk_unregister(struct clk *clk);
134extern void c64x_setup_clocks(void);
135
136extern struct pll_data c6x_soc_pll1;
137
138extern struct clk clkin1;
139extern struct clk c6x_core_clk;
140extern struct clk c6x_i2c_clk;
141extern struct clk c6x_watchdog_clk;
142extern struct clk c6x_mcbsp1_clk;
143extern struct clk c6x_mcbsp2_clk;
144extern struct clk c6x_mdio_clk;
145
146#endif
147
148#endif /* _ASM_C6X_CLOCK_H */
diff --git a/arch/c6x/include/asm/delay.h b/arch/c6x/include/asm/delay.h
new file mode 100644
index 000000000000..f314c2e9eb54
--- /dev/null
+++ b/arch/c6x/include/asm/delay.h
@@ -0,0 +1,67 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_DELAY_H
12#define _ASM_C6X_DELAY_H
13
14#include <linux/kernel.h>
15
16extern unsigned int ticks_per_ns_scaled;
17
18static inline void __delay(unsigned long loops)
19{
20 uint32_t tmp;
21
22 /* 6 cycles per loop */
23 asm volatile (" mv .s1 %0,%1\n"
24 "0: [%1] b .s1 0b\n"
25 " add .l1 -6,%0,%0\n"
26 " cmplt .l1 1,%0,%1\n"
27 " nop 3\n"
28 : "+a"(loops), "=A"(tmp));
29}
30
31static inline void _c6x_tickdelay(unsigned int x)
32{
33 uint32_t cnt, endcnt;
34
35 asm volatile (" mvc .s2 TSCL,%0\n"
36 " add .s2x %0,%1,%2\n"
37 " || mvk .l2 1,B0\n"
38 "0: [B0] b .s2 0b\n"
39 " mvc .s2 TSCL,%0\n"
40 " sub .s2 %0,%2,%0\n"
41 " cmpgt .l2 0,%0,B0\n"
42 " nop 2\n"
43 : "=b"(cnt), "+a"(x), "=b"(endcnt) : : "B0");
44}
45
46/* use scaled math to avoid slow division */
47#define C6X_NDELAY_SCALE 10
48
49static inline void _ndelay(unsigned int n)
50{
51 _c6x_tickdelay((ticks_per_ns_scaled * n) >> C6X_NDELAY_SCALE);
52}
53
54static inline void _udelay(unsigned int n)
55{
56 while (n >= 10) {
57 _ndelay(10000);
58 n -= 10;
59 }
60 while (n-- > 0)
61 _ndelay(1000);
62}
63
64#define udelay(x) _udelay((unsigned int)(x))
65#define ndelay(x) _ndelay((unsigned int)(x))
66
67#endif /* _ASM_C6X_DELAY_H */
diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h
new file mode 100644
index 000000000000..03579fd99dba
--- /dev/null
+++ b/arch/c6x/include/asm/dma-mapping.h
@@ -0,0 +1,91 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot <aurelien.jacquiot@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#ifndef _ASM_C6X_DMA_MAPPING_H
13#define _ASM_C6X_DMA_MAPPING_H
14
15#include <linux/dma-debug.h>
16#include <asm-generic/dma-coherent.h>
17
18#define dma_supported(d, m) 1
19
20static inline int dma_set_mask(struct device *dev, u64 dma_mask)
21{
22 if (!dev->dma_mask || !dma_supported(dev, dma_mask))
23 return -EIO;
24
25 *dev->dma_mask = dma_mask;
26
27 return 0;
28}
29
30/*
31 * DMA errors are defined by all-bits-set in the DMA address.
32 */
33static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
34{
35 return dma_addr == ~0;
36}
37
38extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
39 size_t size, enum dma_data_direction dir);
40
41extern void dma_unmap_single(struct device *dev, dma_addr_t handle,
42 size_t size, enum dma_data_direction dir);
43
44extern int dma_map_sg(struct device *dev, struct scatterlist *sglist,
45 int nents, enum dma_data_direction direction);
46
47extern void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
48 int nents, enum dma_data_direction direction);
49
50static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
51 unsigned long offset, size_t size,
52 enum dma_data_direction dir)
53{
54 dma_addr_t handle;
55
56 handle = dma_map_single(dev, page_address(page) + offset, size, dir);
57
58 debug_dma_map_page(dev, page, offset, size, dir, handle, false);
59
60 return handle;
61}
62
63static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
64 size_t size, enum dma_data_direction dir)
65{
66 dma_unmap_single(dev, handle, size, dir);
67
68 debug_dma_unmap_page(dev, handle, size, dir, false);
69}
70
71extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
72 size_t size, enum dma_data_direction dir);
73
74extern void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
75 size_t size,
76 enum dma_data_direction dir);
77
78extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
79 int nents, enum dma_data_direction dir);
80
81extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
82 int nents, enum dma_data_direction dir);
83
84extern void coherent_mem_init(u32 start, u32 size);
85extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
86extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
87
88#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
89#define dma_free_noncoherent(d, s, v, h) dma_free_coherent((d), (s), (v), (h))
90
91#endif /* _ASM_C6X_DMA_MAPPING_H */
diff --git a/arch/c6x/include/asm/dscr.h b/arch/c6x/include/asm/dscr.h
new file mode 100644
index 000000000000..561ba8332042
--- /dev/null
+++ b/arch/c6x/include/asm/dscr.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 */
10#ifndef _ASM_C6X_DSCR_H
11#define _ASM_C6X_DSCR_H
12
13enum dscr_devstate_t {
14 DSCR_DEVSTATE_ENABLED,
15 DSCR_DEVSTATE_DISABLED,
16};
17
18/*
19 * Set the device state of the device with the given ID.
20 *
21 * Individual drivers should use this to enable or disable the
22 * hardware device. The devid used to identify the device being
23 * controlled should be a property in the device's tree node.
24 */
25extern void dscr_set_devstate(int devid, enum dscr_devstate_t state);
26
27/*
28 * Assert or de-assert an RMII reset.
29 */
30extern void dscr_rmii_reset(int id, int assert);
31
32extern void dscr_probe(void);
33
34#endif /* _ASM_C6X_DSCR_H */
diff --git a/arch/c6x/include/asm/elf.h b/arch/c6x/include/asm/elf.h
new file mode 100644
index 000000000000..d57865ba2c44
--- /dev/null
+++ b/arch/c6x/include/asm/elf.h
@@ -0,0 +1,113 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_ELF_H
12#define _ASM_C6X_ELF_H
13
14/*
15 * ELF register definitions..
16 */
17#include <asm/ptrace.h>
18
19typedef unsigned long elf_greg_t;
20typedef unsigned long elf_fpreg_t;
21
22#define ELF_NGREG 58
23#define ELF_NFPREG 1
24
25typedef elf_greg_t elf_gregset_t[ELF_NGREG];
26typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
27
28/*
29 * This is used to ensure we don't load something for the wrong architecture.
30 */
31#define elf_check_arch(x) ((x)->e_machine == EM_TI_C6000)
32
33#define elf_check_const_displacement(x) (1)
34
35/*
36 * These are used to set parameters in the core dumps.
37 */
38#ifdef __LITTLE_ENDIAN__
39#define ELF_DATA ELFDATA2LSB
40#else
41#define ELF_DATA ELFDATA2MSB
42#endif
43
44#define ELF_CLASS ELFCLASS32
45#define ELF_ARCH EM_TI_C6000
46
47/* Nothing for now. Need to setup DP... */
48#define ELF_PLAT_INIT(_r)
49
50#define USE_ELF_CORE_DUMP
51#define ELF_EXEC_PAGESIZE 4096
52
53#define ELF_CORE_COPY_REGS(_dest, _regs) \
54 memcpy((char *) &_dest, (char *) _regs, \
55 sizeof(struct pt_regs));
56
57/* This yields a mask that user programs can use to figure out what
58 instruction set this cpu supports. */
59
60#define ELF_HWCAP (0)
61
62/* This yields a string that ld.so will use to load implementation
63 specific libraries for optimization. This is more specific in
64 intent than poking at uname or /proc/cpuinfo. */
65
66#define ELF_PLATFORM (NULL)
67
68#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
69
70/* C6X specific section types */
71#define SHT_C6000_UNWIND 0x70000001
72#define SHT_C6000_PREEMPTMAP 0x70000002
73#define SHT_C6000_ATTRIBUTES 0x70000003
74
75/* C6X specific DT_ tags */
76#define DT_C6000_DSBT_BASE 0x70000000
77#define DT_C6000_DSBT_SIZE 0x70000001
78#define DT_C6000_PREEMPTMAP 0x70000002
79#define DT_C6000_DSBT_INDEX 0x70000003
80
81/* C6X specific relocs */
82#define R_C6000_NONE 0
83#define R_C6000_ABS32 1
84#define R_C6000_ABS16 2
85#define R_C6000_ABS8 3
86#define R_C6000_PCR_S21 4
87#define R_C6000_PCR_S12 5
88#define R_C6000_PCR_S10 6
89#define R_C6000_PCR_S7 7
90#define R_C6000_ABS_S16 8
91#define R_C6000_ABS_L16 9
92#define R_C6000_ABS_H16 10
93#define R_C6000_SBR_U15_B 11
94#define R_C6000_SBR_U15_H 12
95#define R_C6000_SBR_U15_W 13
96#define R_C6000_SBR_S16 14
97#define R_C6000_SBR_L16_B 15
98#define R_C6000_SBR_L16_H 16
99#define R_C6000_SBR_L16_W 17
100#define R_C6000_SBR_H16_B 18
101#define R_C6000_SBR_H16_H 19
102#define R_C6000_SBR_H16_W 20
103#define R_C6000_SBR_GOT_U15_W 21
104#define R_C6000_SBR_GOT_L16_W 22
105#define R_C6000_SBR_GOT_H16_W 23
106#define R_C6000_DSBT_INDEX 24
107#define R_C6000_PREL31 25
108#define R_C6000_COPY 26
109#define R_C6000_ALIGN 253
110#define R_C6000_FPHEAD 254
111#define R_C6000_NOCMP 255
112
113#endif /*_ASM_C6X_ELF_H */
diff --git a/arch/c6x/include/asm/ftrace.h b/arch/c6x/include/asm/ftrace.h
new file mode 100644
index 000000000000..3701958d3d1c
--- /dev/null
+++ b/arch/c6x/include/asm/ftrace.h
@@ -0,0 +1,6 @@
1#ifndef _ASM_C6X_FTRACE_H
2#define _ASM_C6X_FTRACE_H
3
4/* empty */
5
6#endif /* _ASM_C6X_FTRACE_H */
diff --git a/arch/c6x/include/asm/hardirq.h b/arch/c6x/include/asm/hardirq.h
new file mode 100644
index 000000000000..9621954f98f4
--- /dev/null
+++ b/arch/c6x/include/asm/hardirq.h
@@ -0,0 +1,20 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _ASM_C6X_HARDIRQ_H
13#define _ASM_C6X_HARDIRQ_H
14
15extern void ack_bad_irq(int irq);
16#define ack_bad_irq ack_bad_irq
17
18#include <asm-generic/hardirq.h>
19
20#endif /* _ASM_C6X_HARDIRQ_H */
diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h
new file mode 100644
index 000000000000..a6ae3c9d9c40
--- /dev/null
+++ b/arch/c6x/include/asm/irq.h
@@ -0,0 +1,302 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Large parts taken directly from powerpc.
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#ifndef _ASM_C6X_IRQ_H
14#define _ASM_C6X_IRQ_H
15
16#include <linux/threads.h>
17#include <linux/list.h>
18#include <linux/radix-tree.h>
19#include <asm/percpu.h>
20
21#define irq_canonicalize(irq) (irq)
22
23/*
24 * The C64X+ core has 16 IRQ vectors. One each is used by Reset and NMI. Two
25 * are reserved. The remaining 12 vectors are used to route SoC interrupts.
26 * These interrupt vectors are prioritized with IRQ 4 having the highest
27 * priority and IRQ 15 having the lowest.
28 *
29 * The C64x+ megamodule provides a PIC which combines SoC IRQ sources into a
30 * single core IRQ vector. There are four combined sources, each of which
31 * feed into one of the 12 general interrupt vectors. The remaining 8 vectors
32 * can each route a single SoC interrupt directly.
33 */
34#define NR_PRIORITY_IRQS 16
35
36#define NR_IRQS_LEGACY NR_PRIORITY_IRQS
37
38/* Total number of virq in the platform */
39#define NR_IRQS 256
40
41/* This number is used when no interrupt has been assigned */
42#define NO_IRQ 0
43
44/* This type is the placeholder for a hardware interrupt number. It has to
45 * be big enough to enclose whatever representation is used by a given
46 * platform.
47 */
48typedef unsigned long irq_hw_number_t;
49
50/* Interrupt controller "host" data structure. This could be defined as a
51 * irq domain controller. That is, it handles the mapping between hardware
52 * and virtual interrupt numbers for a given interrupt domain. The host
53 * structure is generally created by the PIC code for a given PIC instance
54 * (though a host can cover more than one PIC if they have a flat number
55 * model). It's the host callbacks that are responsible for setting the
56 * irq_chip on a given irq_desc after it's been mapped.
57 *
58 * The host code and data structures are fairly agnostic to the fact that
59 * we use an open firmware device-tree. We do have references to struct
60 * device_node in two places: in irq_find_host() to find the host matching
61 * a given interrupt controller node, and of course as an argument to its
62 * counterpart host->ops->match() callback. However, those are treated as
63 * generic pointers by the core and the fact that it's actually a device-node
64 * pointer is purely a convention between callers and implementation. This
65 * code could thus be used on other architectures by replacing those two
66 * by some sort of arch-specific void * "token" used to identify interrupt
67 * controllers.
68 */
69struct irq_host;
70struct radix_tree_root;
71struct device_node;
72
73/* Functions below are provided by the host and called whenever a new mapping
74 * is created or an old mapping is disposed. The host can then proceed to
75 * whatever internal data structures management is required. It also needs
76 * to setup the irq_desc when returning from map().
77 */
78struct irq_host_ops {
79 /* Match an interrupt controller device node to a host, returns
80 * 1 on a match
81 */
82 int (*match)(struct irq_host *h, struct device_node *node);
83
84 /* Create or update a mapping between a virtual irq number and a hw
85 * irq number. This is called only once for a given mapping.
86 */
87 int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
88
89 /* Dispose of such a mapping */
90 void (*unmap)(struct irq_host *h, unsigned int virq);
91
92 /* Translate device-tree interrupt specifier from raw format coming
93 * from the firmware to a irq_hw_number_t (interrupt line number) and
94 * type (sense) that can be passed to set_irq_type(). In the absence
95 * of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
96 * will return the hw number in the first cell and IRQ_TYPE_NONE for
97 * the type (which amount to keeping whatever default value the
98 * interrupt controller has for that line)
99 */
100 int (*xlate)(struct irq_host *h, struct device_node *ctrler,
101 const u32 *intspec, unsigned int intsize,
102 irq_hw_number_t *out_hwirq, unsigned int *out_type);
103};
104
105struct irq_host {
106 struct list_head link;
107
108 /* type of reverse mapping technique */
109 unsigned int revmap_type;
110#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */
111#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */
112#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */
113#define IRQ_HOST_MAP_TREE 3 /* radix tree */
114 union {
115 struct {
116 unsigned int size;
117 unsigned int *revmap;
118 } linear;
119 struct radix_tree_root tree;
120 } revmap_data;
121 struct irq_host_ops *ops;
122 void *host_data;
123 irq_hw_number_t inval_irq;
124
125 /* Optional device node pointer */
126 struct device_node *of_node;
127};
128
129struct irq_data;
130extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
131extern irq_hw_number_t virq_to_hw(unsigned int virq);
132extern bool virq_is_host(unsigned int virq, struct irq_host *host);
133
134/**
135 * irq_alloc_host - Allocate a new irq_host data structure
136 * @of_node: optional device-tree node of the interrupt controller
137 * @revmap_type: type of reverse mapping to use
138 * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
139 * @ops: map/unmap host callbacks
140 * @inval_irq: provide a hw number in that host space that is always invalid
141 *
142 * Allocates and initialize and irq_host structure. Note that in the case of
143 * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
144 * for all legacy interrupts except 0 (which is always the invalid irq for
145 * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
146 * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
147 * later during boot automatically (the reverse mapping will use the slow path
148 * until that happens).
149 */
150extern struct irq_host *irq_alloc_host(struct device_node *of_node,
151 unsigned int revmap_type,
152 unsigned int revmap_arg,
153 struct irq_host_ops *ops,
154 irq_hw_number_t inval_irq);
155
156
157/**
158 * irq_find_host - Locates a host for a given device node
159 * @node: device-tree node of the interrupt controller
160 */
161extern struct irq_host *irq_find_host(struct device_node *node);
162
163
164/**
165 * irq_set_default_host - Set a "default" host
166 * @host: default host pointer
167 *
168 * For convenience, it's possible to set a "default" host that will be used
169 * whenever NULL is passed to irq_create_mapping(). It makes life easier for
170 * platforms that want to manipulate a few hard coded interrupt numbers that
171 * aren't properly represented in the device-tree.
172 */
173extern void irq_set_default_host(struct irq_host *host);
174
175
176/**
177 * irq_set_virq_count - Set the maximum number of virt irqs
178 * @count: number of linux virtual irqs, capped with NR_IRQS
179 *
180 * This is mainly for use by platforms like iSeries who want to program
181 * the virtual irq number in the controller to avoid the reverse mapping
182 */
183extern void irq_set_virq_count(unsigned int count);
184
185
186/**
187 * irq_create_mapping - Map a hardware interrupt into linux virq space
188 * @host: host owning this hardware interrupt or NULL for default host
189 * @hwirq: hardware irq number in that host space
190 *
191 * Only one mapping per hardware interrupt is permitted. Returns a linux
192 * virq number.
193 * If the sense/trigger is to be specified, set_irq_type() should be called
194 * on the number returned from that call.
195 */
196extern unsigned int irq_create_mapping(struct irq_host *host,
197 irq_hw_number_t hwirq);
198
199
200/**
201 * irq_dispose_mapping - Unmap an interrupt
202 * @virq: linux virq number of the interrupt to unmap
203 */
204extern void irq_dispose_mapping(unsigned int virq);
205
206/**
207 * irq_find_mapping - Find a linux virq from an hw irq number.
208 * @host: host owning this hardware interrupt
209 * @hwirq: hardware irq number in that host space
210 *
211 * This is a slow path, for use by generic code. It's expected that an
212 * irq controller implementation directly calls the appropriate low level
213 * mapping function.
214 */
215extern unsigned int irq_find_mapping(struct irq_host *host,
216 irq_hw_number_t hwirq);
217
218/**
219 * irq_create_direct_mapping - Allocate a virq for direct mapping
220 * @host: host to allocate the virq for or NULL for default host
221 *
222 * This routine is used for irq controllers which can choose the hardware
223 * interrupt numbers they generate. In such a case it's simplest to use
224 * the linux virq as the hardware interrupt number.
225 */
226extern unsigned int irq_create_direct_mapping(struct irq_host *host);
227
228/**
229 * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
230 * @host: host owning this hardware interrupt
231 * @virq: linux irq number
232 * @hwirq: hardware irq number in that host space
233 *
234 * This is for use by irq controllers that use a radix tree reverse
235 * mapping for fast lookup.
236 */
237extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
238 irq_hw_number_t hwirq);
239
240/**
241 * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
242 * @host: host owning this hardware interrupt
243 * @hwirq: hardware irq number in that host space
244 *
245 * This is a fast path, for use by irq controller code that uses radix tree
246 * revmaps
247 */
248extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
249 irq_hw_number_t hwirq);
250
251/**
252 * irq_linear_revmap - Find a linux virq from a hw irq number.
253 * @host: host owning this hardware interrupt
254 * @hwirq: hardware irq number in that host space
255 *
256 * This is a fast path, for use by irq controller code that uses linear
257 * revmaps. It does fallback to the slow path if the revmap doesn't exist
258 * yet and will create the revmap entry with appropriate locking
259 */
260
261extern unsigned int irq_linear_revmap(struct irq_host *host,
262 irq_hw_number_t hwirq);
263
264
265
266/**
267 * irq_alloc_virt - Allocate virtual irq numbers
268 * @host: host owning these new virtual irqs
269 * @count: number of consecutive numbers to allocate
270 * @hint: pass a hint number, the allocator will try to use a 1:1 mapping
271 *
272 * This is a low level function that is used internally by irq_create_mapping()
273 * and that can be used by some irq controllers implementations for things
274 * like allocating ranges of numbers for MSIs. The revmaps are left untouched.
275 */
276extern unsigned int irq_alloc_virt(struct irq_host *host,
277 unsigned int count,
278 unsigned int hint);
279
280/**
281 * irq_free_virt - Free virtual irq numbers
282 * @virq: virtual irq number of the first interrupt to free
283 * @count: number of interrupts to free
284 *
285 * This function is the opposite of irq_alloc_virt. It will not clear reverse
286 * maps, this should be done previously by unmap'ing the interrupt. In fact,
287 * all interrupts covered by the range being freed should have been unmapped
288 * prior to calling this.
289 */
290extern void irq_free_virt(unsigned int virq, unsigned int count);
291
292extern void __init init_pic_c64xplus(void);
293
294extern void init_IRQ(void);
295
296struct pt_regs;
297
298extern asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs);
299
300extern unsigned long irq_err_count;
301
302#endif /* _ASM_C6X_IRQ_H */
diff --git a/arch/c6x/include/asm/irqflags.h b/arch/c6x/include/asm/irqflags.h
new file mode 100644
index 000000000000..cf78e09e18c3
--- /dev/null
+++ b/arch/c6x/include/asm/irqflags.h
@@ -0,0 +1,72 @@
1/*
2 * C6X IRQ flag handling
3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated
5 * Written by Mark Salter (msalter@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#ifndef _ASM_IRQFLAGS_H
14#define _ASM_IRQFLAGS_H
15
16#ifndef __ASSEMBLY__
17
18/* read interrupt enabled status */
19static inline unsigned long arch_local_save_flags(void)
20{
21 unsigned long flags;
22
23 asm volatile (" mvc .s2 CSR,%0\n" : "=b"(flags));
24 return flags;
25}
26
27/* set interrupt enabled status */
28static inline void arch_local_irq_restore(unsigned long flags)
29{
30 asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags));
31}
32
33/* unconditionally enable interrupts */
34static inline void arch_local_irq_enable(void)
35{
36 unsigned long flags = arch_local_save_flags();
37 flags |= 1;
38 arch_local_irq_restore(flags);
39}
40
41/* unconditionally disable interrupts */
42static inline void arch_local_irq_disable(void)
43{
44 unsigned long flags = arch_local_save_flags();
45 flags &= ~1;
46 arch_local_irq_restore(flags);
47}
48
49/* get status and disable interrupts */
50static inline unsigned long arch_local_irq_save(void)
51{
52 unsigned long flags;
53
54 flags = arch_local_save_flags();
55 arch_local_irq_restore(flags & ~1);
56 return flags;
57}
58
59/* test flags */
60static inline int arch_irqs_disabled_flags(unsigned long flags)
61{
62 return (flags & 1) == 0;
63}
64
65/* test hardware interrupt enable bit */
66static inline int arch_irqs_disabled(void)
67{
68 return arch_irqs_disabled_flags(arch_local_save_flags());
69}
70
71#endif /* __ASSEMBLY__ */
72#endif /* __ASM_IRQFLAGS_H */
diff --git a/arch/c6x/include/asm/linkage.h b/arch/c6x/include/asm/linkage.h
new file mode 100644
index 000000000000..376925c47d57
--- /dev/null
+++ b/arch/c6x/include/asm/linkage.h
@@ -0,0 +1,30 @@
1#ifndef _ASM_C6X_LINKAGE_H
2#define _ASM_C6X_LINKAGE_H
3
4#ifdef __ASSEMBLER__
5
6#define __ALIGN .align 2
7#define __ALIGN_STR ".align 2"
8
9#ifndef __DSBT__
10#define ENTRY(name) \
11 .global name @ \
12 __ALIGN @ \
13name:
14#else
15#define ENTRY(name) \
16 .global name @ \
17 .hidden name @ \
18 __ALIGN @ \
19name:
20#endif
21
22#define ENDPROC(name) \
23 .type name, @function @ \
24 .size name, . - name
25
26#endif
27
28#include <asm-generic/linkage.h>
29
30#endif /* _ASM_C6X_LINKAGE_H */
diff --git a/arch/c6x/include/asm/megamod-pic.h b/arch/c6x/include/asm/megamod-pic.h
new file mode 100644
index 000000000000..eca0a8678034
--- /dev/null
+++ b/arch/c6x/include/asm/megamod-pic.h
@@ -0,0 +1,9 @@
1#ifndef _C6X_MEGAMOD_PIC_H
2#define _C6X_MEGAMOD_PIC_H
3
4#ifdef __KERNEL__
5
6extern void __init megamod_pic_init(void);
7
8#endif /* __KERNEL__ */
9#endif /* _C6X_MEGAMOD_PIC_H */
diff --git a/arch/c6x/include/asm/mmu.h b/arch/c6x/include/asm/mmu.h
new file mode 100644
index 000000000000..41592bf16067
--- /dev/null
+++ b/arch/c6x/include/asm/mmu.h
@@ -0,0 +1,18 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_MMU_H
12#define _ASM_C6X_MMU_H
13
14typedef struct {
15 unsigned long end_brk;
16} mm_context_t;
17
18#endif /* _ASM_C6X_MMU_H */
diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h
new file mode 100644
index 000000000000..a453f9744f42
--- /dev/null
+++ b/arch/c6x/include/asm/module.h
@@ -0,0 +1,33 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Updated for 2.6.34 by: Mark Salter (msalter@redhat.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#ifndef _ASM_C6X_MODULE_H
14#define _ASM_C6X_MODULE_H
15
16#define Elf_Shdr Elf32_Shdr
17#define Elf_Sym Elf32_Sym
18#define Elf_Ehdr Elf32_Ehdr
19#define Elf_Addr Elf32_Addr
20#define Elf_Word Elf32_Word
21
22/*
23 * This file contains the C6x architecture specific module code.
24 */
25struct mod_arch_specific {
26};
27
28struct loaded_sections {
29 unsigned int new_vaddr;
30 unsigned int loaded;
31};
32
33#endif /* _ASM_C6X_MODULE_H */
diff --git a/arch/c6x/include/asm/mutex.h b/arch/c6x/include/asm/mutex.h
new file mode 100644
index 000000000000..7a7248e0462d
--- /dev/null
+++ b/arch/c6x/include/asm/mutex.h
@@ -0,0 +1,6 @@
1#ifndef _ASM_C6X_MUTEX_H
2#define _ASM_C6X_MUTEX_H
3
4#include <asm-generic/mutex-null.h>
5
6#endif /* _ASM_C6X_MUTEX_H */
diff --git a/arch/c6x/include/asm/page.h b/arch/c6x/include/asm/page.h
new file mode 100644
index 000000000000..d18e2b0c7aea
--- /dev/null
+++ b/arch/c6x/include/asm/page.h
@@ -0,0 +1,11 @@
1#ifndef _ASM_C6X_PAGE_H
2#define _ASM_C6X_PAGE_H
3
4#define VM_DATA_DEFAULT_FLAGS \
5 (VM_READ | VM_WRITE | \
6 ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
7 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
8
9#include <asm-generic/page.h>
10
11#endif /* _ASM_C6X_PAGE_H */
diff --git a/arch/c6x/include/asm/pgtable.h b/arch/c6x/include/asm/pgtable.h
new file mode 100644
index 000000000000..68c8af4f1f97
--- /dev/null
+++ b/arch/c6x/include/asm/pgtable.h
@@ -0,0 +1,81 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_PGTABLE_H
12#define _ASM_C6X_PGTABLE_H
13
14#include <asm-generic/4level-fixup.h>
15
16#include <asm/setup.h>
17#include <asm/page.h>
18
19/*
20 * All 32bit addresses are effectively valid for vmalloc...
21 * Sort of meaningless for non-VM targets.
22 */
23#define VMALLOC_START 0
24#define VMALLOC_END 0xffffffff
25
26#define pgd_present(pgd) (1)
27#define pgd_none(pgd) (0)
28#define pgd_bad(pgd) (0)
29#define pgd_clear(pgdp)
30#define kern_addr_valid(addr) (1)
31
32#define pmd_offset(a, b) ((void *)0)
33#define pmd_none(x) (!pmd_val(x))
34#define pmd_present(x) (pmd_val(x))
35#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
36#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK)
37
38#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */
39#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */
40#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */
41#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */
42#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */
43#define pgprot_noncached(prot) (prot)
44
45extern void paging_init(void);
46
47#define __swp_type(x) (0)
48#define __swp_offset(x) (0)
49#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) })
50#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
51#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
52
53static inline int pte_file(pte_t pte)
54{
55 return 0;
56}
57
58#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
59#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
60
61/*
62 * ZERO_PAGE is a global shared page that is always zero: used
63 * for zero-mapped memory areas etc..
64 */
65#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
66extern unsigned long empty_zero_page;
67
68#define swapper_pg_dir ((pgd_t *) 0)
69
70/*
71 * No page table caches to initialise
72 */
73#define pgtable_cache_init() do { } while (0)
74#define io_remap_pfn_range remap_pfn_range
75
76#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
77 remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
78
79#include <asm-generic/pgtable.h>
80
81#endif /* _ASM_C6X_PGTABLE_H */
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
new file mode 100644
index 000000000000..8154c4ee8c9c
--- /dev/null
+++ b/arch/c6x/include/asm/processor.h
@@ -0,0 +1,132 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Updated for 2.6.34: Mark Salter <msalter@redhat.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#ifndef _ASM_C6X_PROCESSOR_H
14#define _ASM_C6X_PROCESSOR_H
15
16#include <asm/ptrace.h>
17#include <asm/page.h>
18#include <asm/current.h>
19
20/*
21 * Default implementation of macro that returns current
22 * instruction pointer ("program counter").
23 */
24#define current_text_addr() \
25({ \
26 void *__pc; \
27 asm("mvc .S2 pce1,%0\n" : "=b"(__pc)); \
28 __pc; \
29})
30
31/*
32 * User space process size. This is mostly meaningless for NOMMU
33 * but some C6X processors may have RAM addresses up to 0xFFFFFFFF.
34 * Since calls like mmap() can return an address or an error, we
35 * have to allow room for error returns when code does something
36 * like:
37 *
38 * addr = do_mmap(...)
39 * if ((unsigned long)addr >= TASK_SIZE)
40 * ... its an error code, not an address ...
41 *
42 * Here, we allow for 4096 error codes which means we really can't
43 * use the last 4K page on systems with RAM extending all the way
44 * to the end of the 32-bit address space.
45 */
46#define TASK_SIZE 0xFFFFF000
47
48/*
49 * This decides where the kernel will search for a free chunk of vm
50 * space during mmap's. We won't be using it
51 */
52#define TASK_UNMAPPED_BASE 0
53
54struct thread_struct {
55 unsigned long long b15_14;
56 unsigned long long a15_14;
57 unsigned long long b13_12;
58 unsigned long long a13_12;
59 unsigned long long b11_10;
60 unsigned long long a11_10;
61 unsigned long long ricl_icl;
62 unsigned long usp; /* user stack pointer */
63 unsigned long pc; /* kernel pc */
64 unsigned long wchan;
65};
66
67#define INIT_THREAD \
68{ \
69 .usp = 0, \
70 .wchan = 0, \
71}
72
73#define INIT_MMAP { \
74 &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, \
75 NULL, NULL }
76
77#define task_pt_regs(task) \
78 ((struct pt_regs *)(THREAD_START_SP + task_stack_page(task)) - 1)
79
80#define alloc_kernel_stack() __get_free_page(GFP_KERNEL)
81#define free_kernel_stack(page) free_page((page))
82
83
84/* Forward declaration, a strange C thing */
85struct task_struct;
86
87extern void start_thread(struct pt_regs *regs, unsigned int pc,
88 unsigned long usp);
89
90/* Free all resources held by a thread. */
91static inline void release_thread(struct task_struct *dead_task)
92{
93}
94
95/* Prepare to copy thread state - unlazy all lazy status */
96#define prepare_to_copy(tsk) do { } while (0)
97
98extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
99
100#define copy_segments(tsk, mm) do { } while (0)
101#define release_segments(mm) do { } while (0)
102
103/*
104 * saved PC of a blocked thread.
105 */
106#define thread_saved_pc(tsk) (task_pt_regs(tsk)->pc)
107
108/*
109 * saved kernel SP and DP of a blocked thread.
110 */
111#ifdef _BIG_ENDIAN
112#define thread_saved_ksp(tsk) \
113 (*(unsigned long *)&(tsk)->thread.b15_14)
114#define thread_saved_dp(tsk) \
115 (*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
116#else
117#define thread_saved_ksp(tsk) \
118 (*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
119#define thread_saved_dp(tsk) \
120 (*(unsigned long *)&(tsk)->thread.b15_14)
121#endif
122
123extern unsigned long get_wchan(struct task_struct *p);
124
125#define KSTK_EIP(tsk) (task_pt_regs(task)->pc)
126#define KSTK_ESP(tsk) (task_pt_regs(task)->sp)
127
128#define cpu_relax() do { } while (0)
129
130extern const struct seq_operations cpuinfo_op;
131
132#endif /* ASM_C6X_PROCESSOR_H */
diff --git a/arch/c6x/include/asm/procinfo.h b/arch/c6x/include/asm/procinfo.h
new file mode 100644
index 000000000000..c139d1e71f87
--- /dev/null
+++ b/arch/c6x/include/asm/procinfo.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) 2010 Texas Instruments Incorporated
3 * Author: Mark Salter (msalter@redhat.com)
4 *
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#ifndef _ASM_C6X_PROCINFO_H
11#define _ASM_C6X_PROCINFO_H
12
13#ifdef __KERNEL__
14
15struct proc_info_list {
16 unsigned int cpu_val;
17 unsigned int cpu_mask;
18 const char *arch_name;
19 const char *elf_name;
20 unsigned int elf_hwcap;
21};
22
23#else /* __KERNEL__ */
24#include <asm/elf.h>
25#warning "Please include asm/elf.h instead"
26#endif /* __KERNEL__ */
27
28#endif /* _ASM_C6X_PROCINFO_H */
diff --git a/arch/c6x/include/asm/prom.h b/arch/c6x/include/asm/prom.h
new file mode 100644
index 000000000000..b4ec95f07518
--- /dev/null
+++ b/arch/c6x/include/asm/prom.h
@@ -0,0 +1 @@
/* dummy prom.h; here to make linux/of.h's #includes happy */
diff --git a/arch/c6x/include/asm/ptrace.h b/arch/c6x/include/asm/ptrace.h
new file mode 100644
index 000000000000..21e8d7931fe7
--- /dev/null
+++ b/arch/c6x/include/asm/ptrace.h
@@ -0,0 +1,174 @@
1/*
2 * Copyright (C) 2004, 2006, 2009, 2010 Texas Instruments Incorporated
3 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
4 *
5 * Updated for 2.6.34: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_PTRACE_H
12#define _ASM_C6X_PTRACE_H
13
14#define BKPT_OPCODE 0x56454314 /* illegal opcode */
15
16#ifdef _BIG_ENDIAN
17#define PT_LO(odd, even) odd
18#define PT_HI(odd, even) even
19#else
20#define PT_LO(odd, even) even
21#define PT_HI(odd, even) odd
22#endif
23
24#define PT_A4_ORG PT_LO(1, 0)
25#define PT_TSR PT_HI(1, 0)
26#define PT_ILC PT_LO(3, 2)
27#define PT_RILC PT_HI(3, 2)
28#define PT_CSR PT_LO(5, 4)
29#define PT_PC PT_HI(5, 4)
30#define PT_B16 PT_LO(7, 6)
31#define PT_B17 PT_HI(7, 6)
32#define PT_B18 PT_LO(9, 8)
33#define PT_B19 PT_HI(9, 8)
34#define PT_B20 PT_LO(11, 10)
35#define PT_B21 PT_HI(11, 10)
36#define PT_B22 PT_LO(13, 12)
37#define PT_B23 PT_HI(13, 12)
38#define PT_B24 PT_LO(15, 14)
39#define PT_B25 PT_HI(15, 14)
40#define PT_B26 PT_LO(17, 16)
41#define PT_B27 PT_HI(17, 16)
42#define PT_B28 PT_LO(19, 18)
43#define PT_B29 PT_HI(19, 18)
44#define PT_B30 PT_LO(21, 20)
45#define PT_B31 PT_HI(21, 20)
46#define PT_B0 PT_LO(23, 22)
47#define PT_B1 PT_HI(23, 22)
48#define PT_B2 PT_LO(25, 24)
49#define PT_B3 PT_HI(25, 24)
50#define PT_B4 PT_LO(27, 26)
51#define PT_B5 PT_HI(27, 26)
52#define PT_B6 PT_LO(29, 28)
53#define PT_B7 PT_HI(29, 28)
54#define PT_B8 PT_LO(31, 30)
55#define PT_B9 PT_HI(31, 30)
56#define PT_B10 PT_LO(33, 32)
57#define PT_B11 PT_HI(33, 32)
58#define PT_B12 PT_LO(35, 34)
59#define PT_B13 PT_HI(35, 34)
60#define PT_A16 PT_LO(37, 36)
61#define PT_A17 PT_HI(37, 36)
62#define PT_A18 PT_LO(39, 38)
63#define PT_A19 PT_HI(39, 38)
64#define PT_A20 PT_LO(41, 40)
65#define PT_A21 PT_HI(41, 40)
66#define PT_A22 PT_LO(43, 42)
67#define PT_A23 PT_HI(43, 42)
68#define PT_A24 PT_LO(45, 44)
69#define PT_A25 PT_HI(45, 44)
70#define PT_A26 PT_LO(47, 46)
71#define PT_A27 PT_HI(47, 46)
72#define PT_A28 PT_LO(49, 48)
73#define PT_A29 PT_HI(49, 48)
74#define PT_A30 PT_LO(51, 50)
75#define PT_A31 PT_HI(51, 50)
76#define PT_A0 PT_LO(53, 52)
77#define PT_A1 PT_HI(53, 52)
78#define PT_A2 PT_LO(55, 54)
79#define PT_A3 PT_HI(55, 54)
80#define PT_A4 PT_LO(57, 56)
81#define PT_A5 PT_HI(57, 56)
82#define PT_A6 PT_LO(59, 58)
83#define PT_A7 PT_HI(59, 58)
84#define PT_A8 PT_LO(61, 60)
85#define PT_A9 PT_HI(61, 60)
86#define PT_A10 PT_LO(63, 62)
87#define PT_A11 PT_HI(63, 62)
88#define PT_A12 PT_LO(65, 64)
89#define PT_A13 PT_HI(65, 64)
90#define PT_A14 PT_LO(67, 66)
91#define PT_A15 PT_HI(67, 66)
92#define PT_B14 PT_LO(69, 68)
93#define PT_B15 PT_HI(69, 68)
94
95#define NR_PTREGS 70
96
97#define PT_DP PT_B14 /* Data Segment Pointer (B14) */
98#define PT_SP PT_B15 /* Stack Pointer (B15) */
99
100#ifndef __ASSEMBLY__
101
102#ifdef _BIG_ENDIAN
103#define REG_PAIR(odd, even) unsigned long odd; unsigned long even
104#else
105#define REG_PAIR(odd, even) unsigned long even; unsigned long odd
106#endif
107
108/*
109 * this struct defines the way the registers are stored on the
110 * stack during a system call. fields defined with REG_PAIR
111 * are saved and restored using double-word memory operations
112 * which means the word ordering of the pair depends on endianess.
113 */
114struct pt_regs {
115 REG_PAIR(tsr, orig_a4);
116 REG_PAIR(rilc, ilc);
117 REG_PAIR(pc, csr);
118
119 REG_PAIR(b17, b16);
120 REG_PAIR(b19, b18);
121 REG_PAIR(b21, b20);
122 REG_PAIR(b23, b22);
123 REG_PAIR(b25, b24);
124 REG_PAIR(b27, b26);
125 REG_PAIR(b29, b28);
126 REG_PAIR(b31, b30);
127
128 REG_PAIR(b1, b0);
129 REG_PAIR(b3, b2);
130 REG_PAIR(b5, b4);
131 REG_PAIR(b7, b6);
132 REG_PAIR(b9, b8);
133 REG_PAIR(b11, b10);
134 REG_PAIR(b13, b12);
135
136 REG_PAIR(a17, a16);
137 REG_PAIR(a19, a18);
138 REG_PAIR(a21, a20);
139 REG_PAIR(a23, a22);
140 REG_PAIR(a25, a24);
141 REG_PAIR(a27, a26);
142 REG_PAIR(a29, a28);
143 REG_PAIR(a31, a30);
144
145 REG_PAIR(a1, a0);
146 REG_PAIR(a3, a2);
147 REG_PAIR(a5, a4);
148 REG_PAIR(a7, a6);
149 REG_PAIR(a9, a8);
150 REG_PAIR(a11, a10);
151 REG_PAIR(a13, a12);
152
153 REG_PAIR(a15, a14);
154 REG_PAIR(sp, dp);
155};
156
157#ifdef __KERNEL__
158
159#include <linux/linkage.h>
160
161#define user_mode(regs) ((((regs)->tsr) & 0x40) != 0)
162
163#define instruction_pointer(regs) ((regs)->pc)
164#define profile_pc(regs) instruction_pointer(regs)
165#define user_stack_pointer(regs) ((regs)->sp)
166
167extern void show_regs(struct pt_regs *);
168
169extern asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs);
170extern asmlinkage void syscall_trace_exit(struct pt_regs *regs);
171
172#endif /* __KERNEL__ */
173#endif /* __ASSEMBLY__ */
174#endif /* _ASM_C6X_PTRACE_H */
diff --git a/arch/c6x/include/asm/sections.h b/arch/c6x/include/asm/sections.h
new file mode 100644
index 000000000000..f703989d837a
--- /dev/null
+++ b/arch/c6x/include/asm/sections.h
@@ -0,0 +1,12 @@
1#ifndef _ASM_C6X_SECTIONS_H
2#define _ASM_C6X_SECTIONS_H
3
4#include <asm-generic/sections.h>
5
6extern char _vectors_start[];
7extern char _vectors_end[];
8
9extern char _data_lma[];
10extern char _fdt_start[], _fdt_end[];
11
12#endif /* _ASM_C6X_SECTIONS_H */
diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h
new file mode 100644
index 000000000000..1808f279f82e
--- /dev/null
+++ b/arch/c6x/include/asm/setup.h
@@ -0,0 +1,32 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_SETUP_H
12#define _ASM_C6X_SETUP_H
13
14#define COMMAND_LINE_SIZE 1024
15
16#ifndef __ASSEMBLY__
17extern char c6x_command_line[COMMAND_LINE_SIZE];
18
19extern int c6x_add_memory(phys_addr_t start, unsigned long size);
20
21extern unsigned long ram_start;
22extern unsigned long ram_end;
23
24extern int c6x_num_cores;
25extern unsigned int c6x_silicon_rev;
26extern unsigned int c6x_devstat;
27extern unsigned char c6x_fuse_mac[6];
28
29extern void machine_init(unsigned long dt_ptr);
30
31#endif /* !__ASSEMBLY__ */
32#endif /* _ASM_C6X_SETUP_H */
diff --git a/arch/c6x/include/asm/sigcontext.h b/arch/c6x/include/asm/sigcontext.h
new file mode 100644
index 000000000000..eb702f39cde7
--- /dev/null
+++ b/arch/c6x/include/asm/sigcontext.h
@@ -0,0 +1,80 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_SIGCONTEXT_H
12#define _ASM_C6X_SIGCONTEXT_H
13
14
15struct sigcontext {
16 unsigned long sc_mask; /* old sigmask */
17 unsigned long sc_sp; /* old user stack pointer */
18
19 unsigned long sc_a4;
20 unsigned long sc_b4;
21 unsigned long sc_a6;
22 unsigned long sc_b6;
23 unsigned long sc_a8;
24 unsigned long sc_b8;
25
26 unsigned long sc_a0;
27 unsigned long sc_a1;
28 unsigned long sc_a2;
29 unsigned long sc_a3;
30 unsigned long sc_a5;
31 unsigned long sc_a7;
32 unsigned long sc_a9;
33
34 unsigned long sc_b0;
35 unsigned long sc_b1;
36 unsigned long sc_b2;
37 unsigned long sc_b3;
38 unsigned long sc_b5;
39 unsigned long sc_b7;
40 unsigned long sc_b9;
41
42 unsigned long sc_a16;
43 unsigned long sc_a17;
44 unsigned long sc_a18;
45 unsigned long sc_a19;
46 unsigned long sc_a20;
47 unsigned long sc_a21;
48 unsigned long sc_a22;
49 unsigned long sc_a23;
50 unsigned long sc_a24;
51 unsigned long sc_a25;
52 unsigned long sc_a26;
53 unsigned long sc_a27;
54 unsigned long sc_a28;
55 unsigned long sc_a29;
56 unsigned long sc_a30;
57 unsigned long sc_a31;
58
59 unsigned long sc_b16;
60 unsigned long sc_b17;
61 unsigned long sc_b18;
62 unsigned long sc_b19;
63 unsigned long sc_b20;
64 unsigned long sc_b21;
65 unsigned long sc_b22;
66 unsigned long sc_b23;
67 unsigned long sc_b24;
68 unsigned long sc_b25;
69 unsigned long sc_b26;
70 unsigned long sc_b27;
71 unsigned long sc_b28;
72 unsigned long sc_b29;
73 unsigned long sc_b30;
74 unsigned long sc_b31;
75
76 unsigned long sc_csr;
77 unsigned long sc_pc;
78};
79
80#endif /* _ASM_C6X_SIGCONTEXT_H */
diff --git a/arch/c6x/include/asm/signal.h b/arch/c6x/include/asm/signal.h
new file mode 100644
index 000000000000..f1cd870596a3
--- /dev/null
+++ b/arch/c6x/include/asm/signal.h
@@ -0,0 +1,17 @@
1#ifndef _ASM_C6X_SIGNAL_H
2#define _ASM_C6X_SIGNAL_H
3
4#include <asm-generic/signal.h>
5
6#ifndef __ASSEMBLY__
7#include <linux/linkage.h>
8
9struct pt_regs;
10
11extern asmlinkage int do_rt_sigreturn(struct pt_regs *regs);
12extern asmlinkage void do_notify_resume(struct pt_regs *regs,
13 u32 thread_info_flags,
14 int syscall);
15#endif
16
17#endif /* _ASM_C6X_SIGNAL_H */
diff --git a/arch/c6x/include/asm/soc.h b/arch/c6x/include/asm/soc.h
new file mode 100644
index 000000000000..43f50159e59b
--- /dev/null
+++ b/arch/c6x/include/asm/soc.h
@@ -0,0 +1,35 @@
1/*
2 * Miscellaneous SoC-specific hooks.
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 *
6 * Author: Mark Salter <msalter@redhat.com>
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12#ifndef _ASM_C6X_SOC_H
13#define _ASM_C6X_SOC_H
14
15struct soc_ops {
16 /* Return active exception event or -1 if none */
17 int (*get_exception)(void);
18
19 /* Assert an event */
20 void (*assert_event)(unsigned int evt);
21};
22
23extern struct soc_ops soc_ops;
24
25extern int soc_get_exception(void);
26extern void soc_assert_event(unsigned int event);
27extern int soc_mac_addr(unsigned int index, u8 *addr);
28
29/*
30 * for mmio on SoC devices. regs are always same byte order as cpu.
31 */
32#define soc_readl(addr) __raw_readl(addr)
33#define soc_writel(b, addr) __raw_writel((b), (addr))
34
35#endif /* _ASM_C6X_SOC_H */
diff --git a/arch/c6x/include/asm/string.h b/arch/c6x/include/asm/string.h
new file mode 100644
index 000000000000..b21517c80a17
--- /dev/null
+++ b/arch/c6x/include/asm/string.h
@@ -0,0 +1,21 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_STRING_H
12#define _ASM_C6X_STRING_H
13
14#include <asm/page.h>
15#include <linux/linkage.h>
16
17asmlinkage extern void *memcpy(void *to, const void *from, size_t n);
18
19#define __HAVE_ARCH_MEMCPY
20
21#endif /* _ASM_C6X_STRING_H */
diff --git a/arch/c6x/include/asm/swab.h b/arch/c6x/include/asm/swab.h
new file mode 100644
index 000000000000..fd4bb0520e5e
--- /dev/null
+++ b/arch/c6x/include/asm/swab.h
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#ifndef _ASM_C6X_SWAB_H
10#define _ASM_C6X_SWAB_H
11
12static inline __attribute_const__ __u16 __c6x_swab16(__u16 val)
13{
14 asm("swap4 .l1 %0,%0\n" : "+a"(val));
15 return val;
16}
17
18static inline __attribute_const__ __u32 __c6x_swab32(__u32 val)
19{
20 asm("swap4 .l1 %0,%0\n"
21 "swap2 .l1 %0,%0\n"
22 : "+a"(val));
23 return val;
24}
25
26static inline __attribute_const__ __u64 __c6x_swab64(__u64 val)
27{
28 asm(" swap2 .s1 %p0,%P0\n"
29 "|| swap2 .l1 %P0,%p0\n"
30 " swap4 .l1 %p0,%p0\n"
31 " swap4 .l1 %P0,%P0\n"
32 : "+a"(val));
33 return val;
34}
35
36static inline __attribute_const__ __u32 __c6x_swahw32(__u32 val)
37{
38 asm("swap2 .l1 %0,%0\n" : "+a"(val));
39 return val;
40}
41
42static inline __attribute_const__ __u32 __c6x_swahb32(__u32 val)
43{
44 asm("swap4 .l1 %0,%0\n" : "+a"(val));
45 return val;
46}
47
48#define __arch_swab16 __c6x_swab16
49#define __arch_swab32 __c6x_swab32
50#define __arch_swab64 __c6x_swab64
51#define __arch_swahw32 __c6x_swahw32
52#define __arch_swahb32 __c6x_swahb32
53
54#endif /* _ASM_C6X_SWAB_H */
diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h
new file mode 100644
index 000000000000..ae2be315ee9c
--- /dev/null
+++ b/arch/c6x/include/asm/syscall.h
@@ -0,0 +1,123 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#ifndef __ASM_C6X_SYSCALL_H
12#define __ASM_C6X_SYSCALL_H
13
14#include <linux/err.h>
15#include <linux/sched.h>
16
17static inline int syscall_get_nr(struct task_struct *task,
18 struct pt_regs *regs)
19{
20 return regs->b0;
21}
22
23static inline void syscall_rollback(struct task_struct *task,
24 struct pt_regs *regs)
25{
26 /* do nothing */
27}
28
29static inline long syscall_get_error(struct task_struct *task,
30 struct pt_regs *regs)
31{
32 return IS_ERR_VALUE(regs->a4) ? regs->a4 : 0;
33}
34
35static inline long syscall_get_return_value(struct task_struct *task,
36 struct pt_regs *regs)
37{
38 return regs->a4;
39}
40
41static inline void syscall_set_return_value(struct task_struct *task,
42 struct pt_regs *regs,
43 int error, long val)
44{
45 regs->a4 = error ?: val;
46}
47
48static inline void syscall_get_arguments(struct task_struct *task,
49 struct pt_regs *regs, unsigned int i,
50 unsigned int n, unsigned long *args)
51{
52 switch (i) {
53 case 0:
54 if (!n--)
55 break;
56 *args++ = regs->a4;
57 case 1:
58 if (!n--)
59 break;
60 *args++ = regs->b4;
61 case 2:
62 if (!n--)
63 break;
64 *args++ = regs->a6;
65 case 3:
66 if (!n--)
67 break;
68 *args++ = regs->b6;
69 case 4:
70 if (!n--)
71 break;
72 *args++ = regs->a8;
73 case 5:
74 if (!n--)
75 break;
76 *args++ = regs->b8;
77 case 6:
78 if (!n--)
79 break;
80 default:
81 BUG();
82 }
83}
84
85static inline void syscall_set_arguments(struct task_struct *task,
86 struct pt_regs *regs,
87 unsigned int i, unsigned int n,
88 const unsigned long *args)
89{
90 switch (i) {
91 case 0:
92 if (!n--)
93 break;
94 regs->a4 = *args++;
95 case 1:
96 if (!n--)
97 break;
98 regs->b4 = *args++;
99 case 2:
100 if (!n--)
101 break;
102 regs->a6 = *args++;
103 case 3:
104 if (!n--)
105 break;
106 regs->b6 = *args++;
107 case 4:
108 if (!n--)
109 break;
110 regs->a8 = *args++;
111 case 5:
112 if (!n--)
113 break;
114 regs->a9 = *args++;
115 case 6:
116 if (!n)
117 break;
118 default:
119 BUG();
120 }
121}
122
123#endif /* __ASM_C6X_SYSCALLS_H */
diff --git a/arch/c6x/include/asm/syscalls.h b/arch/c6x/include/asm/syscalls.h
new file mode 100644
index 000000000000..aed53da703c9
--- /dev/null
+++ b/arch/c6x/include/asm/syscalls.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation, version 2.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12 * NON INFRINGEMENT. See the GNU General Public License for
13 * more details.
14 */
15
16#ifndef __ASM_C6X_SYSCALLS_H
17#define __ASM_C6X_SYSCALLS_H
18
19#include <linux/compiler.h>
20#include <linux/linkage.h>
21#include <linux/types.h>
22
23/* The array of function pointers for syscalls. */
24extern void *sys_call_table[];
25
26/* The following are trampolines in entry.S to handle 64-bit arguments */
27extern long sys_pread_c6x(unsigned int fd, char __user *buf,
28 size_t count, off_t pos_low, off_t pos_high);
29extern long sys_pwrite_c6x(unsigned int fd, const char __user *buf,
30 size_t count, off_t pos_low, off_t pos_high);
31extern long sys_truncate64_c6x(const char __user *path,
32 off_t length_low, off_t length_high);
33extern long sys_ftruncate64_c6x(unsigned int fd,
34 off_t length_low, off_t length_high);
35extern long sys_fadvise64_c6x(int fd, u32 offset_lo, u32 offset_hi,
36 u32 len, int advice);
37extern long sys_fadvise64_64_c6x(int fd, u32 offset_lo, u32 offset_hi,
38 u32 len_lo, u32 len_hi, int advice);
39extern long sys_fallocate_c6x(int fd, int mode,
40 u32 offset_lo, u32 offset_hi,
41 u32 len_lo, u32 len_hi);
42extern int sys_cache_sync(unsigned long s, unsigned long e);
43
44struct pt_regs;
45
46extern asmlinkage long sys_c6x_clone(struct pt_regs *regs);
47extern asmlinkage long sys_c6x_execve(const char __user *name,
48 const char __user *const __user *argv,
49 const char __user *const __user *envp,
50 struct pt_regs *regs);
51
52
53#include <asm-generic/syscalls.h>
54
55#endif /* __ASM_C6X_SYSCALLS_H */
diff --git a/arch/c6x/include/asm/system.h b/arch/c6x/include/asm/system.h
new file mode 100644
index 000000000000..e076dc0eacc8
--- /dev/null
+++ b/arch/c6x/include/asm/system.h
@@ -0,0 +1,168 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_SYSTEM_H
12#define _ASM_C6X_SYSTEM_H
13
14#include <linux/linkage.h>
15#include <linux/irqflags.h>
16
17#define prepare_to_switch() do { } while (0)
18
19struct task_struct;
20struct thread_struct;
21asmlinkage void *__switch_to(struct thread_struct *prev,
22 struct thread_struct *next,
23 struct task_struct *tsk);
24
25#define switch_to(prev, next, last) \
26 do { \
27 current->thread.wchan = (u_long) __builtin_return_address(0); \
28 (last) = __switch_to(&(prev)->thread, \
29 &(next)->thread, (prev)); \
30 mb(); \
31 current->thread.wchan = 0; \
32 } while (0)
33
34/* Reset the board */
35#define HARD_RESET_NOW()
36
37#define get_creg(reg) \
38 ({ unsigned int __x; \
39 asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; })
40
41#define set_creg(reg, v) \
42 do { unsigned int __x = (unsigned int)(v); \
43 asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \
44 } while (0)
45
46#define or_creg(reg, n) \
47 do { unsigned __x, __n = (unsigned)(n); \
48 asm volatile ("mvc .s2 " #reg ",%0\n" \
49 "or .l2 %1,%0,%0\n" \
50 "mvc .s2 %0," #reg "\n" \
51 "nop\n" \
52 : "=&b"(__x) : "b"(__n)); \
53 } while (0)
54
55#define and_creg(reg, n) \
56 do { unsigned __x, __n = (unsigned)(n); \
57 asm volatile ("mvc .s2 " #reg ",%0\n" \
58 "and .l2 %1,%0,%0\n" \
59 "mvc .s2 %0," #reg "\n" \
60 "nop\n" \
61 : "=&b"(__x) : "b"(__n)); \
62 } while (0)
63
64#define get_coreid() (get_creg(DNUM) & 0xff)
65
66/* Set/get IST */
67#define set_ist(x) set_creg(ISTP, x)
68#define get_ist() get_creg(ISTP)
69
70/*
71 * Exception management
72 */
73asmlinkage void enable_exception(void);
74#define disable_exception()
75#define get_except_type() get_creg(EFR)
76#define ack_exception(type) set_creg(ECR, 1 << (type))
77#define get_iexcept() get_creg(IERR)
78#define set_iexcept(mask) set_creg(IERR, (mask))
79
80/*
81 * Misc. functions
82 */
83#define nop() asm("NOP\n");
84#define mb() barrier()
85#define rmb() barrier()
86#define wmb() barrier()
87#define set_mb(var, value) do { var = value; mb(); } while (0)
88#define set_wmb(var, value) do { var = value; wmb(); } while (0)
89
90#define smp_mb() barrier()
91#define smp_rmb() barrier()
92#define smp_wmb() barrier()
93#define smp_read_barrier_depends() do { } while (0)
94
95#define xchg(ptr, x) \
96 ((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
97 sizeof(*(ptr))))
98#define tas(ptr) xchg((ptr), 1)
99
100unsigned int _lmbd(unsigned int, unsigned int);
101unsigned int _bitr(unsigned int);
102
103struct __xchg_dummy { unsigned int a[100]; };
104#define __xg(x) ((volatile struct __xchg_dummy *)(x))
105
106static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
107{
108 unsigned int tmp;
109 unsigned long flags;
110
111 local_irq_save(flags);
112
113 switch (size) {
114 case 1:
115 tmp = 0;
116 tmp = *((unsigned char *) ptr);
117 *((unsigned char *) ptr) = (unsigned char) x;
118 break;
119 case 2:
120 tmp = 0;
121 tmp = *((unsigned short *) ptr);
122 *((unsigned short *) ptr) = x;
123 break;
124 case 4:
125 tmp = 0;
126 tmp = *((unsigned int *) ptr);
127 *((unsigned int *) ptr) = x;
128 break;
129 }
130 local_irq_restore(flags);
131 return tmp;
132}
133
134#include <asm-generic/cmpxchg-local.h>
135
136/*
137 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
138 * them available.
139 */
140#define cmpxchg_local(ptr, o, n) \
141 ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
142 (unsigned long)(o), \
143 (unsigned long)(n), \
144 sizeof(*(ptr))))
145#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
146
147#include <asm-generic/cmpxchg.h>
148
149#define _extu(x, s, e) \
150 ({ unsigned int __x; \
151 asm volatile ("extu .S2 %3,%1,%2,%0\n" : \
152 "=b"(__x) : "n"(s), "n"(e), "b"(x)); \
153 __x; })
154
155
156extern unsigned int c6x_core_freq;
157
158struct pt_regs;
159
160extern void die(char *str, struct pt_regs *fp, int nr);
161extern asmlinkage int process_exception(struct pt_regs *regs);
162extern void time_init(void);
163extern void free_initmem(void);
164
165extern void (*c6x_restart)(void);
166extern void (*c6x_halt)(void);
167
168#endif /* _ASM_C6X_SYSTEM_H */
diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h
new file mode 100644
index 000000000000..fd99148cda9d
--- /dev/null
+++ b/arch/c6x/include/asm/thread_info.h
@@ -0,0 +1,121 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Updated for 2.6.3x: Mark Salter <msalter@redhat.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#ifndef _ASM_C6X_THREAD_INFO_H
14#define _ASM_C6X_THREAD_INFO_H
15
16#ifdef __KERNEL__
17
18#include <asm/page.h>
19
20#ifdef CONFIG_4KSTACKS
21#define THREAD_SIZE 4096
22#define THREAD_SHIFT 12
23#define THREAD_ORDER 0
24#else
25#define THREAD_SIZE 8192
26#define THREAD_SHIFT 13
27#define THREAD_ORDER 1
28#endif
29
30#define THREAD_START_SP (THREAD_SIZE - 8)
31
32#ifndef __ASSEMBLY__
33
34typedef struct {
35 unsigned long seg;
36} mm_segment_t;
37
38/*
39 * low level task data.
40 */
41struct thread_info {
42 struct task_struct *task; /* main task structure */
43 struct exec_domain *exec_domain; /* execution domain */
44 unsigned long flags; /* low level flags */
45 int cpu; /* cpu we're on */
46 int preempt_count; /* 0 = preemptable, <0 = BUG */
47 mm_segment_t addr_limit; /* thread address space */
48 struct restart_block restart_block;
49};
50
51/*
52 * macros/functions for gaining access to the thread information structure
53 *
54 * preempt_count needs to be 1 initially, until the scheduler is functional.
55 */
56#define INIT_THREAD_INFO(tsk) \
57{ \
58 .task = &tsk, \
59 .exec_domain = &default_exec_domain, \
60 .flags = 0, \
61 .cpu = 0, \
62 .preempt_count = INIT_PREEMPT_COUNT, \
63 .addr_limit = KERNEL_DS, \
64 .restart_block = { \
65 .fn = do_no_restart_syscall, \
66 }, \
67}
68
69#define init_thread_info (init_thread_union.thread_info)
70#define init_stack (init_thread_union.stack)
71
72/* get the thread information struct of current task */
73static inline __attribute__((const))
74struct thread_info *current_thread_info(void)
75{
76 struct thread_info *ti;
77 asm volatile (" clr .s2 B15,0,%1,%0\n"
78 : "=b" (ti)
79 : "Iu5" (THREAD_SHIFT - 1));
80 return ti;
81}
82
83#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
84
85/* thread information allocation */
86#ifdef CONFIG_DEBUG_STACK_USAGE
87#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
88#else
89#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK)
90#endif
91
92#define alloc_thread_info_node(tsk, node) \
93 ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
94
95#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER)
96#define get_thread_info(ti) get_task_struct((ti)->task)
97#define put_thread_info(ti) put_task_struct((ti)->task)
98#endif /* __ASSEMBLY__ */
99
100#define PREEMPT_ACTIVE 0x10000000
101
102/*
103 * thread information flag bit numbers
104 * - pending work-to-be-done flags are in LSW
105 * - other flags in MSW
106 */
107#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
108#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
109#define TIF_SIGPENDING 2 /* signal pending */
110#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
111#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
112
113#define TIF_POLLING_NRFLAG 16 /* true if polling TIF_NEED_RESCHED */
114#define TIF_MEMDIE 17 /* OOM killer killed process */
115
116#define TIF_WORK_MASK 0x00007FFE /* work on irq/exception return */
117#define TIF_ALLWORK_MASK 0x00007FFF /* work on any return to u-space */
118
119#endif /* __KERNEL__ */
120
121#endif /* _ASM_C6X_THREAD_INFO_H */
diff --git a/arch/c6x/include/asm/timer64.h b/arch/c6x/include/asm/timer64.h
new file mode 100644
index 000000000000..bbe27bb9887e
--- /dev/null
+++ b/arch/c6x/include/asm/timer64.h
@@ -0,0 +1,6 @@
1#ifndef _C6X_TIMER64_H
2#define _C6X_TIMER64_H
3
4extern void __init timer64_init(void);
5
6#endif /* _C6X_TIMER64_H */
diff --git a/arch/c6x/include/asm/timex.h b/arch/c6x/include/asm/timex.h
new file mode 100644
index 000000000000..508c3ec971f9
--- /dev/null
+++ b/arch/c6x/include/asm/timex.h
@@ -0,0 +1,33 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Modified for 2.6.34: Mark Salter <msalter@redhat.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#ifndef _ASM_C6X_TIMEX_H
14#define _ASM_C6X_TIMEX_H
15
16#define CLOCK_TICK_RATE ((1000 * 1000000UL) / 6)
17
18/* 64-bit timestamp */
19typedef unsigned long long cycles_t;
20
21static inline cycles_t get_cycles(void)
22{
23 unsigned l, h;
24
25 asm volatile (" dint\n"
26 " mvc .s2 TSCL,%0\n"
27 " mvc .s2 TSCH,%1\n"
28 " rint\n"
29 : "=b"(l), "=b"(h));
30 return ((cycles_t)h << 32) | l;
31}
32
33#endif /* _ASM_C6X_TIMEX_H */
diff --git a/arch/c6x/include/asm/tlb.h b/arch/c6x/include/asm/tlb.h
new file mode 100644
index 000000000000..8709e5e29d2d
--- /dev/null
+++ b/arch/c6x/include/asm/tlb.h
@@ -0,0 +1,8 @@
1#ifndef _ASM_C6X_TLB_H
2#define _ASM_C6X_TLB_H
3
4#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
5
6#include <asm-generic/tlb.h>
7
8#endif /* _ASM_C6X_TLB_H */
diff --git a/arch/c6x/include/asm/traps.h b/arch/c6x/include/asm/traps.h
new file mode 100644
index 000000000000..62124d7b1b5f
--- /dev/null
+++ b/arch/c6x/include/asm/traps.h
@@ -0,0 +1,36 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _ASM_C6X_TRAPS_H
12#define _ASM_C6X_TRAPS_H
13
14#define EXCEPT_TYPE_NXF 31 /* NMI */
15#define EXCEPT_TYPE_EXC 30 /* external exception */
16#define EXCEPT_TYPE_IXF 1 /* internal exception */
17#define EXCEPT_TYPE_SXF 0 /* software exception */
18
19#define EXCEPT_CAUSE_LBX (1 << 7) /* loop buffer exception */
20#define EXCEPT_CAUSE_PRX (1 << 6) /* privilege exception */
21#define EXCEPT_CAUSE_RAX (1 << 5) /* resource access exception */
22#define EXCEPT_CAUSE_RCX (1 << 4) /* resource conflict exception */
23#define EXCEPT_CAUSE_OPX (1 << 3) /* opcode exception */
24#define EXCEPT_CAUSE_EPX (1 << 2) /* execute packet exception */
25#define EXCEPT_CAUSE_FPX (1 << 1) /* fetch packet exception */
26#define EXCEPT_CAUSE_IFX (1 << 0) /* instruction fetch exception */
27
28struct exception_info {
29 char *kernel_str;
30 int signo;
31 int code;
32};
33
34extern int (*c6x_nmi_handler)(struct pt_regs *regs);
35
36#endif /* _ASM_C6X_TRAPS_H */
diff --git a/arch/c6x/include/asm/uaccess.h b/arch/c6x/include/asm/uaccess.h
new file mode 100644
index 000000000000..453dd263bee3
--- /dev/null
+++ b/arch/c6x/include/asm/uaccess.h
@@ -0,0 +1,107 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#ifndef _ASM_C6X_UACCESS_H
10#define _ASM_C6X_UACCESS_H
11
12#include <linux/types.h>
13#include <linux/compiler.h>
14#include <linux/string.h>
15
16#ifdef CONFIG_ACCESS_CHECK
17#define __access_ok _access_ok
18#endif
19
20/*
21 * __copy_from_user/copy_to_user are based on ones in asm-generic/uaccess.h
22 *
23 * C6X supports unaligned 32 and 64 bit loads and stores.
24 */
25static inline __must_check long __copy_from_user(void *to,
26 const void __user *from, unsigned long n)
27{
28 u32 tmp32;
29 u64 tmp64;
30
31 if (__builtin_constant_p(n)) {
32 switch (n) {
33 case 1:
34 *(u8 *)to = *(u8 __force *)from;
35 return 0;
36 case 4:
37 asm volatile ("ldnw .d1t1 *%2,%0\n"
38 "nop 4\n"
39 "stnw .d1t1 %0,*%1\n"
40 : "=&a"(tmp32)
41 : "A"(to), "a"(from)
42 : "memory");
43 return 0;
44 case 8:
45 asm volatile ("ldndw .d1t1 *%2,%0\n"
46 "nop 4\n"
47 "stndw .d1t1 %0,*%1\n"
48 : "=&a"(tmp64)
49 : "a"(to), "a"(from)
50 : "memory");
51 return 0;
52 default:
53 break;
54 }
55 }
56
57 memcpy(to, (const void __force *)from, n);
58 return 0;
59}
60
61static inline __must_check long __copy_to_user(void __user *to,
62 const void *from, unsigned long n)
63{
64 u32 tmp32;
65 u64 tmp64;
66
67 if (__builtin_constant_p(n)) {
68 switch (n) {
69 case 1:
70 *(u8 __force *)to = *(u8 *)from;
71 return 0;
72 case 4:
73 asm volatile ("ldnw .d1t1 *%2,%0\n"
74 "nop 4\n"
75 "stnw .d1t1 %0,*%1\n"
76 : "=&a"(tmp32)
77 : "a"(to), "a"(from)
78 : "memory");
79 return 0;
80 case 8:
81 asm volatile ("ldndw .d1t1 *%2,%0\n"
82 "nop 4\n"
83 "stndw .d1t1 %0,*%1\n"
84 : "=&a"(tmp64)
85 : "a"(to), "a"(from)
86 : "memory");
87 return 0;
88 default:
89 break;
90 }
91 }
92
93 memcpy((void __force *)to, from, n);
94 return 0;
95}
96
97#define __copy_to_user __copy_to_user
98#define __copy_from_user __copy_from_user
99
100extern int _access_ok(unsigned long addr, unsigned long size);
101#ifdef CONFIG_ACCESS_CHECK
102#define __access_ok _access_ok
103#endif
104
105#include <asm-generic/uaccess.h>
106
107#endif /* _ASM_C6X_UACCESS_H */
diff --git a/arch/c6x/include/asm/unaligned.h b/arch/c6x/include/asm/unaligned.h
new file mode 100644
index 000000000000..b976cb740eaa
--- /dev/null
+++ b/arch/c6x/include/asm/unaligned.h
@@ -0,0 +1,170 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 * Rewritten for 2.6.3x: Mark Salter <msalter@redhat.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef _ASM_C6X_UNALIGNED_H
13#define _ASM_C6X_UNALIGNED_H
14
15#include <linux/swab.h>
16
17/*
18 * The C64x+ can do unaligned word and dword accesses in hardware
19 * using special load/store instructions.
20 */
21
22static inline u16 get_unaligned_le16(const void *p)
23{
24 const u8 *_p = p;
25 return _p[0] | _p[1] << 8;
26}
27
28static inline u16 get_unaligned_be16(const void *p)
29{
30 const u8 *_p = p;
31 return _p[0] << 8 | _p[1];
32}
33
34static inline void put_unaligned_le16(u16 val, void *p)
35{
36 u8 *_p = p;
37 _p[0] = val;
38 _p[1] = val >> 8;
39}
40
41static inline void put_unaligned_be16(u16 val, void *p)
42{
43 u8 *_p = p;
44 _p[0] = val >> 8;
45 _p[1] = val;
46}
47
48static inline u32 get_unaligned32(const void *p)
49{
50 u32 val = (u32) p;
51 asm (" ldnw .d1t1 *%0,%0\n"
52 " nop 4\n"
53 : "+a"(val));
54 return val;
55}
56
57static inline void put_unaligned32(u32 val, void *p)
58{
59 asm volatile (" stnw .d2t1 %0,*%1\n"
60 : : "a"(val), "b"(p) : "memory");
61}
62
63static inline u64 get_unaligned64(const void *p)
64{
65 u64 val;
66 asm volatile (" ldndw .d1t1 *%1,%0\n"
67 " nop 4\n"
68 : "=a"(val) : "a"(p));
69 return val;
70}
71
72static inline void put_unaligned64(u64 val, const void *p)
73{
74 asm volatile (" stndw .d2t1 %0,*%1\n"
75 : : "a"(val), "b"(p) : "memory");
76}
77
78#ifdef CONFIG_CPU_BIG_ENDIAN
79
80#define get_unaligned_le32(p) __swab32(get_unaligned32(p))
81#define get_unaligned_le64(p) __swab64(get_unaligned64(p))
82#define get_unaligned_be32(p) get_unaligned32(p)
83#define get_unaligned_be64(p) get_unaligned64(p)
84#define put_unaligned_le32(v, p) put_unaligned32(__swab32(v), (p))
85#define put_unaligned_le64(v, p) put_unaligned64(__swab64(v), (p))
86#define put_unaligned_be32(v, p) put_unaligned32((v), (p))
87#define put_unaligned_be64(v, p) put_unaligned64((v), (p))
88#define get_unaligned __get_unaligned_be
89#define put_unaligned __put_unaligned_be
90
91#else
92
93#define get_unaligned_le32(p) get_unaligned32(p)
94#define get_unaligned_le64(p) get_unaligned64(p)
95#define get_unaligned_be32(p) __swab32(get_unaligned32(p))
96#define get_unaligned_be64(p) __swab64(get_unaligned64(p))
97#define put_unaligned_le32(v, p) put_unaligned32((v), (p))
98#define put_unaligned_le64(v, p) put_unaligned64((v), (p))
99#define put_unaligned_be32(v, p) put_unaligned32(__swab32(v), (p))
100#define put_unaligned_be64(v, p) put_unaligned64(__swab64(v), (p))
101#define get_unaligned __get_unaligned_le
102#define put_unaligned __put_unaligned_le
103
104#endif
105
106/*
107 * Cause a link-time error if we try an unaligned access other than
108 * 1,2,4 or 8 bytes long
109 */
110extern int __bad_unaligned_access_size(void);
111
112#define __get_unaligned_le(ptr) (typeof(*(ptr)))({ \
113 sizeof(*(ptr)) == 1 ? *(ptr) : \
114 (sizeof(*(ptr)) == 2 ? get_unaligned_le16((ptr)) : \
115 (sizeof(*(ptr)) == 4 ? get_unaligned_le32((ptr)) : \
116 (sizeof(*(ptr)) == 8 ? get_unaligned_le64((ptr)) : \
117 __bad_unaligned_access_size()))); \
118 })
119
120#define __get_unaligned_be(ptr) (__force typeof(*(ptr)))({ \
121 sizeof(*(ptr)) == 1 ? *(ptr) : \
122 (sizeof(*(ptr)) == 2 ? get_unaligned_be16((ptr)) : \
123 (sizeof(*(ptr)) == 4 ? get_unaligned_be32((ptr)) : \
124 (sizeof(*(ptr)) == 8 ? get_unaligned_be64((ptr)) : \
125 __bad_unaligned_access_size()))); \
126 })
127
128#define __put_unaligned_le(val, ptr) ({ \
129 void *__gu_p = (ptr); \
130 switch (sizeof(*(ptr))) { \
131 case 1: \
132 *(u8 *)__gu_p = (__force u8)(val); \
133 break; \
134 case 2: \
135 put_unaligned_le16((__force u16)(val), __gu_p); \
136 break; \
137 case 4: \
138 put_unaligned_le32((__force u32)(val), __gu_p); \
139 break; \
140 case 8: \
141 put_unaligned_le64((__force u64)(val), __gu_p); \
142 break; \
143 default: \
144 __bad_unaligned_access_size(); \
145 break; \
146 } \
147 (void)0; })
148
149#define __put_unaligned_be(val, ptr) ({ \
150 void *__gu_p = (ptr); \
151 switch (sizeof(*(ptr))) { \
152 case 1: \
153 *(u8 *)__gu_p = (__force u8)(val); \
154 break; \
155 case 2: \
156 put_unaligned_be16((__force u16)(val), __gu_p); \
157 break; \
158 case 4: \
159 put_unaligned_be32((__force u32)(val), __gu_p); \
160 break; \
161 case 8: \
162 put_unaligned_be64((__force u64)(val), __gu_p); \
163 break; \
164 default: \
165 __bad_unaligned_access_size(); \
166 break; \
167 } \
168 (void)0; })
169
170#endif /* _ASM_C6X_UNALIGNED_H */
diff --git a/arch/c6x/include/asm/unistd.h b/arch/c6x/include/asm/unistd.h
new file mode 100644
index 000000000000..6d54ea4262eb
--- /dev/null
+++ b/arch/c6x/include/asm/unistd.h
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 *
4 * Based on arch/tile version.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation, version 2.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
13 * NON INFRINGEMENT. See the GNU General Public License for
14 * more details.
15 */
16#if !defined(_ASM_C6X_UNISTD_H) || defined(__SYSCALL)
17#define _ASM_C6X_UNISTD_H
18
19/* Use the standard ABI for syscalls. */
20#include <asm-generic/unistd.h>
21
22/* C6X-specific syscalls. */
23#define __NR_cache_sync (__NR_arch_specific_syscall + 0)
24__SYSCALL(__NR_cache_sync, sys_cache_sync)
25
26#endif /* _ASM_C6X_UNISTD_H */
diff --git a/arch/c6x/kernel/Makefile b/arch/c6x/kernel/Makefile
new file mode 100644
index 000000000000..580a515a9443
--- /dev/null
+++ b/arch/c6x/kernel/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for arch/c6x/kernel/
3#
4
5extra-y := head.o vmlinux.lds
6
7obj-y := process.o traps.o irq.o signal.o ptrace.o
8obj-y += setup.o sys_c6x.o time.o devicetree.o
9obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o
10obj-y += soc.o dma.o
11
12obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c
new file mode 100644
index 000000000000..759ad6d207b6
--- /dev/null
+++ b/arch/c6x/kernel/asm-offsets.c
@@ -0,0 +1,123 @@
1/*
2 * Generate definitions needed by assembly language modules.
3 * This code generates raw asm output which is post-processed
4 * to extract and format the required data.
5 */
6
7#include <linux/sched.h>
8#include <linux/thread_info.h>
9#include <asm/procinfo.h>
10#include <linux/kbuild.h>
11#include <linux/unistd.h>
12
13void foo(void)
14{
15 OFFSET(REGS_A16, pt_regs, a16);
16 OFFSET(REGS_A17, pt_regs, a17);
17 OFFSET(REGS_A18, pt_regs, a18);
18 OFFSET(REGS_A19, pt_regs, a19);
19 OFFSET(REGS_A20, pt_regs, a20);
20 OFFSET(REGS_A21, pt_regs, a21);
21 OFFSET(REGS_A22, pt_regs, a22);
22 OFFSET(REGS_A23, pt_regs, a23);
23 OFFSET(REGS_A24, pt_regs, a24);
24 OFFSET(REGS_A25, pt_regs, a25);
25 OFFSET(REGS_A26, pt_regs, a26);
26 OFFSET(REGS_A27, pt_regs, a27);
27 OFFSET(REGS_A28, pt_regs, a28);
28 OFFSET(REGS_A29, pt_regs, a29);
29 OFFSET(REGS_A30, pt_regs, a30);
30 OFFSET(REGS_A31, pt_regs, a31);
31
32 OFFSET(REGS_B16, pt_regs, b16);
33 OFFSET(REGS_B17, pt_regs, b17);
34 OFFSET(REGS_B18, pt_regs, b18);
35 OFFSET(REGS_B19, pt_regs, b19);
36 OFFSET(REGS_B20, pt_regs, b20);
37 OFFSET(REGS_B21, pt_regs, b21);
38 OFFSET(REGS_B22, pt_regs, b22);
39 OFFSET(REGS_B23, pt_regs, b23);
40 OFFSET(REGS_B24, pt_regs, b24);
41 OFFSET(REGS_B25, pt_regs, b25);
42 OFFSET(REGS_B26, pt_regs, b26);
43 OFFSET(REGS_B27, pt_regs, b27);
44 OFFSET(REGS_B28, pt_regs, b28);
45 OFFSET(REGS_B29, pt_regs, b29);
46 OFFSET(REGS_B30, pt_regs, b30);
47 OFFSET(REGS_B31, pt_regs, b31);
48
49 OFFSET(REGS_A0, pt_regs, a0);
50 OFFSET(REGS_A1, pt_regs, a1);
51 OFFSET(REGS_A2, pt_regs, a2);
52 OFFSET(REGS_A3, pt_regs, a3);
53 OFFSET(REGS_A4, pt_regs, a4);
54 OFFSET(REGS_A5, pt_regs, a5);
55 OFFSET(REGS_A6, pt_regs, a6);
56 OFFSET(REGS_A7, pt_regs, a7);
57 OFFSET(REGS_A8, pt_regs, a8);
58 OFFSET(REGS_A9, pt_regs, a9);
59 OFFSET(REGS_A10, pt_regs, a10);
60 OFFSET(REGS_A11, pt_regs, a11);
61 OFFSET(REGS_A12, pt_regs, a12);
62 OFFSET(REGS_A13, pt_regs, a13);
63 OFFSET(REGS_A14, pt_regs, a14);
64 OFFSET(REGS_A15, pt_regs, a15);
65
66 OFFSET(REGS_B0, pt_regs, b0);
67 OFFSET(REGS_B1, pt_regs, b1);
68 OFFSET(REGS_B2, pt_regs, b2);
69 OFFSET(REGS_B3, pt_regs, b3);
70 OFFSET(REGS_B4, pt_regs, b4);
71 OFFSET(REGS_B5, pt_regs, b5);
72 OFFSET(REGS_B6, pt_regs, b6);
73 OFFSET(REGS_B7, pt_regs, b7);
74 OFFSET(REGS_B8, pt_regs, b8);
75 OFFSET(REGS_B9, pt_regs, b9);
76 OFFSET(REGS_B10, pt_regs, b10);
77 OFFSET(REGS_B11, pt_regs, b11);
78 OFFSET(REGS_B12, pt_regs, b12);
79 OFFSET(REGS_B13, pt_regs, b13);
80 OFFSET(REGS_DP, pt_regs, dp);
81 OFFSET(REGS_SP, pt_regs, sp);
82
83 OFFSET(REGS_TSR, pt_regs, tsr);
84 OFFSET(REGS_ORIG_A4, pt_regs, orig_a4);
85
86 DEFINE(REGS__END, sizeof(struct pt_regs));
87 BLANK();
88
89 OFFSET(THREAD_PC, thread_struct, pc);
90 OFFSET(THREAD_B15_14, thread_struct, b15_14);
91 OFFSET(THREAD_A15_14, thread_struct, a15_14);
92 OFFSET(THREAD_B13_12, thread_struct, b13_12);
93 OFFSET(THREAD_A13_12, thread_struct, a13_12);
94 OFFSET(THREAD_B11_10, thread_struct, b11_10);
95 OFFSET(THREAD_A11_10, thread_struct, a11_10);
96 OFFSET(THREAD_RICL_ICL, thread_struct, ricl_icl);
97 BLANK();
98
99 OFFSET(TASK_STATE, task_struct, state);
100 BLANK();
101
102 OFFSET(THREAD_INFO_FLAGS, thread_info, flags);
103 OFFSET(THREAD_INFO_PREEMPT_COUNT, thread_info, preempt_count);
104 BLANK();
105
106 /* These would be unneccessary if we ran asm files
107 * through the preprocessor.
108 */
109 DEFINE(KTHREAD_SIZE, THREAD_SIZE);
110 DEFINE(KTHREAD_SHIFT, THREAD_SHIFT);
111 DEFINE(KTHREAD_START_SP, THREAD_START_SP);
112 DEFINE(ENOSYS_, ENOSYS);
113 DEFINE(NR_SYSCALLS_, __NR_syscalls);
114
115 DEFINE(_TIF_SYSCALL_TRACE, (1<<TIF_SYSCALL_TRACE));
116 DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
117 DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
118 DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
119 DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
120
121 DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
122 DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
123}
diff --git a/arch/c6x/kernel/c6x_ksyms.c b/arch/c6x/kernel/c6x_ksyms.c
new file mode 100644
index 000000000000..0ba3e0bba3e1
--- /dev/null
+++ b/arch/c6x/kernel/c6x_ksyms.c
@@ -0,0 +1,66 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/module.h>
13#include <asm/checksum.h>
14#include <linux/io.h>
15
16/*
17 * libgcc functions - used internally by the compiler...
18 */
19extern int __c6xabi_divi(int dividend, int divisor);
20EXPORT_SYMBOL(__c6xabi_divi);
21
22extern unsigned __c6xabi_divu(unsigned dividend, unsigned divisor);
23EXPORT_SYMBOL(__c6xabi_divu);
24
25extern int __c6xabi_remi(int dividend, int divisor);
26EXPORT_SYMBOL(__c6xabi_remi);
27
28extern unsigned __c6xabi_remu(unsigned dividend, unsigned divisor);
29EXPORT_SYMBOL(__c6xabi_remu);
30
31extern int __c6xabi_divremi(int dividend, int divisor);
32EXPORT_SYMBOL(__c6xabi_divremi);
33
34extern unsigned __c6xabi_divremu(unsigned dividend, unsigned divisor);
35EXPORT_SYMBOL(__c6xabi_divremu);
36
37extern unsigned long long __c6xabi_mpyll(unsigned long long src1,
38 unsigned long long src2);
39EXPORT_SYMBOL(__c6xabi_mpyll);
40
41extern long long __c6xabi_negll(long long src);
42EXPORT_SYMBOL(__c6xabi_negll);
43
44extern unsigned long long __c6xabi_llshl(unsigned long long src1, uint src2);
45EXPORT_SYMBOL(__c6xabi_llshl);
46
47extern long long __c6xabi_llshr(long long src1, uint src2);
48EXPORT_SYMBOL(__c6xabi_llshr);
49
50extern unsigned long long __c6xabi_llshru(unsigned long long src1, uint src2);
51EXPORT_SYMBOL(__c6xabi_llshru);
52
53extern void __c6xabi_strasgi(int *dst, const int *src, unsigned cnt);
54EXPORT_SYMBOL(__c6xabi_strasgi);
55
56extern void __c6xabi_push_rts(void);
57EXPORT_SYMBOL(__c6xabi_push_rts);
58
59extern void __c6xabi_pop_rts(void);
60EXPORT_SYMBOL(__c6xabi_pop_rts);
61
62extern void __c6xabi_strasgi_64plus(int *dst, const int *src, unsigned cnt);
63EXPORT_SYMBOL(__c6xabi_strasgi_64plus);
64
65/* lib functions */
66EXPORT_SYMBOL(memcpy);
diff --git a/arch/c6x/kernel/devicetree.c b/arch/c6x/kernel/devicetree.c
new file mode 100644
index 000000000000..bdb56f09d0ac
--- /dev/null
+++ b/arch/c6x/kernel/devicetree.c
@@ -0,0 +1,53 @@
1/*
2 * Architecture specific OF callbacks.
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/init.h>
13#include <linux/of.h>
14#include <linux/of_fdt.h>
15#include <linux/initrd.h>
16#include <linux/memblock.h>
17
18void __init early_init_devtree(void *params)
19{
20 /* Setup flat device-tree pointer */
21 initial_boot_params = params;
22
23 /* Retrieve various informations from the /chosen node of the
24 * device-tree, including the platform type, initrd location and
25 * size and more ...
26 */
27 of_scan_flat_dt(early_init_dt_scan_chosen, c6x_command_line);
28
29 /* Scan memory nodes and rebuild MEMBLOCKs */
30 of_scan_flat_dt(early_init_dt_scan_root, NULL);
31 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
32}
33
34
35#ifdef CONFIG_BLK_DEV_INITRD
36void __init early_init_dt_setup_initrd_arch(unsigned long start,
37 unsigned long end)
38{
39 initrd_start = (unsigned long)__va(start);
40 initrd_end = (unsigned long)__va(end);
41 initrd_below_start_ok = 1;
42}
43#endif
44
45void __init early_init_dt_add_memory_arch(u64 base, u64 size)
46{
47 c6x_add_memory(base, size);
48}
49
50void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
51{
52 return __va(memblock_alloc(size, align));
53}
diff --git a/arch/c6x/kernel/dma.c b/arch/c6x/kernel/dma.c
new file mode 100644
index 000000000000..ab7b12de144d
--- /dev/null
+++ b/arch/c6x/kernel/dma.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#include <linux/module.h>
10#include <linux/dma-mapping.h>
11#include <linux/mm.h>
12#include <linux/mm_types.h>
13#include <linux/scatterlist.h>
14
15#include <asm/cacheflush.h>
16
17static void c6x_dma_sync(dma_addr_t handle, size_t size,
18 enum dma_data_direction dir)
19{
20 unsigned long paddr = handle;
21
22 BUG_ON(!valid_dma_direction(dir));
23
24 switch (dir) {
25 case DMA_FROM_DEVICE:
26 L2_cache_block_invalidate(paddr, paddr + size);
27 break;
28 case DMA_TO_DEVICE:
29 L2_cache_block_writeback(paddr, paddr + size);
30 break;
31 case DMA_BIDIRECTIONAL:
32 L2_cache_block_writeback_invalidate(paddr, paddr + size);
33 break;
34 default:
35 break;
36 }
37}
38
39dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
40 enum dma_data_direction dir)
41{
42 dma_addr_t addr = virt_to_phys(ptr);
43
44 c6x_dma_sync(addr, size, dir);
45
46 debug_dma_map_page(dev, virt_to_page(ptr),
47 (unsigned long)ptr & ~PAGE_MASK, size,
48 dir, addr, true);
49 return addr;
50}
51EXPORT_SYMBOL(dma_map_single);
52
53
54void dma_unmap_single(struct device *dev, dma_addr_t handle,
55 size_t size, enum dma_data_direction dir)
56{
57 c6x_dma_sync(handle, size, dir);
58
59 debug_dma_unmap_page(dev, handle, size, dir, true);
60}
61EXPORT_SYMBOL(dma_unmap_single);
62
63
64int dma_map_sg(struct device *dev, struct scatterlist *sglist,
65 int nents, enum dma_data_direction dir)
66{
67 struct scatterlist *sg;
68 int i;
69
70 for_each_sg(sglist, sg, nents, i)
71 sg->dma_address = dma_map_single(dev, sg_virt(sg), sg->length,
72 dir);
73
74 debug_dma_map_sg(dev, sglist, nents, nents, dir);
75
76 return nents;
77}
78EXPORT_SYMBOL(dma_map_sg);
79
80
81void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
82 int nents, enum dma_data_direction dir)
83{
84 struct scatterlist *sg;
85 int i;
86
87 for_each_sg(sglist, sg, nents, i)
88 dma_unmap_single(dev, sg_dma_address(sg), sg->length, dir);
89
90 debug_dma_unmap_sg(dev, sglist, nents, dir);
91}
92EXPORT_SYMBOL(dma_unmap_sg);
93
94void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
95 size_t size, enum dma_data_direction dir)
96{
97 c6x_dma_sync(handle, size, dir);
98
99 debug_dma_sync_single_for_cpu(dev, handle, size, dir);
100}
101EXPORT_SYMBOL(dma_sync_single_for_cpu);
102
103
104void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
105 size_t size, enum dma_data_direction dir)
106{
107 c6x_dma_sync(handle, size, dir);
108
109 debug_dma_sync_single_for_device(dev, handle, size, dir);
110}
111EXPORT_SYMBOL(dma_sync_single_for_device);
112
113
114void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist,
115 int nents, enum dma_data_direction dir)
116{
117 struct scatterlist *sg;
118 int i;
119
120 for_each_sg(sglist, sg, nents, i)
121 dma_sync_single_for_cpu(dev, sg_dma_address(sg),
122 sg->length, dir);
123
124 debug_dma_sync_sg_for_cpu(dev, sglist, nents, dir);
125}
126EXPORT_SYMBOL(dma_sync_sg_for_cpu);
127
128
129void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
130 int nents, enum dma_data_direction dir)
131{
132 struct scatterlist *sg;
133 int i;
134
135 for_each_sg(sglist, sg, nents, i)
136 dma_sync_single_for_device(dev, sg_dma_address(sg),
137 sg->length, dir);
138
139 debug_dma_sync_sg_for_device(dev, sglist, nents, dir);
140}
141EXPORT_SYMBOL(dma_sync_sg_for_device);
142
143
144/* Number of entries preallocated for DMA-API debugging */
145#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
146
147static int __init dma_init(void)
148{
149 dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
150
151 return 0;
152}
153fs_initcall(dma_init);
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
new file mode 100644
index 000000000000..3e977ccda827
--- /dev/null
+++ b/arch/c6x/kernel/entry.S
@@ -0,0 +1,803 @@
1;
2; Port on Texas Instruments TMS320C6x architecture
3;
4; Copyright (C) 2004-2011 Texas Instruments Incorporated
5; Author: Aurelien Jacquiot (aurelien.jacquiot@virtuallogix.com)
6; Updated for 2.6.34: Mark Salter <msalter@redhat.com>
7;
8; This program is free software; you can redistribute it and/or modify
9; it under the terms of the GNU General Public License version 2 as
10; published by the Free Software Foundation.
11;
12
13#include <linux/sys.h>
14#include <linux/linkage.h>
15#include <asm/thread_info.h>
16#include <asm/asm-offsets.h>
17#include <asm/unistd.h>
18#include <asm/errno.h>
19
20; Registers naming
21#define DP B14
22#define SP B15
23
24#ifndef CONFIG_PREEMPT
25#define resume_kernel restore_all
26#endif
27
28 .altmacro
29
30 .macro MASK_INT reg
31 MVC .S2 CSR,reg
32 CLR .S2 reg,0,0,reg
33 MVC .S2 reg,CSR
34 .endm
35
36 .macro UNMASK_INT reg
37 MVC .S2 CSR,reg
38 SET .S2 reg,0,0,reg
39 MVC .S2 reg,CSR
40 .endm
41
42 .macro GET_THREAD_INFO reg
43 SHR .S1X SP,THREAD_SHIFT,reg
44 SHL .S1 reg,THREAD_SHIFT,reg
45 .endm
46
47 ;;
48 ;; This defines the normal kernel pt_regs layout.
49 ;;
50 .macro SAVE_ALL __rp __tsr
51 STW .D2T2 B0,*SP--[2] ; save original B0
52 MVKL .S2 current_ksp,B0
53 MVKH .S2 current_ksp,B0
54 LDW .D2T2 *B0,B1 ; KSP
55
56 NOP 3
57 STW .D2T2 B1,*+SP[1] ; save original B1
58 XOR .D2 SP,B1,B0 ; (SP ^ KSP)
59 LDW .D2T2 *+SP[1],B1 ; restore B0/B1
60 LDW .D2T2 *++SP[2],B0
61 SHR .S2 B0,THREAD_SHIFT,B0 ; 0 if already using kstack
62 [B0] STDW .D2T2 SP:DP,*--B1[1] ; user: save user sp/dp kstack
63 [B0] MV .S2 B1,SP ; and switch to kstack
64||[!B0] STDW .D2T2 SP:DP,*--SP[1] ; kernel: save on current stack
65
66 SUBAW .D2 SP,2,SP
67
68 ADD .D1X SP,-8,A15
69 || STDW .D2T1 A15:A14,*SP--[16] ; save A15:A14
70
71 STDW .D2T2 B13:B12,*SP--[1]
72 || STDW .D1T1 A13:A12,*A15--[1]
73 || MVC .S2 __rp,B13
74
75 STDW .D2T2 B11:B10,*SP--[1]
76 || STDW .D1T1 A11:A10,*A15--[1]
77 || MVC .S2 CSR,B12
78
79 STDW .D2T2 B9:B8,*SP--[1]
80 || STDW .D1T1 A9:A8,*A15--[1]
81 || MVC .S2 RILC,B11
82 STDW .D2T2 B7:B6,*SP--[1]
83 || STDW .D1T1 A7:A6,*A15--[1]
84 || MVC .S2 ILC,B10
85
86 STDW .D2T2 B5:B4,*SP--[1]
87 || STDW .D1T1 A5:A4,*A15--[1]
88
89 STDW .D2T2 B3:B2,*SP--[1]
90 || STDW .D1T1 A3:A2,*A15--[1]
91 || MVC .S2 __tsr,B5
92
93 STDW .D2T2 B1:B0,*SP--[1]
94 || STDW .D1T1 A1:A0,*A15--[1]
95 || MV .S1X B5,A5
96
97 STDW .D2T2 B31:B30,*SP--[1]
98 || STDW .D1T1 A31:A30,*A15--[1]
99 STDW .D2T2 B29:B28,*SP--[1]
100 || STDW .D1T1 A29:A28,*A15--[1]
101 STDW .D2T2 B27:B26,*SP--[1]
102 || STDW .D1T1 A27:A26,*A15--[1]
103 STDW .D2T2 B25:B24,*SP--[1]
104 || STDW .D1T1 A25:A24,*A15--[1]
105 STDW .D2T2 B23:B22,*SP--[1]
106 || STDW .D1T1 A23:A22,*A15--[1]
107 STDW .D2T2 B21:B20,*SP--[1]
108 || STDW .D1T1 A21:A20,*A15--[1]
109 STDW .D2T2 B19:B18,*SP--[1]
110 || STDW .D1T1 A19:A18,*A15--[1]
111 STDW .D2T2 B17:B16,*SP--[1]
112 || STDW .D1T1 A17:A16,*A15--[1]
113
114 STDW .D2T2 B13:B12,*SP--[1] ; save PC and CSR
115
116 STDW .D2T2 B11:B10,*SP--[1] ; save RILC and ILC
117 STDW .D2T1 A5:A4,*SP--[1] ; save TSR and orig A4
118
119 ;; We left an unused word on the stack just above pt_regs.
120 ;; It is used to save whether or not this frame is due to
121 ;; a syscall. It is cleared here, but the syscall handler
122 ;; sets it to a non-zero value.
123 MVK .L2 0,B1
124 STW .D2T2 B1,*+SP(REGS__END+8) ; clear syscall flag
125 .endm
126
127 .macro RESTORE_ALL __rp __tsr
128 LDDW .D2T2 *++SP[1],B9:B8 ; get TSR (B9)
129 LDDW .D2T2 *++SP[1],B11:B10 ; get RILC (B11) and ILC (B10)
130 LDDW .D2T2 *++SP[1],B13:B12 ; get PC (B13) and CSR (B12)
131
132 ADDAW .D1X SP,30,A15
133
134 LDDW .D1T1 *++A15[1],A17:A16
135 || LDDW .D2T2 *++SP[1],B17:B16
136 LDDW .D1T1 *++A15[1],A19:A18
137 || LDDW .D2T2 *++SP[1],B19:B18
138 LDDW .D1T1 *++A15[1],A21:A20
139 || LDDW .D2T2 *++SP[1],B21:B20
140 LDDW .D1T1 *++A15[1],A23:A22
141 || LDDW .D2T2 *++SP[1],B23:B22
142 LDDW .D1T1 *++A15[1],A25:A24
143 || LDDW .D2T2 *++SP[1],B25:B24
144 LDDW .D1T1 *++A15[1],A27:A26
145 || LDDW .D2T2 *++SP[1],B27:B26
146 LDDW .D1T1 *++A15[1],A29:A28
147 || LDDW .D2T2 *++SP[1],B29:B28
148 LDDW .D1T1 *++A15[1],A31:A30
149 || LDDW .D2T2 *++SP[1],B31:B30
150
151 LDDW .D1T1 *++A15[1],A1:A0
152 || LDDW .D2T2 *++SP[1],B1:B0
153
154 LDDW .D1T1 *++A15[1],A3:A2
155 || LDDW .D2T2 *++SP[1],B3:B2
156 || MVC .S2 B9,__tsr
157 LDDW .D1T1 *++A15[1],A5:A4
158 || LDDW .D2T2 *++SP[1],B5:B4
159 || MVC .S2 B11,RILC
160 LDDW .D1T1 *++A15[1],A7:A6
161 || LDDW .D2T2 *++SP[1],B7:B6
162 || MVC .S2 B10,ILC
163
164 LDDW .D1T1 *++A15[1],A9:A8
165 || LDDW .D2T2 *++SP[1],B9:B8
166 || MVC .S2 B13,__rp
167
168 LDDW .D1T1 *++A15[1],A11:A10
169 || LDDW .D2T2 *++SP[1],B11:B10
170 || MVC .S2 B12,CSR
171
172 LDDW .D1T1 *++A15[1],A13:A12
173 || LDDW .D2T2 *++SP[1],B13:B12
174
175 MV .D2X A15,SP
176 || MVKL .S1 current_ksp,A15
177 MVKH .S1 current_ksp,A15
178 || ADDAW .D1X SP,6,A14
179 STW .D1T1 A14,*A15 ; save kernel stack pointer
180
181 LDDW .D2T1 *++SP[1],A15:A14
182
183 B .S2 __rp ; return from interruption
184 LDDW .D2T2 *+SP[1],SP:DP
185 NOP 4
186 .endm
187
188 .section .text
189
190 ;;
191 ;; Jump to schedule() then return to ret_from_exception
192 ;;
193_reschedule:
194#ifdef CONFIG_C6X_BIG_KERNEL
195 MVKL .S1 schedule,A0
196 MVKH .S1 schedule,A0
197 B .S2X A0
198#else
199 B .S1 schedule
200#endif
201 ADDKPC .S2 ret_from_exception,B3,4
202
203 ;;
204 ;; Called before syscall handler when process is being debugged
205 ;;
206tracesys_on:
207#ifdef CONFIG_C6X_BIG_KERNEL
208 MVKL .S1 syscall_trace_entry,A0
209 MVKH .S1 syscall_trace_entry,A0
210 B .S2X A0
211#else
212 B .S1 syscall_trace_entry
213#endif
214 ADDKPC .S2 ret_from_syscall_trace,B3,3
215 ADD .S1X 8,SP,A4
216
217ret_from_syscall_trace:
218 ;; tracing returns (possibly new) syscall number
219 MV .D2X A4,B0
220 || MVK .S2 __NR_syscalls,B1
221 CMPLTU .L2 B0,B1,B1
222
223 [!B1] BNOP .S2 ret_from_syscall_function,5
224 || MVK .S1 -ENOSYS,A4
225
226 ;; reload syscall args from (possibly modified) stack frame
227 ;; and get syscall handler addr from sys_call_table:
228 LDW .D2T2 *+SP(REGS_B4+8),B4
229 || MVKL .S2 sys_call_table,B1
230 LDW .D2T1 *+SP(REGS_A6+8),A6
231 || MVKH .S2 sys_call_table,B1
232 LDW .D2T2 *+B1[B0],B0
233 || MVKL .S2 ret_from_syscall_function,B3
234 LDW .D2T2 *+SP(REGS_B6+8),B6
235 || MVKH .S2 ret_from_syscall_function,B3
236 LDW .D2T1 *+SP(REGS_A8+8),A8
237 LDW .D2T2 *+SP(REGS_B8+8),B8
238 NOP
239 ; B0 = sys_call_table[__NR_*]
240 BNOP .S2 B0,5 ; branch to syscall handler
241 || LDW .D2T1 *+SP(REGS_ORIG_A4+8),A4
242
243syscall_exit_work:
244 AND .D1 _TIF_SYSCALL_TRACE,A2,A0
245 [!A0] BNOP .S1 work_pending,5
246 [A0] B .S2 syscall_trace_exit
247 ADDKPC .S2 resume_userspace,B3,1
248 MVC .S2 CSR,B1
249 SET .S2 B1,0,0,B1
250 MVC .S2 B1,CSR ; enable ints
251
252work_pending:
253 AND .D1 _TIF_NEED_RESCHED,A2,A0
254 [!A0] BNOP .S1 work_notifysig,5
255
256work_resched:
257#ifdef CONFIG_C6X_BIG_KERNEL
258 MVKL .S1 schedule,A1
259 MVKH .S1 schedule,A1
260 B .S2X A1
261#else
262 B .S2 schedule
263#endif
264 ADDKPC .S2 work_rescheduled,B3,4
265work_rescheduled:
266 ;; make sure we don't miss an interrupt setting need_resched or
267 ;; sigpending between sampling and the rti
268 MASK_INT B2
269 GET_THREAD_INFO A12
270 LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
271 MVK .S1 _TIF_WORK_MASK,A1
272 MVK .S1 _TIF_NEED_RESCHED,A3
273 NOP 2
274 AND .D1 A1,A2,A0
275 || AND .S1 A3,A2,A1
276 [!A0] BNOP .S1 restore_all,5
277 [A1] BNOP .S1 work_resched,5
278
279work_notifysig:
280 B .S2 do_notify_resume
281 LDW .D2T1 *+SP(REGS__END+8),A6 ; syscall flag
282 ADDKPC .S2 resume_userspace,B3,1
283 ADD .S1X 8,SP,A4 ; pt_regs pointer is first arg
284 MV .D2X A2,B4 ; thread_info flags is second arg
285
286 ;;
287 ;; On C64x+, the return way from exception and interrupt
288 ;; is a little bit different
289 ;;
290ENTRY(ret_from_exception)
291#ifdef CONFIG_PREEMPT
292 MASK_INT B2
293#endif
294
295ENTRY(ret_from_interrupt)
296 ;;
297 ;; Check if we are comming from user mode.
298 ;;
299 LDW .D2T2 *+SP(REGS_TSR+8),B0
300 MVK .S2 0x40,B1
301 NOP 3
302 AND .D2 B0,B1,B0
303 [!B0] BNOP .S2 resume_kernel,5
304
305resume_userspace:
306 ;; make sure we don't miss an interrupt setting need_resched or
307 ;; sigpending between sampling and the rti
308 MASK_INT B2
309 GET_THREAD_INFO A12
310 LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
311 MVK .S1 _TIF_WORK_MASK,A1
312 MVK .S1 _TIF_NEED_RESCHED,A3
313 NOP 2
314 AND .D1 A1,A2,A0
315 [A0] BNOP .S1 work_pending,5
316 BNOP .S1 restore_all,5
317
318 ;;
319 ;; System call handling
320 ;; B0 = syscall number (in sys_call_table)
321 ;; A4,B4,A6,B6,A8,B8 = arguments of the syscall function
322 ;; A4 is the return value register
323 ;;
324system_call_saved:
325 MVK .L2 1,B2
326 STW .D2T2 B2,*+SP(REGS__END+8) ; set syscall flag
327 MVC .S2 B2,ECR ; ack the software exception
328
329 UNMASK_INT B2 ; re-enable global IT
330
331system_call_saved_noack:
332 ;; Check system call number
333 MVK .S2 __NR_syscalls,B1
334#ifdef CONFIG_C6X_BIG_KERNEL
335 || MVKL .S1 sys_ni_syscall,A0
336#endif
337 CMPLTU .L2 B0,B1,B1
338#ifdef CONFIG_C6X_BIG_KERNEL
339 || MVKH .S1 sys_ni_syscall,A0
340#endif
341
342 ;; Check for ptrace
343 GET_THREAD_INFO A12
344
345#ifdef CONFIG_C6X_BIG_KERNEL
346 [!B1] B .S2X A0
347#else
348 [!B1] B .S2 sys_ni_syscall
349#endif
350 [!B1] ADDKPC .S2 ret_from_syscall_function,B3,4
351
352 ;; Get syscall handler addr from sys_call_table
353 ;; call tracesys_on or call syscall handler
354 LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
355 || MVKL .S2 sys_call_table,B1
356 MVKH .S2 sys_call_table,B1
357 LDW .D2T2 *+B1[B0],B0
358 NOP 2
359 ; A2 = thread_info flags
360 AND .D1 _TIF_SYSCALL_TRACE,A2,A2
361 [A2] BNOP .S1 tracesys_on,5
362 ;; B0 = _sys_call_table[__NR_*]
363 B .S2 B0
364 ADDKPC .S2 ret_from_syscall_function,B3,4
365
366ret_from_syscall_function:
367 STW .D2T1 A4,*+SP(REGS_A4+8) ; save return value in A4
368 ; original A4 is in orig_A4
369syscall_exit:
370 ;; make sure we don't miss an interrupt setting need_resched or
371 ;; sigpending between sampling and the rti
372 MASK_INT B2
373 LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
374 MVK .S1 _TIF_ALLWORK_MASK,A1
375 NOP 3
376 AND .D1 A1,A2,A2 ; check for work to do
377 [A2] BNOP .S1 syscall_exit_work,5
378
379restore_all:
380 RESTORE_ALL NRP,NTSR
381
382 ;;
383 ;; After a fork we jump here directly from resume,
384 ;; so that A4 contains the previous task structure.
385 ;;
386ENTRY(ret_from_fork)
387#ifdef CONFIG_C6X_BIG_KERNEL
388 MVKL .S1 schedule_tail,A0
389 MVKH .S1 schedule_tail,A0
390 B .S2X A0
391#else
392 B .S2 schedule_tail
393#endif
394 ADDKPC .S2 ret_from_fork_2,B3,4
395ret_from_fork_2:
396 ;; return 0 in A4 for child process
397 GET_THREAD_INFO A12
398 BNOP .S2 syscall_exit,3
399 MVK .L2 0,B0
400 STW .D2T2 B0,*+SP(REGS_A4+8)
401ENDPROC(ret_from_fork)
402
403 ;;
404 ;; These are the interrupt handlers, responsible for calling __do_IRQ()
405 ;; int6 is used for syscalls (see _system_call entry)
406 ;;
407 .macro SAVE_ALL_INT
408 SAVE_ALL IRP,ITSR
409 .endm
410
411 .macro CALL_INT int
412#ifdef CONFIG_C6X_BIG_KERNEL
413 MVKL .S1 c6x_do_IRQ,A0
414 MVKH .S1 c6x_do_IRQ,A0
415 BNOP .S2X A0,1
416 MVK .S1 int,A4
417 ADDAW .D2 SP,2,B4
418 MVKL .S2 ret_from_interrupt,B3
419 MVKH .S2 ret_from_interrupt,B3
420#else
421 CALLP .S2 c6x_do_IRQ,B3
422 || MVK .S1 int,A4
423 || ADDAW .D2 SP,2,B4
424 B .S1 ret_from_interrupt
425 NOP 5
426#endif
427 .endm
428
429ENTRY(_int4_handler)
430 SAVE_ALL_INT
431 CALL_INT 4
432ENDPROC(_int4_handler)
433
434ENTRY(_int5_handler)
435 SAVE_ALL_INT
436 CALL_INT 5
437ENDPROC(_int5_handler)
438
439ENTRY(_int6_handler)
440 SAVE_ALL_INT
441 CALL_INT 6
442ENDPROC(_int6_handler)
443
444ENTRY(_int7_handler)
445 SAVE_ALL_INT
446 CALL_INT 7
447ENDPROC(_int7_handler)
448
449ENTRY(_int8_handler)
450 SAVE_ALL_INT
451 CALL_INT 8
452ENDPROC(_int8_handler)
453
454ENTRY(_int9_handler)
455 SAVE_ALL_INT
456 CALL_INT 9
457ENDPROC(_int9_handler)
458
459ENTRY(_int10_handler)
460 SAVE_ALL_INT
461 CALL_INT 10
462ENDPROC(_int10_handler)
463
464ENTRY(_int11_handler)
465 SAVE_ALL_INT
466 CALL_INT 11
467ENDPROC(_int11_handler)
468
469ENTRY(_int12_handler)
470 SAVE_ALL_INT
471 CALL_INT 12
472ENDPROC(_int12_handler)
473
474ENTRY(_int13_handler)
475 SAVE_ALL_INT
476 CALL_INT 13
477ENDPROC(_int13_handler)
478
479ENTRY(_int14_handler)
480 SAVE_ALL_INT
481 CALL_INT 14
482ENDPROC(_int14_handler)
483
484ENTRY(_int15_handler)
485 SAVE_ALL_INT
486 CALL_INT 15
487ENDPROC(_int15_handler)
488
489 ;;
490 ;; Handler for uninitialized and spurious interrupts
491 ;;
492ENTRY(_bad_interrupt)
493 B .S2 IRP
494 NOP 5
495ENDPROC(_bad_interrupt)
496
497 ;;
498 ;; Entry for NMI/exceptions/syscall
499 ;;
500ENTRY(_nmi_handler)
501 SAVE_ALL NRP,NTSR
502
503 MVC .S2 EFR,B2
504 CMPEQ .L2 1,B2,B2
505 || MVC .S2 TSR,B1
506 CLR .S2 B1,10,10,B1
507 MVC .S2 B1,TSR
508#ifdef CONFIG_C6X_BIG_KERNEL
509 [!B2] MVKL .S1 process_exception,A0
510 [!B2] MVKH .S1 process_exception,A0
511 [!B2] B .S2X A0
512#else
513 [!B2] B .S2 process_exception
514#endif
515 [B2] B .S2 system_call_saved
516 [!B2] ADDAW .D2 SP,2,B1
517 [!B2] MV .D1X B1,A4
518 ADDKPC .S2 ret_from_trap,B3,2
519
520ret_from_trap:
521 MV .D2X A4,B0
522 [!B0] BNOP .S2 ret_from_exception,5
523
524#ifdef CONFIG_C6X_BIG_KERNEL
525 MVKL .S2 system_call_saved_noack,B3
526 MVKH .S2 system_call_saved_noack,B3
527#endif
528 LDW .D2T2 *+SP(REGS_B0+8),B0
529 LDW .D2T1 *+SP(REGS_A4+8),A4
530 LDW .D2T2 *+SP(REGS_B4+8),B4
531 LDW .D2T1 *+SP(REGS_A6+8),A6
532 LDW .D2T2 *+SP(REGS_B6+8),B6
533 LDW .D2T1 *+SP(REGS_A8+8),A8
534#ifdef CONFIG_C6X_BIG_KERNEL
535 || B .S2 B3
536#else
537 || B .S2 system_call_saved_noack
538#endif
539 LDW .D2T2 *+SP(REGS_B8+8),B8
540 NOP 4
541ENDPROC(_nmi_handler)
542
543 ;;
544 ;; Jump to schedule() then return to ret_from_isr
545 ;;
546#ifdef CONFIG_PREEMPT
547resume_kernel:
548 GET_THREAD_INFO A12
549 LDW .D1T1 *+A12(THREAD_INFO_PREEMPT_COUNT),A1
550 NOP 4
551 [A1] BNOP .S2 restore_all,5
552
553preempt_schedule:
554 GET_THREAD_INFO A2
555 LDW .D1T1 *+A2(THREAD_INFO_FLAGS),A1
556#ifdef CONFIG_C6X_BIG_KERNEL
557 MVKL .S2 preempt_schedule_irq,B0
558 MVKH .S2 preempt_schedule_irq,B0
559 NOP 2
560#else
561 NOP 4
562#endif
563 AND .D1 _TIF_NEED_RESCHED,A1,A1
564 [!A1] BNOP .S2 restore_all,5
565#ifdef CONFIG_C6X_BIG_KERNEL
566 B .S2 B0
567#else
568 B .S2 preempt_schedule_irq
569#endif
570 ADDKPC .S2 preempt_schedule,B3,4
571#endif /* CONFIG_PREEMPT */
572
573ENTRY(enable_exception)
574 DINT
575 MVC .S2 TSR,B0
576 MVC .S2 B3,NRP
577 MVK .L2 0xc,B1
578 OR .D2 B0,B1,B0
579 MVC .S2 B0,TSR ; Set GEE and XEN in TSR
580 B .S2 NRP
581 NOP 5
582ENDPROC(enable_exception)
583
584ENTRY(sys_sigaltstack)
585#ifdef CONFIG_C6X_BIG_KERNEL
586 MVKL .S1 do_sigaltstack,A0 ; branch to do_sigaltstack
587 MVKH .S1 do_sigaltstack,A0
588 B .S2X A0
589#else
590 B .S2 do_sigaltstack
591#endif
592 LDW .D2T1 *+SP(REGS_SP+8),A6
593 NOP 4
594ENDPROC(sys_sigaltstack)
595
596 ;; kernel_execve
597ENTRY(kernel_execve)
598 MVK .S2 __NR_execve,B0
599 SWE
600 BNOP .S2 B3,5
601ENDPROC(kernel_execve)
602
603 ;;
604 ;; Special system calls
605 ;; return address is in B3
606 ;;
607ENTRY(sys_clone)
608 ADD .D1X SP,8,A4
609#ifdef CONFIG_C6X_BIG_KERNEL
610 || MVKL .S1 sys_c6x_clone,A0
611 MVKH .S1 sys_c6x_clone,A0
612 BNOP .S2X A0,5
613#else
614 || B .S2 sys_c6x_clone
615 NOP 5
616#endif
617ENDPROC(sys_clone)
618
619ENTRY(sys_rt_sigreturn)
620 ADD .D1X SP,8,A4
621#ifdef CONFIG_C6X_BIG_KERNEL
622 || MVKL .S1 do_rt_sigreturn,A0
623 MVKH .S1 do_rt_sigreturn,A0
624 BNOP .S2X A0,5
625#else
626 || B .S2 do_rt_sigreturn
627 NOP 5
628#endif
629ENDPROC(sys_rt_sigreturn)
630
631ENTRY(sys_execve)
632 ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter
633 ; & adjust regs stack addr
634 LDW .D2T2 *+SP(REGS_B4+8),B4
635
636 ;; c6x_execve(char *name, char **argv,
637 ;; char **envp, struct pt_regs *regs)
638#ifdef CONFIG_C6X_BIG_KERNEL
639 || MVKL .S1 sys_c6x_execve,A0
640 MVKH .S1 sys_c6x_execve,A0
641 B .S2X A0
642#else
643 || B .S2 sys_c6x_execve
644#endif
645 STW .D2T2 B3,*SP--[2]
646 ADDKPC .S2 ret_from_c6x_execve,B3,3
647
648ret_from_c6x_execve:
649 LDW .D2T2 *++SP[2],B3
650 NOP 4
651 BNOP .S2 B3,5
652ENDPROC(sys_execve)
653
654ENTRY(sys_pread_c6x)
655 MV .D2X A8,B7
656#ifdef CONFIG_C6X_BIG_KERNEL
657 || MVKL .S1 sys_pread64,A0
658 MVKH .S1 sys_pread64,A0
659 BNOP .S2X A0,5
660#else
661 || B .S2 sys_pread64
662 NOP 5
663#endif
664ENDPROC(sys_pread_c6x)
665
666ENTRY(sys_pwrite_c6x)
667 MV .D2X A8,B7
668#ifdef CONFIG_C6X_BIG_KERNEL
669 || MVKL .S1 sys_pwrite64,A0
670 MVKH .S1 sys_pwrite64,A0
671 BNOP .S2X A0,5
672#else
673 || B .S2 sys_pwrite64
674 NOP 5
675#endif
676ENDPROC(sys_pwrite_c6x)
677
678;; On Entry
679;; A4 - path
680;; B4 - offset_lo (LE), offset_hi (BE)
681;; A6 - offset_lo (BE), offset_hi (LE)
682ENTRY(sys_truncate64_c6x)
683#ifdef CONFIG_CPU_BIG_ENDIAN
684 MV .S2 B4,B5
685 MV .D2X A6,B4
686#else
687 MV .D2X A6,B5
688#endif
689#ifdef CONFIG_C6X_BIG_KERNEL
690 || MVKL .S1 sys_truncate64,A0
691 MVKH .S1 sys_truncate64,A0
692 BNOP .S2X A0,5
693#else
694 || B .S2 sys_truncate64
695 NOP 5
696#endif
697ENDPROC(sys_truncate64_c6x)
698
699;; On Entry
700;; A4 - fd
701;; B4 - offset_lo (LE), offset_hi (BE)
702;; A6 - offset_lo (BE), offset_hi (LE)
703ENTRY(sys_ftruncate64_c6x)
704#ifdef CONFIG_CPU_BIG_ENDIAN
705 MV .S2 B4,B5
706 MV .D2X A6,B4
707#else
708 MV .D2X A6,B5
709#endif
710#ifdef CONFIG_C6X_BIG_KERNEL
711 || MVKL .S1 sys_ftruncate64,A0
712 MVKH .S1 sys_ftruncate64,A0
713 BNOP .S2X A0,5
714#else
715 || B .S2 sys_ftruncate64
716 NOP 5
717#endif
718ENDPROC(sys_ftruncate64_c6x)
719
720#ifdef __ARCH_WANT_SYSCALL_OFF_T
721;; On Entry
722;; A4 - fd
723;; B4 - offset_lo (LE), offset_hi (BE)
724;; A6 - offset_lo (BE), offset_hi (LE)
725;; B6 - len
726;; A8 - advice
727ENTRY(sys_fadvise64_c6x)
728#ifdef CONFIG_C6X_BIG_KERNEL
729 MVKL .S1 sys_fadvise64,A0
730 MVKH .S1 sys_fadvise64,A0
731 BNOP .S2X A0,2
732#else
733 B .S2 sys_fadvise64
734 NOP 2
735#endif
736#ifdef CONFIG_CPU_BIG_ENDIAN
737 MV .L2 B4,B5
738 || MV .D2X A6,B4
739#else
740 MV .D2X A6,B5
741#endif
742 MV .D1X B6,A6
743 MV .D2X A8,B6
744#endif
745ENDPROC(sys_fadvise64_c6x)
746
747;; On Entry
748;; A4 - fd
749;; B4 - offset_lo (LE), offset_hi (BE)
750;; A6 - offset_lo (BE), offset_hi (LE)
751;; B6 - len_lo (LE), len_hi (BE)
752;; A8 - len_lo (BE), len_hi (LE)
753;; B8 - advice
754ENTRY(sys_fadvise64_64_c6x)
755#ifdef CONFIG_C6X_BIG_KERNEL
756 MVKL .S1 sys_fadvise64_64,A0
757 MVKH .S1 sys_fadvise64_64,A0
758 BNOP .S2X A0,2
759#else
760 B .S2 sys_fadvise64_64
761 NOP 2
762#endif
763#ifdef CONFIG_CPU_BIG_ENDIAN
764 MV .L2 B4,B5
765 || MV .D2X A6,B4
766 MV .L1 A8,A6
767 || MV .D1X B6,A7
768#else
769 MV .D2X A6,B5
770 MV .L1 A8,A7
771 || MV .D1X B6,A6
772#endif
773 MV .L2 B8,B6
774ENDPROC(sys_fadvise64_64_c6x)
775
776;; On Entry
777;; A4 - fd
778;; B4 - mode
779;; A6 - offset_hi
780;; B6 - offset_lo
781;; A8 - len_hi
782;; B8 - len_lo
783ENTRY(sys_fallocate_c6x)
784#ifdef CONFIG_C6X_BIG_KERNEL
785 MVKL .S1 sys_fallocate,A0
786 MVKH .S1 sys_fallocate,A0
787 BNOP .S2X A0,1
788#else
789 B .S2 sys_fallocate
790 NOP
791#endif
792 MV .D1 A6,A7
793 MV .D1X B6,A6
794 MV .D2X A8,B7
795 MV .D2 B8,B6
796ENDPROC(sys_fallocate_c6x)
797
798 ;; put this in .neardata for faster access when using DSBT mode
799 .section .neardata,"aw",@progbits
800 .global current_ksp
801 .hidden current_ksp
802current_ksp:
803 .word init_thread_union + THREAD_START_SP
diff --git a/arch/c6x/kernel/head.S b/arch/c6x/kernel/head.S
new file mode 100644
index 000000000000..133eab6edf6b
--- /dev/null
+++ b/arch/c6x/kernel/head.S
@@ -0,0 +1,84 @@
1;
2; Port on Texas Instruments TMS320C6x architecture
3;
4; Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6;
7; This program is free software; you can redistribute it and/or modify
8; it under the terms of the GNU General Public License version 2 as
9; published by the Free Software Foundation.
10;
11#include <linux/linkage.h>
12#include <linux/of_fdt.h>
13#include <asm/asm-offsets.h>
14
15 __HEAD
16ENTRY(_c_int00)
17 ;; Save magic and pointer
18 MV .S1 A4,A10
19 MV .S2 B4,B10
20 MVKL .S2 __bss_start,B5
21 MVKH .S2 __bss_start,B5
22 MVKL .S2 __bss_stop,B6
23 MVKH .S2 __bss_stop,B6
24 SUB .L2 B6,B5,B6 ; bss size
25
26 ;; Set the stack pointer
27 MVKL .S2 current_ksp,B0
28 MVKH .S2 current_ksp,B0
29 LDW .D2T2 *B0,B15
30
31 ;; clear bss
32 SHR .S2 B6,3,B0 ; number of dwords to clear
33 ZERO .L2 B13
34 ZERO .L2 B12
35bss_loop:
36 BDEC .S2 bss_loop,B0
37 NOP 3
38 CMPLT .L2 B0,0,B1
39 [!B1] STDW .D2T2 B13:B12,*B5++[1]
40
41 NOP 4
42 AND .D2 ~7,B15,B15
43
44 ;; Clear GIE and PGIE
45 MVC .S2 CSR,B2
46 CLR .S2 B2,0,1,B2
47 MVC .S2 B2,CSR
48 MVC .S2 TSR,B2
49 CLR .S2 B2,0,1,B2
50 MVC .S2 B2,TSR
51 MVC .S2 ITSR,B2
52 CLR .S2 B2,0,1,B2
53 MVC .S2 B2,ITSR
54 MVC .S2 NTSR,B2
55 CLR .S2 B2,0,1,B2
56 MVC .S2 B2,NTSR
57
58 ;; pass DTB pointer to machine_init (or zero if none)
59 MVKL .S1 OF_DT_HEADER,A0
60 MVKH .S1 OF_DT_HEADER,A0
61 CMPEQ .L1 A10,A0,A0
62 [A0] MV .S1X B10,A4
63 [!A0] MVK .S1 0,A4
64
65#ifdef CONFIG_C6X_BIG_KERNEL
66 MVKL .S1 machine_init,A0
67 MVKH .S1 machine_init,A0
68 B .S2X A0
69 ADDKPC .S2 0f,B3,4
700:
71#else
72 CALLP .S2 machine_init,B3
73#endif
74
75 ;; Jump to Linux init
76#ifdef CONFIG_C6X_BIG_KERNEL
77 MVKL .S1 start_kernel,A0
78 MVKH .S1 start_kernel,A0
79 B .S2X A0
80#else
81 B .S2 start_kernel
82#endif
83 NOP 5
84L1: BNOP .S2 L1,5
diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c
new file mode 100644
index 000000000000..0929e4b2b244
--- /dev/null
+++ b/arch/c6x/kernel/irq.c
@@ -0,0 +1,728 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 *
4 * This borrows heavily from powerpc version, which is:
5 *
6 * Derived from arch/i386/kernel/irq.c
7 * Copyright (C) 1992 Linus Torvalds
8 * Adapted from arch/i386 by Gary Thomas
9 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
10 * Updated and modified by Cort Dougan <cort@fsmlabs.com>
11 * Copyright (C) 1996-2001 Cort Dougan
12 * Adapted for Power Macintosh by Paul Mackerras
13 * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
19 */
20#include <linux/slab.h>
21#include <linux/seq_file.h>
22#include <linux/radix-tree.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/of_irq.h>
26#include <linux/interrupt.h>
27#include <linux/kernel_stat.h>
28
29#include <asm/megamod-pic.h>
30
31unsigned long irq_err_count;
32
33static DEFINE_RAW_SPINLOCK(core_irq_lock);
34
35static void mask_core_irq(struct irq_data *data)
36{
37 unsigned int prio = data->irq;
38
39 BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
40
41 raw_spin_lock(&core_irq_lock);
42 and_creg(IER, ~(1 << prio));
43 raw_spin_unlock(&core_irq_lock);
44}
45
46static void unmask_core_irq(struct irq_data *data)
47{
48 unsigned int prio = data->irq;
49
50 raw_spin_lock(&core_irq_lock);
51 or_creg(IER, 1 << prio);
52 raw_spin_unlock(&core_irq_lock);
53}
54
55static struct irq_chip core_chip = {
56 .name = "core",
57 .irq_mask = mask_core_irq,
58 .irq_unmask = unmask_core_irq,
59};
60
61asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
62{
63 struct pt_regs *old_regs = set_irq_regs(regs);
64
65 irq_enter();
66
67 BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
68
69 generic_handle_irq(prio);
70
71 irq_exit();
72
73 set_irq_regs(old_regs);
74}
75
76static struct irq_host *core_host;
77
78static int core_host_map(struct irq_host *h, unsigned int virq,
79 irq_hw_number_t hw)
80{
81 if (hw < 4 || hw >= NR_PRIORITY_IRQS)
82 return -EINVAL;
83
84 irq_set_status_flags(virq, IRQ_LEVEL);
85 irq_set_chip_and_handler(virq, &core_chip, handle_level_irq);
86 return 0;
87}
88
89static struct irq_host_ops core_host_ops = {
90 .map = core_host_map,
91};
92
93void __init init_IRQ(void)
94{
95 struct device_node *np;
96
97 /* Mask all priority IRQs */
98 and_creg(IER, ~0xfff0);
99
100 np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
101 if (np != NULL) {
102 /* create the core host */
103 core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0,
104 &core_host_ops, 0);
105 if (core_host)
106 irq_set_default_host(core_host);
107 of_node_put(np);
108 }
109
110 printk(KERN_INFO "Core interrupt controller initialized\n");
111
112 /* now we're ready for other SoC controllers */
113 megamod_pic_init();
114
115 /* Clear all general IRQ flags */
116 set_creg(ICR, 0xfff0);
117}
118
119void ack_bad_irq(int irq)
120{
121 printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
122 irq_err_count++;
123}
124
125int arch_show_interrupts(struct seq_file *p, int prec)
126{
127 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
128 return 0;
129}
130
131/*
132 * IRQ controller and virtual interrupts
133 */
134
135/* The main irq map itself is an array of NR_IRQ entries containing the
136 * associate host and irq number. An entry with a host of NULL is free.
137 * An entry can be allocated if it's free, the allocator always then sets
138 * hwirq first to the host's invalid irq number and then fills ops.
139 */
140struct irq_map_entry {
141 irq_hw_number_t hwirq;
142 struct irq_host *host;
143};
144
145static LIST_HEAD(irq_hosts);
146static DEFINE_RAW_SPINLOCK(irq_big_lock);
147static DEFINE_MUTEX(revmap_trees_mutex);
148static struct irq_map_entry irq_map[NR_IRQS];
149static unsigned int irq_virq_count = NR_IRQS;
150static struct irq_host *irq_default_host;
151
152irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
153{
154 return irq_map[d->irq].hwirq;
155}
156EXPORT_SYMBOL_GPL(irqd_to_hwirq);
157
158irq_hw_number_t virq_to_hw(unsigned int virq)
159{
160 return irq_map[virq].hwirq;
161}
162EXPORT_SYMBOL_GPL(virq_to_hw);
163
164bool virq_is_host(unsigned int virq, struct irq_host *host)
165{
166 return irq_map[virq].host == host;
167}
168EXPORT_SYMBOL_GPL(virq_is_host);
169
170static int default_irq_host_match(struct irq_host *h, struct device_node *np)
171{
172 return h->of_node != NULL && h->of_node == np;
173}
174
175struct irq_host *irq_alloc_host(struct device_node *of_node,
176 unsigned int revmap_type,
177 unsigned int revmap_arg,
178 struct irq_host_ops *ops,
179 irq_hw_number_t inval_irq)
180{
181 struct irq_host *host;
182 unsigned int size = sizeof(struct irq_host);
183 unsigned int i;
184 unsigned int *rmap;
185 unsigned long flags;
186
187 /* Allocate structure and revmap table if using linear mapping */
188 if (revmap_type == IRQ_HOST_MAP_LINEAR)
189 size += revmap_arg * sizeof(unsigned int);
190 host = kzalloc(size, GFP_KERNEL);
191 if (host == NULL)
192 return NULL;
193
194 /* Fill structure */
195 host->revmap_type = revmap_type;
196 host->inval_irq = inval_irq;
197 host->ops = ops;
198 host->of_node = of_node_get(of_node);
199
200 if (host->ops->match == NULL)
201 host->ops->match = default_irq_host_match;
202
203 raw_spin_lock_irqsave(&irq_big_lock, flags);
204
205 /* Check for the priority controller. */
206 if (revmap_type == IRQ_HOST_MAP_PRIORITY) {
207 if (irq_map[0].host != NULL) {
208 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
209 of_node_put(host->of_node);
210 kfree(host);
211 return NULL;
212 }
213 irq_map[0].host = host;
214 }
215
216 list_add(&host->link, &irq_hosts);
217 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
218
219 /* Additional setups per revmap type */
220 switch (revmap_type) {
221 case IRQ_HOST_MAP_PRIORITY:
222 /* 0 is always the invalid number for priority */
223 host->inval_irq = 0;
224 /* setup us as the host for all priority interrupts */
225 for (i = 1; i < NR_PRIORITY_IRQS; i++) {
226 irq_map[i].hwirq = i;
227 smp_wmb();
228 irq_map[i].host = host;
229 smp_wmb();
230
231 ops->map(host, i, i);
232 }
233 break;
234 case IRQ_HOST_MAP_LINEAR:
235 rmap = (unsigned int *)(host + 1);
236 for (i = 0; i < revmap_arg; i++)
237 rmap[i] = NO_IRQ;
238 host->revmap_data.linear.size = revmap_arg;
239 smp_wmb();
240 host->revmap_data.linear.revmap = rmap;
241 break;
242 case IRQ_HOST_MAP_TREE:
243 INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
244 break;
245 default:
246 break;
247 }
248
249 pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
250
251 return host;
252}
253
254struct irq_host *irq_find_host(struct device_node *node)
255{
256 struct irq_host *h, *found = NULL;
257 unsigned long flags;
258
259 /* We might want to match the legacy controller last since
260 * it might potentially be set to match all interrupts in
261 * the absence of a device node. This isn't a problem so far
262 * yet though...
263 */
264 raw_spin_lock_irqsave(&irq_big_lock, flags);
265 list_for_each_entry(h, &irq_hosts, link)
266 if (h->ops->match(h, node)) {
267 found = h;
268 break;
269 }
270 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
271 return found;
272}
273EXPORT_SYMBOL_GPL(irq_find_host);
274
275void irq_set_default_host(struct irq_host *host)
276{
277 pr_debug("irq: Default host set to @0x%p\n", host);
278
279 irq_default_host = host;
280}
281
282void irq_set_virq_count(unsigned int count)
283{
284 pr_debug("irq: Trying to set virq count to %d\n", count);
285
286 BUG_ON(count < NR_PRIORITY_IRQS);
287 if (count < NR_IRQS)
288 irq_virq_count = count;
289}
290
291static int irq_setup_virq(struct irq_host *host, unsigned int virq,
292 irq_hw_number_t hwirq)
293{
294 int res;
295
296 res = irq_alloc_desc_at(virq, 0);
297 if (res != virq) {
298 pr_debug("irq: -> allocating desc failed\n");
299 goto error;
300 }
301
302 /* map it */
303 smp_wmb();
304 irq_map[virq].hwirq = hwirq;
305 smp_mb();
306
307 if (host->ops->map(host, virq, hwirq)) {
308 pr_debug("irq: -> mapping failed, freeing\n");
309 goto errdesc;
310 }
311
312 irq_clear_status_flags(virq, IRQ_NOREQUEST);
313
314 return 0;
315
316errdesc:
317 irq_free_descs(virq, 1);
318error:
319 irq_free_virt(virq, 1);
320 return -1;
321}
322
323unsigned int irq_create_direct_mapping(struct irq_host *host)
324{
325 unsigned int virq;
326
327 if (host == NULL)
328 host = irq_default_host;
329
330 BUG_ON(host == NULL);
331 WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
332
333 virq = irq_alloc_virt(host, 1, 0);
334 if (virq == NO_IRQ) {
335 pr_debug("irq: create_direct virq allocation failed\n");
336 return NO_IRQ;
337 }
338
339 pr_debug("irq: create_direct obtained virq %d\n", virq);
340
341 if (irq_setup_virq(host, virq, virq))
342 return NO_IRQ;
343
344 return virq;
345}
346
347unsigned int irq_create_mapping(struct irq_host *host,
348 irq_hw_number_t hwirq)
349{
350 unsigned int virq, hint;
351
352 pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
353
354 /* Look for default host if nececssary */
355 if (host == NULL)
356 host = irq_default_host;
357 if (host == NULL) {
358 printk(KERN_WARNING "irq_create_mapping called for"
359 " NULL host, hwirq=%lx\n", hwirq);
360 WARN_ON(1);
361 return NO_IRQ;
362 }
363 pr_debug("irq: -> using host @%p\n", host);
364
365 /* Check if mapping already exists */
366 virq = irq_find_mapping(host, hwirq);
367 if (virq != NO_IRQ) {
368 pr_debug("irq: -> existing mapping on virq %d\n", virq);
369 return virq;
370 }
371
372 /* Allocate a virtual interrupt number */
373 hint = hwirq % irq_virq_count;
374 virq = irq_alloc_virt(host, 1, hint);
375 if (virq == NO_IRQ) {
376 pr_debug("irq: -> virq allocation failed\n");
377 return NO_IRQ;
378 }
379
380 if (irq_setup_virq(host, virq, hwirq))
381 return NO_IRQ;
382
383 pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
384 hwirq, host->of_node ? host->of_node->full_name : "null", virq);
385
386 return virq;
387}
388EXPORT_SYMBOL_GPL(irq_create_mapping);
389
390unsigned int irq_create_of_mapping(struct device_node *controller,
391 const u32 *intspec, unsigned int intsize)
392{
393 struct irq_host *host;
394 irq_hw_number_t hwirq;
395 unsigned int type = IRQ_TYPE_NONE;
396 unsigned int virq;
397
398 if (controller == NULL)
399 host = irq_default_host;
400 else
401 host = irq_find_host(controller);
402 if (host == NULL) {
403 printk(KERN_WARNING "irq: no irq host found for %s !\n",
404 controller->full_name);
405 return NO_IRQ;
406 }
407
408 /* If host has no translation, then we assume interrupt line */
409 if (host->ops->xlate == NULL)
410 hwirq = intspec[0];
411 else {
412 if (host->ops->xlate(host, controller, intspec, intsize,
413 &hwirq, &type))
414 return NO_IRQ;
415 }
416
417 /* Create mapping */
418 virq = irq_create_mapping(host, hwirq);
419 if (virq == NO_IRQ)
420 return virq;
421
422 /* Set type if specified and different than the current one */
423 if (type != IRQ_TYPE_NONE &&
424 type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
425 irq_set_irq_type(virq, type);
426 return virq;
427}
428EXPORT_SYMBOL_GPL(irq_create_of_mapping);
429
430void irq_dispose_mapping(unsigned int virq)
431{
432 struct irq_host *host;
433 irq_hw_number_t hwirq;
434
435 if (virq == NO_IRQ)
436 return;
437
438 /* Never unmap priority interrupts */
439 if (virq < NR_PRIORITY_IRQS)
440 return;
441
442 host = irq_map[virq].host;
443 if (WARN_ON(host == NULL))
444 return;
445
446 irq_set_status_flags(virq, IRQ_NOREQUEST);
447
448 /* remove chip and handler */
449 irq_set_chip_and_handler(virq, NULL, NULL);
450
451 /* Make sure it's completed */
452 synchronize_irq(virq);
453
454 /* Tell the PIC about it */
455 if (host->ops->unmap)
456 host->ops->unmap(host, virq);
457 smp_mb();
458
459 /* Clear reverse map */
460 hwirq = irq_map[virq].hwirq;
461 switch (host->revmap_type) {
462 case IRQ_HOST_MAP_LINEAR:
463 if (hwirq < host->revmap_data.linear.size)
464 host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
465 break;
466 case IRQ_HOST_MAP_TREE:
467 mutex_lock(&revmap_trees_mutex);
468 radix_tree_delete(&host->revmap_data.tree, hwirq);
469 mutex_unlock(&revmap_trees_mutex);
470 break;
471 }
472
473 /* Destroy map */
474 smp_mb();
475 irq_map[virq].hwirq = host->inval_irq;
476
477 irq_free_descs(virq, 1);
478 /* Free it */
479 irq_free_virt(virq, 1);
480}
481EXPORT_SYMBOL_GPL(irq_dispose_mapping);
482
483unsigned int irq_find_mapping(struct irq_host *host,
484 irq_hw_number_t hwirq)
485{
486 unsigned int i;
487 unsigned int hint = hwirq % irq_virq_count;
488
489 /* Look for default host if nececssary */
490 if (host == NULL)
491 host = irq_default_host;
492 if (host == NULL)
493 return NO_IRQ;
494
495 /* Slow path does a linear search of the map */
496 i = hint;
497 do {
498 if (irq_map[i].host == host &&
499 irq_map[i].hwirq == hwirq)
500 return i;
501 i++;
502 if (i >= irq_virq_count)
503 i = 4;
504 } while (i != hint);
505 return NO_IRQ;
506}
507EXPORT_SYMBOL_GPL(irq_find_mapping);
508
509unsigned int irq_radix_revmap_lookup(struct irq_host *host,
510 irq_hw_number_t hwirq)
511{
512 struct irq_map_entry *ptr;
513 unsigned int virq;
514
515 if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
516 return irq_find_mapping(host, hwirq);
517
518 /*
519 * The ptr returned references the static global irq_map.
520 * but freeing an irq can delete nodes along the path to
521 * do the lookup via call_rcu.
522 */
523 rcu_read_lock();
524 ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
525 rcu_read_unlock();
526
527 /*
528 * If found in radix tree, then fine.
529 * Else fallback to linear lookup - this should not happen in practice
530 * as it means that we failed to insert the node in the radix tree.
531 */
532 if (ptr)
533 virq = ptr - irq_map;
534 else
535 virq = irq_find_mapping(host, hwirq);
536
537 return virq;
538}
539
540void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
541 irq_hw_number_t hwirq)
542{
543 if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
544 return;
545
546 if (virq != NO_IRQ) {
547 mutex_lock(&revmap_trees_mutex);
548 radix_tree_insert(&host->revmap_data.tree, hwirq,
549 &irq_map[virq]);
550 mutex_unlock(&revmap_trees_mutex);
551 }
552}
553
554unsigned int irq_linear_revmap(struct irq_host *host,
555 irq_hw_number_t hwirq)
556{
557 unsigned int *revmap;
558
559 if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
560 return irq_find_mapping(host, hwirq);
561
562 /* Check revmap bounds */
563 if (unlikely(hwirq >= host->revmap_data.linear.size))
564 return irq_find_mapping(host, hwirq);
565
566 /* Check if revmap was allocated */
567 revmap = host->revmap_data.linear.revmap;
568 if (unlikely(revmap == NULL))
569 return irq_find_mapping(host, hwirq);
570
571 /* Fill up revmap with slow path if no mapping found */
572 if (unlikely(revmap[hwirq] == NO_IRQ))
573 revmap[hwirq] = irq_find_mapping(host, hwirq);
574
575 return revmap[hwirq];
576}
577
578unsigned int irq_alloc_virt(struct irq_host *host,
579 unsigned int count,
580 unsigned int hint)
581{
582 unsigned long flags;
583 unsigned int i, j, found = NO_IRQ;
584
585 if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS))
586 return NO_IRQ;
587
588 raw_spin_lock_irqsave(&irq_big_lock, flags);
589
590 /* Use hint for 1 interrupt if any */
591 if (count == 1 && hint >= NR_PRIORITY_IRQS &&
592 hint < irq_virq_count && irq_map[hint].host == NULL) {
593 found = hint;
594 goto hint_found;
595 }
596
597 /* Look for count consecutive numbers in the allocatable
598 * (non-legacy) space
599 */
600 for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) {
601 if (irq_map[i].host != NULL)
602 j = 0;
603 else
604 j++;
605
606 if (j == count) {
607 found = i - count + 1;
608 break;
609 }
610 }
611 if (found == NO_IRQ) {
612 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
613 return NO_IRQ;
614 }
615 hint_found:
616 for (i = found; i < (found + count); i++) {
617 irq_map[i].hwirq = host->inval_irq;
618 smp_wmb();
619 irq_map[i].host = host;
620 }
621 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
622 return found;
623}
624
625void irq_free_virt(unsigned int virq, unsigned int count)
626{
627 unsigned long flags;
628 unsigned int i;
629
630 WARN_ON(virq < NR_PRIORITY_IRQS);
631 WARN_ON(count == 0 || (virq + count) > irq_virq_count);
632
633 if (virq < NR_PRIORITY_IRQS) {
634 if (virq + count < NR_PRIORITY_IRQS)
635 return;
636 count -= NR_PRIORITY_IRQS - virq;
637 virq = NR_PRIORITY_IRQS;
638 }
639
640 if (count > irq_virq_count || virq > irq_virq_count - count) {
641 if (virq > irq_virq_count)
642 return;
643 count = irq_virq_count - virq;
644 }
645
646 raw_spin_lock_irqsave(&irq_big_lock, flags);
647 for (i = virq; i < (virq + count); i++) {
648 struct irq_host *host;
649
650 host = irq_map[i].host;
651 irq_map[i].hwirq = host->inval_irq;
652 smp_wmb();
653 irq_map[i].host = NULL;
654 }
655 raw_spin_unlock_irqrestore(&irq_big_lock, flags);
656}
657
658#ifdef CONFIG_VIRQ_DEBUG
659static int virq_debug_show(struct seq_file *m, void *private)
660{
661 unsigned long flags;
662 struct irq_desc *desc;
663 const char *p;
664 static const char none[] = "none";
665 void *data;
666 int i;
667
668 seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
669 "chip name", "chip data", "host name");
670
671 for (i = 1; i < nr_irqs; i++) {
672 desc = irq_to_desc(i);
673 if (!desc)
674 continue;
675
676 raw_spin_lock_irqsave(&desc->lock, flags);
677
678 if (desc->action && desc->action->handler) {
679 struct irq_chip *chip;
680
681 seq_printf(m, "%5d ", i);
682 seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
683
684 chip = irq_desc_get_chip(desc);
685 if (chip && chip->name)
686 p = chip->name;
687 else
688 p = none;
689 seq_printf(m, "%-15s ", p);
690
691 data = irq_desc_get_chip_data(desc);
692 seq_printf(m, "0x%16p ", data);
693
694 if (irq_map[i].host && irq_map[i].host->of_node)
695 p = irq_map[i].host->of_node->full_name;
696 else
697 p = none;
698 seq_printf(m, "%s\n", p);
699 }
700
701 raw_spin_unlock_irqrestore(&desc->lock, flags);
702 }
703
704 return 0;
705}
706
707static int virq_debug_open(struct inode *inode, struct file *file)
708{
709 return single_open(file, virq_debug_show, inode->i_private);
710}
711
712static const struct file_operations virq_debug_fops = {
713 .open = virq_debug_open,
714 .read = seq_read,
715 .llseek = seq_lseek,
716 .release = single_release,
717};
718
719static int __init irq_debugfs_init(void)
720{
721 if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
722 NULL, &virq_debug_fops) == NULL)
723 return -ENOMEM;
724
725 return 0;
726}
727device_initcall(irq_debugfs_init);
728#endif /* CONFIG_VIRQ_DEBUG */
diff --git a/arch/c6x/kernel/module.c b/arch/c6x/kernel/module.c
new file mode 100644
index 000000000000..5fc03f18f56c
--- /dev/null
+++ b/arch/c6x/kernel/module.c
@@ -0,0 +1,123 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Thomas Charleux (thomas.charleux@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/moduleloader.h>
13#include <linux/elf.h>
14#include <linux/vmalloc.h>
15#include <linux/kernel.h>
16
17static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift)
18{
19 u32 opcode;
20 long ep = (long)ip & ~31;
21 long delta = ((long)dest - ep) >> 2;
22 long mask = (1 << maskbits) - 1;
23
24 if ((delta >> (maskbits - 1)) == 0 ||
25 (delta >> (maskbits - 1)) == -1) {
26 opcode = *ip;
27 opcode &= ~(mask << shift);
28 opcode |= ((delta & mask) << shift);
29 *ip = opcode;
30
31 pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n",
32 maskbits, ip, (void *)dest, opcode);
33
34 return 0;
35 }
36 pr_err("PCR_S%d reloc %p -> %p out of range!\n",
37 maskbits, ip, (void *)dest);
38
39 return -1;
40}
41
42/*
43 * apply a RELA relocation
44 */
45int apply_relocate_add(Elf32_Shdr *sechdrs,
46 const char *strtab,
47 unsigned int symindex,
48 unsigned int relsec,
49 struct module *me)
50{
51 Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr;
52 Elf_Sym *sym;
53 u32 *location, opcode;
54 unsigned int i;
55 Elf32_Addr v;
56 Elf_Addr offset = 0;
57
58 pr_debug("Applying relocate section %u to %u with offset 0x%x\n",
59 relsec, sechdrs[relsec].sh_info, offset);
60
61 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
62 /* This is where to make the change */
63 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
64 + rel[i].r_offset - offset;
65
66 /* This is the symbol it is referring to. Note that all
67 undefined symbols have been resolved. */
68 sym = (Elf_Sym *)sechdrs[symindex].sh_addr
69 + ELF32_R_SYM(rel[i].r_info);
70
71 /* this is the adjustment to be made */
72 v = sym->st_value + rel[i].r_addend;
73
74 switch (ELF32_R_TYPE(rel[i].r_info)) {
75 case R_C6000_ABS32:
76 pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v);
77 *location = v;
78 break;
79 case R_C6000_ABS16:
80 pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v);
81 *(u16 *)location = v;
82 break;
83 case R_C6000_ABS8:
84 pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v);
85 *(u8 *)location = v;
86 break;
87 case R_C6000_ABS_L16:
88 opcode = *location;
89 opcode &= ~0x7fff80;
90 opcode |= ((v & 0xffff) << 7);
91 pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n",
92 location, v, opcode);
93 *location = opcode;
94 break;
95 case R_C6000_ABS_H16:
96 opcode = *location;
97 opcode &= ~0x7fff80;
98 opcode |= ((v >> 9) & 0x7fff80);
99 pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n",
100 location, v, opcode);
101 *location = opcode;
102 break;
103 case R_C6000_PCR_S21:
104 if (fixup_pcr(location, v, 21, 7))
105 return -ENOEXEC;
106 break;
107 case R_C6000_PCR_S12:
108 if (fixup_pcr(location, v, 12, 16))
109 return -ENOEXEC;
110 break;
111 case R_C6000_PCR_S10:
112 if (fixup_pcr(location, v, 10, 13))
113 return -ENOEXEC;
114 break;
115 default:
116 pr_err("module %s: Unknown RELA relocation: %u\n",
117 me->name, ELF32_R_TYPE(rel[i].r_info));
118 return -ENOEXEC;
119 }
120 }
121
122 return 0;
123}
diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c
new file mode 100644
index 000000000000..7ca8c41b03cd
--- /dev/null
+++ b/arch/c6x/kernel/process.c
@@ -0,0 +1,265 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/module.h>
13#include <linux/unistd.h>
14#include <linux/ptrace.h>
15#include <linux/init_task.h>
16#include <linux/tick.h>
17#include <linux/mqueue.h>
18#include <linux/syscalls.h>
19#include <linux/reboot.h>
20
21#include <asm/syscalls.h>
22
23/* hooks for board specific support */
24void (*c6x_restart)(void);
25void (*c6x_halt)(void);
26
27extern asmlinkage void ret_from_fork(void);
28
29static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
30static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
31
32/*
33 * Initial thread structure.
34 */
35union thread_union init_thread_union __init_task_data = {
36 INIT_THREAD_INFO(init_task)
37};
38
39/*
40 * Initial task structure.
41 */
42struct task_struct init_task = INIT_TASK(init_task);
43EXPORT_SYMBOL(init_task);
44
45/*
46 * power off function, if any
47 */
48void (*pm_power_off)(void);
49EXPORT_SYMBOL(pm_power_off);
50
51static void c6x_idle(void)
52{
53 unsigned long tmp;
54
55 /*
56 * Put local_irq_enable and idle in same execute packet
57 * to make them atomic and avoid race to idle with
58 * interrupts enabled.
59 */
60 asm volatile (" mvc .s2 CSR,%0\n"
61 " or .d2 1,%0,%0\n"
62 " mvc .s2 %0,CSR\n"
63 "|| idle\n"
64 : "=b"(tmp));
65}
66
67/*
68 * The idle loop for C64x
69 */
70void cpu_idle(void)
71{
72 /* endless idle loop with no priority at all */
73 while (1) {
74 tick_nohz_idle_enter();
75 rcu_idle_enter();
76 while (1) {
77 local_irq_disable();
78 if (need_resched()) {
79 local_irq_enable();
80 break;
81 }
82 c6x_idle(); /* enables local irqs */
83 }
84 rcu_idle_exit();
85 tick_nohz_idle_exit();
86
87 preempt_enable_no_resched();
88 schedule();
89 preempt_disable();
90 }
91}
92
93static void halt_loop(void)
94{
95 printk(KERN_EMERG "System Halted, OK to turn off power\n");
96 local_irq_disable();
97 while (1)
98 asm volatile("idle\n");
99}
100
101void machine_restart(char *__unused)
102{
103 if (c6x_restart)
104 c6x_restart();
105 halt_loop();
106}
107
108void machine_halt(void)
109{
110 if (c6x_halt)
111 c6x_halt();
112 halt_loop();
113}
114
115void machine_power_off(void)
116{
117 if (pm_power_off)
118 pm_power_off();
119 halt_loop();
120}
121
122static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *))
123{
124 do_exit(fn(arg));
125}
126
127/*
128 * Create a kernel thread
129 */
130int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
131{
132 struct pt_regs regs;
133
134 /*
135 * copy_thread sets a4 to zero (child return from fork)
136 * so we can't just set things up to directly return to
137 * fn.
138 */
139 memset(&regs, 0, sizeof(regs));
140 regs.b4 = (unsigned long) arg;
141 regs.a6 = (unsigned long) fn;
142 regs.pc = (unsigned long) kernel_thread_helper;
143 local_save_flags(regs.csr);
144 regs.csr |= 1;
145 regs.tsr = 5; /* Set GEE and GIE in TSR */
146
147 /* Ok, create the new process.. */
148 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, &regs,
149 0, NULL, NULL);
150}
151EXPORT_SYMBOL(kernel_thread);
152
153void flush_thread(void)
154{
155}
156
157void exit_thread(void)
158{
159}
160
161SYSCALL_DEFINE1(c6x_clone, struct pt_regs *, regs)
162{
163 unsigned long clone_flags;
164 unsigned long newsp;
165
166 /* syscall puts clone_flags in A4 and usp in B4 */
167 clone_flags = regs->orig_a4;
168 if (regs->b4)
169 newsp = regs->b4;
170 else
171 newsp = regs->sp;
172
173 return do_fork(clone_flags, newsp, regs, 0, (int __user *)regs->a6,
174 (int __user *)regs->b6);
175}
176
177/*
178 * Do necessary setup to start up a newly executed thread.
179 */
180void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
181{
182 /*
183 * The binfmt loader will setup a "full" stack, but the C6X
184 * operates an "empty" stack. So we adjust the usp so that
185 * argc doesn't get destroyed if an interrupt is taken before
186 * it is read from the stack.
187 *
188 * NB: Library startup code needs to match this.
189 */
190 usp -= 8;
191
192 set_fs(USER_DS);
193 regs->pc = pc;
194 regs->sp = usp;
195 regs->tsr |= 0x40; /* set user mode */
196 current->thread.usp = usp;
197}
198
199/*
200 * Copy a new thread context in its stack.
201 */
202int copy_thread(unsigned long clone_flags, unsigned long usp,
203 unsigned long ustk_size,
204 struct task_struct *p, struct pt_regs *regs)
205{
206 struct pt_regs *childregs;
207
208 childregs = task_pt_regs(p);
209
210 *childregs = *regs;
211 childregs->a4 = 0;
212
213 if (usp == -1)
214 /* case of __kernel_thread: we return to supervisor space */
215 childregs->sp = (unsigned long)(childregs + 1);
216 else
217 /* Otherwise use the given stack */
218 childregs->sp = usp;
219
220 /* Set usp/ksp */
221 p->thread.usp = childregs->sp;
222 /* switch_to uses stack to save/restore 14 callee-saved regs */
223 thread_saved_ksp(p) = (unsigned long)childregs - 8;
224 p->thread.pc = (unsigned int) ret_from_fork;
225 p->thread.wchan = (unsigned long) ret_from_fork;
226#ifdef __DSBT__
227 {
228 unsigned long dp;
229
230 asm volatile ("mv .S2 b14,%0\n" : "=b"(dp));
231
232 thread_saved_dp(p) = dp;
233 if (usp == -1)
234 childregs->dp = dp;
235 }
236#endif
237 return 0;
238}
239
240/*
241 * c6x_execve() executes a new program.
242 */
243SYSCALL_DEFINE4(c6x_execve, const char __user *, name,
244 const char __user *const __user *, argv,
245 const char __user *const __user *, envp,
246 struct pt_regs *, regs)
247{
248 int error;
249 char *filename;
250
251 filename = getname(name);
252 error = PTR_ERR(filename);
253 if (IS_ERR(filename))
254 goto out;
255
256 error = do_execve(filename, argv, envp, regs);
257 putname(filename);
258out:
259 return error;
260}
261
262unsigned long get_wchan(struct task_struct *p)
263{
264 return p->thread.wchan;
265}
diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c
new file mode 100644
index 000000000000..3c494e84444d
--- /dev/null
+++ b/arch/c6x/kernel/ptrace.c
@@ -0,0 +1,187 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Updated for 2.6.34: Mark Salter <msalter@redhat.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#include <linux/ptrace.h>
14#include <linux/tracehook.h>
15#include <linux/regset.h>
16#include <linux/elf.h>
17
18#include <asm/cacheflush.h>
19
20#define PT_REG_SIZE (sizeof(struct pt_regs))
21
22/*
23 * Called by kernel/ptrace.c when detaching.
24 */
25void ptrace_disable(struct task_struct *child)
26{
27 /* nothing to do */
28}
29
30/*
31 * Get a register number from live pt_regs for the specified task.
32 */
33static inline long get_reg(struct task_struct *task, int regno)
34{
35 long *addr = (long *)task_pt_regs(task);
36
37 if (regno == PT_TSR || regno == PT_CSR)
38 return 0;
39
40 return addr[regno];
41}
42
43/*
44 * Write contents of register REGNO in task TASK.
45 */
46static inline int put_reg(struct task_struct *task,
47 int regno,
48 unsigned long data)
49{
50 unsigned long *addr = (unsigned long *)task_pt_regs(task);
51
52 if (regno != PT_TSR && regno != PT_CSR)
53 addr[regno] = data;
54
55 return 0;
56}
57
58/* regset get/set implementations */
59
60static int gpr_get(struct task_struct *target,
61 const struct user_regset *regset,
62 unsigned int pos, unsigned int count,
63 void *kbuf, void __user *ubuf)
64{
65 struct pt_regs *regs = task_pt_regs(target);
66
67 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
68 regs,
69 0, sizeof(*regs));
70}
71
72static int gpr_set(struct task_struct *target,
73 const struct user_regset *regset,
74 unsigned int pos, unsigned int count,
75 const void *kbuf, const void __user *ubuf)
76{
77 int ret;
78 struct pt_regs *regs = task_pt_regs(target);
79
80 /* Don't copyin TSR or CSR */
81 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
82 &regs,
83 0, PT_TSR * sizeof(long));
84 if (ret)
85 return ret;
86
87 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
88 PT_TSR * sizeof(long),
89 (PT_TSR + 1) * sizeof(long));
90 if (ret)
91 return ret;
92
93 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
94 &regs,
95 (PT_TSR + 1) * sizeof(long),
96 PT_CSR * sizeof(long));
97 if (ret)
98 return ret;
99
100 ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
101 PT_CSR * sizeof(long),
102 (PT_CSR + 1) * sizeof(long));
103 if (ret)
104 return ret;
105
106 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
107 &regs,
108 (PT_CSR + 1) * sizeof(long), -1);
109 return ret;
110}
111
112enum c6x_regset {
113 REGSET_GPR,
114};
115
116static const struct user_regset c6x_regsets[] = {
117 [REGSET_GPR] = {
118 .core_note_type = NT_PRSTATUS,
119 .n = ELF_NGREG,
120 .size = sizeof(u32),
121 .align = sizeof(u32),
122 .get = gpr_get,
123 .set = gpr_set
124 },
125};
126
127static const struct user_regset_view user_c6x_native_view = {
128 .name = "tic6x",
129 .e_machine = EM_TI_C6000,
130 .regsets = c6x_regsets,
131 .n = ARRAY_SIZE(c6x_regsets),
132};
133
134const struct user_regset_view *task_user_regset_view(struct task_struct *task)
135{
136 return &user_c6x_native_view;
137}
138
139/*
140 * Perform ptrace request
141 */
142long arch_ptrace(struct task_struct *child, long request,
143 unsigned long addr, unsigned long data)
144{
145 int ret = 0;
146
147 switch (request) {
148 /*
149 * write the word at location addr.
150 */
151 case PTRACE_POKETEXT:
152 ret = generic_ptrace_pokedata(child, addr, data);
153 if (ret == 0 && request == PTRACE_POKETEXT)
154 flush_icache_range(addr, addr + 4);
155 break;
156 default:
157 ret = ptrace_request(child, request, addr, data);
158 break;
159 }
160
161 return ret;
162}
163
164/*
165 * handle tracing of system call entry
166 * - return the revised system call number or ULONG_MAX to cause ENOSYS
167 */
168asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
169{
170 if (tracehook_report_syscall_entry(regs))
171 /* tracing decided this syscall should not happen, so
172 * We'll return a bogus call number to get an ENOSYS
173 * error, but leave the original number in
174 * regs->orig_a4
175 */
176 return ULONG_MAX;
177
178 return regs->b0;
179}
180
181/*
182 * handle tracing of system call exit
183 */
184asmlinkage void syscall_trace_exit(struct pt_regs *regs)
185{
186 tracehook_report_syscall_exit(regs, 0);
187}
diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c
new file mode 100644
index 000000000000..0c07921747f4
--- /dev/null
+++ b/arch/c6x/kernel/setup.c
@@ -0,0 +1,510 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/dma-mapping.h>
12#include <linux/memblock.h>
13#include <linux/seq_file.h>
14#include <linux/bootmem.h>
15#include <linux/clkdev.h>
16#include <linux/initrd.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/of_fdt.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/cache.h>
23#include <linux/delay.h>
24#include <linux/sched.h>
25#include <linux/clk.h>
26#include <linux/cpu.h>
27#include <linux/fs.h>
28#include <linux/of.h>
29
30
31#include <asm/sections.h>
32#include <asm/div64.h>
33#include <asm/setup.h>
34#include <asm/dscr.h>
35#include <asm/clock.h>
36#include <asm/soc.h>
37
38static const char *c6x_soc_name;
39
40int c6x_num_cores;
41EXPORT_SYMBOL_GPL(c6x_num_cores);
42
43unsigned int c6x_silicon_rev;
44EXPORT_SYMBOL_GPL(c6x_silicon_rev);
45
46/*
47 * Device status register. This holds information
48 * about device configuration needed by some drivers.
49 */
50unsigned int c6x_devstat;
51EXPORT_SYMBOL_GPL(c6x_devstat);
52
53/*
54 * Some SoCs have fuse registers holding a unique MAC
55 * address. This is parsed out of the device tree with
56 * the resulting MAC being held here.
57 */
58unsigned char c6x_fuse_mac[6];
59
60unsigned long memory_start;
61unsigned long memory_end;
62
63unsigned long ram_start;
64unsigned long ram_end;
65
66/* Uncached memory for DMA consistent use (memdma=) */
67static unsigned long dma_start __initdata;
68static unsigned long dma_size __initdata;
69
70char c6x_command_line[COMMAND_LINE_SIZE];
71
72#if defined(CONFIG_CMDLINE_BOOL)
73static const char default_command_line[COMMAND_LINE_SIZE] __section(.cmdline) =
74 CONFIG_CMDLINE;
75#endif
76
77struct cpuinfo_c6x {
78 const char *cpu_name;
79 const char *cpu_voltage;
80 const char *mmu;
81 const char *fpu;
82 char *cpu_rev;
83 unsigned int core_id;
84 char __cpu_rev[5];
85};
86
87static DEFINE_PER_CPU(struct cpuinfo_c6x, cpu_data);
88
89unsigned int ticks_per_ns_scaled;
90EXPORT_SYMBOL(ticks_per_ns_scaled);
91
92unsigned int c6x_core_freq;
93
94static void __init get_cpuinfo(void)
95{
96 unsigned cpu_id, rev_id, csr;
97 struct clk *coreclk = clk_get_sys(NULL, "core");
98 unsigned long core_khz;
99 u64 tmp;
100 struct cpuinfo_c6x *p;
101 struct device_node *node, *np;
102
103 p = &per_cpu(cpu_data, smp_processor_id());
104
105 if (!IS_ERR(coreclk))
106 c6x_core_freq = clk_get_rate(coreclk);
107 else {
108 printk(KERN_WARNING
109 "Cannot find core clock frequency. Using 700MHz\n");
110 c6x_core_freq = 700000000;
111 }
112
113 core_khz = c6x_core_freq / 1000;
114
115 tmp = (uint64_t)core_khz << C6X_NDELAY_SCALE;
116 do_div(tmp, 1000000);
117 ticks_per_ns_scaled = tmp;
118
119 csr = get_creg(CSR);
120 cpu_id = csr >> 24;
121 rev_id = (csr >> 16) & 0xff;
122
123 p->mmu = "none";
124 p->fpu = "none";
125 p->cpu_voltage = "unknown";
126
127 switch (cpu_id) {
128 case 0:
129 p->cpu_name = "C67x";
130 p->fpu = "yes";
131 break;
132 case 2:
133 p->cpu_name = "C62x";
134 break;
135 case 8:
136 p->cpu_name = "C64x";
137 break;
138 case 12:
139 p->cpu_name = "C64x";
140 break;
141 case 16:
142 p->cpu_name = "C64x+";
143 p->cpu_voltage = "1.2";
144 break;
145 default:
146 p->cpu_name = "unknown";
147 break;
148 }
149
150 if (cpu_id < 16) {
151 switch (rev_id) {
152 case 0x1:
153 if (cpu_id > 8) {
154 p->cpu_rev = "DM640/DM641/DM642/DM643";
155 p->cpu_voltage = "1.2 - 1.4";
156 } else {
157 p->cpu_rev = "C6201";
158 p->cpu_voltage = "2.5";
159 }
160 break;
161 case 0x2:
162 p->cpu_rev = "C6201B/C6202/C6211";
163 p->cpu_voltage = "1.8";
164 break;
165 case 0x3:
166 p->cpu_rev = "C6202B/C6203/C6204/C6205";
167 p->cpu_voltage = "1.5";
168 break;
169 case 0x201:
170 p->cpu_rev = "C6701 revision 0 (early CPU)";
171 p->cpu_voltage = "1.8";
172 break;
173 case 0x202:
174 p->cpu_rev = "C6701/C6711/C6712";
175 p->cpu_voltage = "1.8";
176 break;
177 case 0x801:
178 p->cpu_rev = "C64x";
179 p->cpu_voltage = "1.5";
180 break;
181 default:
182 p->cpu_rev = "unknown";
183 }
184 } else {
185 p->cpu_rev = p->__cpu_rev;
186 snprintf(p->__cpu_rev, sizeof(p->__cpu_rev), "0x%x", cpu_id);
187 }
188
189 p->core_id = get_coreid();
190
191 node = of_find_node_by_name(NULL, "cpus");
192 if (node) {
193 for_each_child_of_node(node, np)
194 if (!strcmp("cpu", np->name))
195 ++c6x_num_cores;
196 of_node_put(node);
197 }
198
199 node = of_find_node_by_name(NULL, "soc");
200 if (node) {
201 if (of_property_read_string(node, "model", &c6x_soc_name))
202 c6x_soc_name = "unknown";
203 of_node_put(node);
204 } else
205 c6x_soc_name = "unknown";
206
207 printk(KERN_INFO "CPU%d: %s rev %s, %s volts, %uMHz\n",
208 p->core_id, p->cpu_name, p->cpu_rev,
209 p->cpu_voltage, c6x_core_freq / 1000000);
210}
211
212/*
213 * Early parsing of the command line
214 */
215static u32 mem_size __initdata;
216
217/* "mem=" parsing. */
218static int __init early_mem(char *p)
219{
220 if (!p)
221 return -EINVAL;
222
223 mem_size = memparse(p, &p);
224 /* don't remove all of memory when handling "mem={invalid}" */
225 if (mem_size == 0)
226 return -EINVAL;
227
228 return 0;
229}
230early_param("mem", early_mem);
231
232/* "memdma=<size>[@<address>]" parsing. */
233static int __init early_memdma(char *p)
234{
235 if (!p)
236 return -EINVAL;
237
238 dma_size = memparse(p, &p);
239 if (*p == '@')
240 dma_start = memparse(p, &p);
241
242 return 0;
243}
244early_param("memdma", early_memdma);
245
246int __init c6x_add_memory(phys_addr_t start, unsigned long size)
247{
248 static int ram_found __initdata;
249
250 /* We only handle one bank (the one with PAGE_OFFSET) for now */
251 if (ram_found)
252 return -EINVAL;
253
254 if (start > PAGE_OFFSET || PAGE_OFFSET >= (start + size))
255 return 0;
256
257 ram_start = start;
258 ram_end = start + size;
259
260 ram_found = 1;
261 return 0;
262}
263
264/*
265 * Do early machine setup and device tree parsing. This is called very
266 * early on the boot process.
267 */
268notrace void __init machine_init(unsigned long dt_ptr)
269{
270 struct boot_param_header *dtb = __va(dt_ptr);
271 struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start;
272
273 /* interrupts must be masked */
274 set_creg(IER, 2);
275
276 /*
277 * Set the Interrupt Service Table (IST) to the beginning of the
278 * vector table.
279 */
280 set_ist(_vectors_start);
281
282 lockdep_init();
283
284 /*
285 * dtb is passed in from bootloader.
286 * fdt is linked in blob.
287 */
288 if (dtb && dtb != fdt)
289 fdt = dtb;
290
291 /* Do some early initialization based on the flat device tree */
292 early_init_devtree(fdt);
293
294 /* parse_early_param needs a boot_command_line */
295 strlcpy(boot_command_line, c6x_command_line, COMMAND_LINE_SIZE);
296 parse_early_param();
297}
298
299void __init setup_arch(char **cmdline_p)
300{
301 int bootmap_size;
302 struct memblock_region *reg;
303
304 printk(KERN_INFO "Initializing kernel\n");
305
306 /* Initialize command line */
307 *cmdline_p = c6x_command_line;
308
309 memory_end = ram_end;
310 memory_end &= ~(PAGE_SIZE - 1);
311
312 if (mem_size && (PAGE_OFFSET + PAGE_ALIGN(mem_size)) < memory_end)
313 memory_end = PAGE_OFFSET + PAGE_ALIGN(mem_size);
314
315 /* add block that this kernel can use */
316 memblock_add(PAGE_OFFSET, memory_end - PAGE_OFFSET);
317
318 /* reserve kernel text/data/bss */
319 memblock_reserve(PAGE_OFFSET,
320 PAGE_ALIGN((unsigned long)&_end - PAGE_OFFSET));
321
322 if (dma_size) {
323 /* align to cacheability granularity */
324 dma_size = CACHE_REGION_END(dma_size);
325
326 if (!dma_start)
327 dma_start = memory_end - dma_size;
328
329 /* align to cacheability granularity */
330 dma_start = CACHE_REGION_START(dma_start);
331
332 /* reserve DMA memory taken from kernel memory */
333 if (memblock_is_region_memory(dma_start, dma_size))
334 memblock_reserve(dma_start, dma_size);
335 }
336
337 memory_start = PAGE_ALIGN((unsigned int) &_end);
338
339 printk(KERN_INFO "Memory Start=%08lx, Memory End=%08lx\n",
340 memory_start, memory_end);
341
342#ifdef CONFIG_BLK_DEV_INITRD
343 /*
344 * Reserve initrd memory if in kernel memory.
345 */
346 if (initrd_start < initrd_end)
347 if (memblock_is_region_memory(initrd_start,
348 initrd_end - initrd_start))
349 memblock_reserve(initrd_start,
350 initrd_end - initrd_start);
351#endif
352
353 init_mm.start_code = (unsigned long) &_stext;
354 init_mm.end_code = (unsigned long) &_etext;
355 init_mm.end_data = memory_start;
356 init_mm.brk = memory_start;
357
358 /*
359 * Give all the memory to the bootmap allocator, tell it to put the
360 * boot mem_map at the start of memory
361 */
362 bootmap_size = init_bootmem_node(NODE_DATA(0),
363 memory_start >> PAGE_SHIFT,
364 PAGE_OFFSET >> PAGE_SHIFT,
365 memory_end >> PAGE_SHIFT);
366 memblock_reserve(memory_start, bootmap_size);
367
368 unflatten_device_tree();
369
370 c6x_cache_init();
371
372 /* Set the whole external memory as non-cacheable */
373 disable_caching(ram_start, ram_end - 1);
374
375 /* Set caching of external RAM used by Linux */
376 for_each_memblock(memory, reg)
377 enable_caching(CACHE_REGION_START(reg->base),
378 CACHE_REGION_START(reg->base + reg->size - 1));
379
380#ifdef CONFIG_BLK_DEV_INITRD
381 /*
382 * Enable caching for initrd which falls outside kernel memory.
383 */
384 if (initrd_start < initrd_end) {
385 if (!memblock_is_region_memory(initrd_start,
386 initrd_end - initrd_start))
387 enable_caching(CACHE_REGION_START(initrd_start),
388 CACHE_REGION_START(initrd_end - 1));
389 }
390#endif
391
392 /*
393 * Disable caching for dma coherent memory taken from kernel memory.
394 */
395 if (dma_size && memblock_is_region_memory(dma_start, dma_size))
396 disable_caching(dma_start,
397 CACHE_REGION_START(dma_start + dma_size - 1));
398
399 /* Initialize the coherent memory allocator */
400 coherent_mem_init(dma_start, dma_size);
401
402 /*
403 * Free all memory as a starting point.
404 */
405 free_bootmem(PAGE_OFFSET, memory_end - PAGE_OFFSET);
406
407 /*
408 * Then reserve memory which is already being used.
409 */
410 for_each_memblock(reserved, reg) {
411 pr_debug("reserved - 0x%08x-0x%08x\n",
412 (u32) reg->base, (u32) reg->size);
413 reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
414 }
415
416 max_low_pfn = PFN_DOWN(memory_end);
417 min_low_pfn = PFN_UP(memory_start);
418 max_mapnr = max_low_pfn - min_low_pfn;
419
420 /* Get kmalloc into gear */
421 paging_init();
422
423 /*
424 * Probe for Device State Configuration Registers.
425 * We have to do this early in case timer needs to be enabled
426 * through DSCR.
427 */
428 dscr_probe();
429
430 /* We do this early for timer and core clock frequency */
431 c64x_setup_clocks();
432
433 /* Get CPU info */
434 get_cpuinfo();
435
436#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
437 conswitchp = &dummy_con;
438#endif
439}
440
441#define cpu_to_ptr(n) ((void *)((long)(n)+1))
442#define ptr_to_cpu(p) ((long)(p) - 1)
443
444static int show_cpuinfo(struct seq_file *m, void *v)
445{
446 int n = ptr_to_cpu(v);
447 struct cpuinfo_c6x *p = &per_cpu(cpu_data, n);
448
449 if (n == 0) {
450 seq_printf(m,
451 "soc\t\t: %s\n"
452 "soc revision\t: 0x%x\n"
453 "soc cores\t: %d\n",
454 c6x_soc_name, c6x_silicon_rev, c6x_num_cores);
455 }
456
457 seq_printf(m,
458 "\n"
459 "processor\t: %d\n"
460 "cpu\t\t: %s\n"
461 "core revision\t: %s\n"
462 "core voltage\t: %s\n"
463 "core id\t\t: %d\n"
464 "mmu\t\t: %s\n"
465 "fpu\t\t: %s\n"
466 "cpu MHz\t\t: %u\n"
467 "bogomips\t: %lu.%02lu\n\n",
468 n,
469 p->cpu_name, p->cpu_rev, p->cpu_voltage,
470 p->core_id, p->mmu, p->fpu,
471 (c6x_core_freq + 500000) / 1000000,
472 (loops_per_jiffy/(500000/HZ)),
473 (loops_per_jiffy/(5000/HZ))%100);
474
475 return 0;
476}
477
478static void *c_start(struct seq_file *m, loff_t *pos)
479{
480 return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
481}
482static void *c_next(struct seq_file *m, void *v, loff_t *pos)
483{
484 ++*pos;
485 return NULL;
486}
487static void c_stop(struct seq_file *m, void *v)
488{
489}
490
491const struct seq_operations cpuinfo_op = {
492 c_start,
493 c_stop,
494 c_next,
495 show_cpuinfo
496};
497
498static struct cpu cpu_devices[NR_CPUS];
499
500static int __init topology_init(void)
501{
502 int i;
503
504 for_each_present_cpu(i)
505 register_cpu(&cpu_devices[i], i);
506
507 return 0;
508}
509
510subsys_initcall(topology_init);
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
new file mode 100644
index 000000000000..304f675826e9
--- /dev/null
+++ b/arch/c6x/kernel/signal.c
@@ -0,0 +1,377 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * Updated for 2.6.34: Mark Salter <msalter@redhat.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#include <linux/kernel.h>
15#include <linux/uaccess.h>
16#include <linux/syscalls.h>
17#include <linux/tracehook.h>
18
19#include <asm/ucontext.h>
20#include <asm/cacheflush.h>
21
22
23#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
24
25/*
26 * Do a signal return, undo the signal stack.
27 */
28
29#define RETCODE_SIZE (9 << 2) /* 9 instructions = 36 bytes */
30
31struct rt_sigframe {
32 struct siginfo __user *pinfo;
33 void __user *puc;
34 struct siginfo info;
35 struct ucontext uc;
36 unsigned long retcode[RETCODE_SIZE >> 2];
37};
38
39static int restore_sigcontext(struct pt_regs *regs,
40 struct sigcontext __user *sc)
41{
42 int err = 0;
43
44 /* The access_ok check was done by caller, so use __get_user here */
45#define COPY(x) (err |= __get_user(regs->x, &sc->sc_##x))
46
47 COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
48 COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
49 COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
50
51 COPY(a16); COPY(a17); COPY(a18); COPY(a19);
52 COPY(a20); COPY(a21); COPY(a22); COPY(a23);
53 COPY(a24); COPY(a25); COPY(a26); COPY(a27);
54 COPY(a28); COPY(a29); COPY(a30); COPY(a31);
55 COPY(b16); COPY(b17); COPY(b18); COPY(b19);
56 COPY(b20); COPY(b21); COPY(b22); COPY(b23);
57 COPY(b24); COPY(b25); COPY(b26); COPY(b27);
58 COPY(b28); COPY(b29); COPY(b30); COPY(b31);
59
60 COPY(csr); COPY(pc);
61
62#undef COPY
63
64 return err;
65}
66
67asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
68{
69 struct rt_sigframe __user *frame;
70 sigset_t set;
71
72 /*
73 * Since we stacked the signal on a dword boundary,
74 * 'sp' should be dword aligned here. If it's
75 * not, then the user is trying to mess with us.
76 */
77 if (regs->sp & 7)
78 goto badframe;
79
80 frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8);
81
82 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
83 goto badframe;
84 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
85 goto badframe;
86
87 sigdelsetmask(&set, ~_BLOCKABLE);
88 spin_lock_irq(&current->sighand->siglock);
89 current->blocked = set;
90 recalc_sigpending();
91 spin_unlock_irq(&current->sighand->siglock);
92
93 if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
94 goto badframe;
95
96 return regs->a4;
97
98badframe:
99 force_sig(SIGSEGV, current);
100 return 0;
101}
102
103static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
104 unsigned long mask)
105{
106 int err = 0;
107
108 err |= __put_user(mask, &sc->sc_mask);
109
110 /* The access_ok check was done by caller, so use __put_user here */
111#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x))
112
113 COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
114 COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
115 COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
116
117 COPY(a16); COPY(a17); COPY(a18); COPY(a19);
118 COPY(a20); COPY(a21); COPY(a22); COPY(a23);
119 COPY(a24); COPY(a25); COPY(a26); COPY(a27);
120 COPY(a28); COPY(a29); COPY(a30); COPY(a31);
121 COPY(b16); COPY(b17); COPY(b18); COPY(b19);
122 COPY(b20); COPY(b21); COPY(b22); COPY(b23);
123 COPY(b24); COPY(b25); COPY(b26); COPY(b27);
124 COPY(b28); COPY(b29); COPY(b30); COPY(b31);
125
126 COPY(csr); COPY(pc);
127
128#undef COPY
129
130 return err;
131}
132
133static inline void __user *get_sigframe(struct k_sigaction *ka,
134 struct pt_regs *regs,
135 unsigned long framesize)
136{
137 unsigned long sp = regs->sp;
138
139 /*
140 * This is the X/Open sanctioned signal stack switching.
141 */
142 if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp) == 0)
143 sp = current->sas_ss_sp + current->sas_ss_size;
144
145 /*
146 * No matter what happens, 'sp' must be dword
147 * aligned. Otherwise, nasty things will happen
148 */
149 return (void __user *)((sp - framesize) & ~7);
150}
151
152static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
153 sigset_t *set, struct pt_regs *regs)
154{
155 struct rt_sigframe __user *frame;
156 unsigned long __user *retcode;
157 int err = 0;
158
159 frame = get_sigframe(ka, regs, sizeof(*frame));
160
161 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
162 goto segv_and_exit;
163
164 err |= __put_user(&frame->info, &frame->pinfo);
165 err |= __put_user(&frame->uc, &frame->puc);
166 err |= copy_siginfo_to_user(&frame->info, info);
167
168 /* Clear all the bits of the ucontext we don't use. */
169 err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
170
171 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
172 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
173
174 /* Set up to return from userspace */
175 retcode = (unsigned long __user *) &frame->retcode;
176
177 /* The access_ok check was done above, so use __put_user here */
178#define COPY(x) (err |= __put_user(x, retcode++))
179
180 COPY(0x0000002AUL | (__NR_rt_sigreturn << 7));
181 /* MVK __NR_rt_sigreturn,B0 */
182 COPY(0x10000000UL); /* SWE */
183 COPY(0x00006000UL); /* NOP 4 */
184 COPY(0x00006000UL); /* NOP 4 */
185 COPY(0x00006000UL); /* NOP 4 */
186 COPY(0x00006000UL); /* NOP 4 */
187 COPY(0x00006000UL); /* NOP 4 */
188 COPY(0x00006000UL); /* NOP 4 */
189 COPY(0x00006000UL); /* NOP 4 */
190
191#undef COPY
192
193 if (err)
194 goto segv_and_exit;
195
196 flush_icache_range((unsigned long) &frame->retcode,
197 (unsigned long) &frame->retcode + RETCODE_SIZE);
198
199 retcode = (unsigned long __user *) &frame->retcode;
200
201 /* Change user context to branch to signal handler */
202 regs->sp = (unsigned long) frame - 8;
203 regs->b3 = (unsigned long) retcode;
204 regs->pc = (unsigned long) ka->sa.sa_handler;
205
206 /* Give the signal number to the handler */
207 regs->a4 = signr;
208
209 /*
210 * For realtime signals we must also set the second and third
211 * arguments for the signal handler.
212 * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
213 */
214 regs->b4 = (unsigned long)&frame->info;
215 regs->a6 = (unsigned long)&frame->uc;
216
217 return 0;
218
219segv_and_exit:
220 force_sigsegv(signr, current);
221 return -EFAULT;
222}
223
224static inline void
225handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
226{
227 switch (regs->a4) {
228 case -ERESTARTNOHAND:
229 if (!has_handler)
230 goto do_restart;
231 regs->a4 = -EINTR;
232 break;
233
234 case -ERESTARTSYS:
235 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
236 regs->a4 = -EINTR;
237 break;
238 }
239 /* fallthrough */
240 case -ERESTARTNOINTR:
241do_restart:
242 regs->a4 = regs->orig_a4;
243 regs->pc -= 4;
244 break;
245 }
246}
247
248/*
249 * handle the actual delivery of a signal to userspace
250 */
251static int handle_signal(int sig,
252 siginfo_t *info, struct k_sigaction *ka,
253 sigset_t *oldset, struct pt_regs *regs,
254 int syscall)
255{
256 int ret;
257
258 /* Are we from a system call? */
259 if (syscall) {
260 /* If so, check system call restarting.. */
261 switch (regs->a4) {
262 case -ERESTART_RESTARTBLOCK:
263 case -ERESTARTNOHAND:
264 regs->a4 = -EINTR;
265 break;
266
267 case -ERESTARTSYS:
268 if (!(ka->sa.sa_flags & SA_RESTART)) {
269 regs->a4 = -EINTR;
270 break;
271 }
272
273 /* fallthrough */
274 case -ERESTARTNOINTR:
275 regs->a4 = regs->orig_a4;
276 regs->pc -= 4;
277 }
278 }
279
280 /* Set up the stack frame */
281 ret = setup_rt_frame(sig, ka, info, oldset, regs);
282 if (ret == 0) {
283 spin_lock_irq(&current->sighand->siglock);
284 sigorsets(&current->blocked, &current->blocked,
285 &ka->sa.sa_mask);
286 if (!(ka->sa.sa_flags & SA_NODEFER))
287 sigaddset(&current->blocked, sig);
288 recalc_sigpending();
289 spin_unlock_irq(&current->sighand->siglock);
290 }
291
292 return ret;
293}
294
295/*
296 * handle a potential signal
297 */
298static void do_signal(struct pt_regs *regs, int syscall)
299{
300 struct k_sigaction ka;
301 siginfo_t info;
302 sigset_t *oldset;
303 int signr;
304
305 /* we want the common case to go fast, which is why we may in certain
306 * cases get here from kernel mode */
307 if (!user_mode(regs))
308 return;
309
310 if (test_thread_flag(TIF_RESTORE_SIGMASK))
311 oldset = &current->saved_sigmask;
312 else
313 oldset = &current->blocked;
314
315 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
316 if (signr > 0) {
317 if (handle_signal(signr, &info, &ka, oldset,
318 regs, syscall) == 0) {
319 /* a signal was successfully delivered; the saved
320 * sigmask will have been stored in the signal frame,
321 * and will be restored by sigreturn, so we can simply
322 * clear the TIF_RESTORE_SIGMASK flag */
323 if (test_thread_flag(TIF_RESTORE_SIGMASK))
324 clear_thread_flag(TIF_RESTORE_SIGMASK);
325
326 tracehook_signal_handler(signr, &info, &ka, regs, 0);
327 }
328
329 return;
330 }
331
332 /* did we come from a system call? */
333 if (syscall) {
334 /* restart the system call - no handlers present */
335 switch (regs->a4) {
336 case -ERESTARTNOHAND:
337 case -ERESTARTSYS:
338 case -ERESTARTNOINTR:
339 regs->a4 = regs->orig_a4;
340 regs->pc -= 4;
341 break;
342
343 case -ERESTART_RESTARTBLOCK:
344 regs->a4 = regs->orig_a4;
345 regs->b0 = __NR_restart_syscall;
346 regs->pc -= 4;
347 break;
348 }
349 }
350
351 /* if there's no signal to deliver, we just put the saved sigmask
352 * back */
353 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
354 clear_thread_flag(TIF_RESTORE_SIGMASK);
355 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
356 }
357}
358
359/*
360 * notification of userspace execution resumption
361 * - triggered by current->work.notify_resume
362 */
363asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
364 int syscall)
365{
366 /* deal with pending signal delivery */
367 if (thread_info_flags & ((1 << TIF_SIGPENDING) |
368 (1 << TIF_RESTORE_SIGMASK)))
369 do_signal(regs, syscall);
370
371 if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
372 clear_thread_flag(TIF_NOTIFY_RESUME);
373 tracehook_notify_resume(regs);
374 if (current->replacement_session_keyring)
375 key_replace_session_keyring();
376 }
377}
diff --git a/arch/c6x/kernel/soc.c b/arch/c6x/kernel/soc.c
new file mode 100644
index 000000000000..dd45bc39af0e
--- /dev/null
+++ b/arch/c6x/kernel/soc.c
@@ -0,0 +1,91 @@
1/*
2 * Miscellaneous SoC-specific hooks.
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/ctype.h>
13#include <linux/etherdevice.h>
14#include <asm/system.h>
15#include <asm/setup.h>
16#include <asm/soc.h>
17
18struct soc_ops soc_ops;
19
20int soc_get_exception(void)
21{
22 if (!soc_ops.get_exception)
23 return -1;
24 return soc_ops.get_exception();
25}
26
27void soc_assert_event(unsigned int evt)
28{
29 if (soc_ops.assert_event)
30 soc_ops.assert_event(evt);
31}
32
33static u8 cmdline_mac[6];
34
35static int __init get_mac_addr_from_cmdline(char *str)
36{
37 int count, i, val;
38
39 for (count = 0; count < 6 && *str; count++, str += 3) {
40 if (!isxdigit(str[0]) || !isxdigit(str[1]))
41 return 0;
42 if (str[2] != ((count < 5) ? ':' : '\0'))
43 return 0;
44
45 for (i = 0, val = 0; i < 2; i++) {
46 val = val << 4;
47 val |= isdigit(str[i]) ?
48 str[i] - '0' : toupper(str[i]) - 'A' + 10;
49 }
50 cmdline_mac[count] = val;
51 }
52 return 1;
53}
54__setup("emac_addr=", get_mac_addr_from_cmdline);
55
56/*
57 * Setup the MAC address for SoC ethernet devices.
58 *
59 * Before calling this function, the ethernet driver will have
60 * initialized the addr with local-mac-address from the device
61 * tree (if found). Allow command line to override, but not
62 * the fused address.
63 */
64int soc_mac_addr(unsigned int index, u8 *addr)
65{
66 int i, have_dt_mac = 0, have_cmdline_mac = 0, have_fuse_mac = 0;
67
68 for (i = 0; i < 6; i++) {
69 if (cmdline_mac[i])
70 have_cmdline_mac = 1;
71 if (c6x_fuse_mac[i])
72 have_fuse_mac = 1;
73 if (addr[i])
74 have_dt_mac = 1;
75 }
76
77 /* cmdline overrides all */
78 if (have_cmdline_mac)
79 memcpy(addr, cmdline_mac, 6);
80 else if (!have_dt_mac) {
81 if (have_fuse_mac)
82 memcpy(addr, c6x_fuse_mac, 6);
83 else
84 random_ether_addr(addr);
85 }
86
87 /* adjust for specific EMAC device */
88 addr[5] += index * c6x_num_cores;
89 return 1;
90}
91EXPORT_SYMBOL_GPL(soc_mac_addr);
diff --git a/arch/c6x/kernel/switch_to.S b/arch/c6x/kernel/switch_to.S
new file mode 100644
index 000000000000..09177ed0fa5c
--- /dev/null
+++ b/arch/c6x/kernel/switch_to.S
@@ -0,0 +1,74 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter (msalter@redhat.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/linkage.h>
11#include <asm/asm-offsets.h>
12
13#define SP B15
14
15 /*
16 * void __switch_to(struct thread_info *prev,
17 * struct thread_info *next,
18 * struct task_struct *tsk) ;
19 */
20ENTRY(__switch_to)
21 LDDW .D2T2 *+B4(THREAD_B15_14),B7:B6
22 || MV .L2X A4,B5 ; prev
23 || MV .L1X B4,A5 ; next
24 || MVC .S2 RILC,B1
25
26 STW .D2T2 B3,*+B5(THREAD_PC)
27 || STDW .D1T1 A13:A12,*+A4(THREAD_A13_12)
28 || MVC .S2 ILC,B0
29
30 LDW .D2T2 *+B4(THREAD_PC),B3
31 || LDDW .D1T1 *+A5(THREAD_A13_12),A13:A12
32
33 STDW .D1T1 A11:A10,*+A4(THREAD_A11_10)
34 || STDW .D2T2 B1:B0,*+B5(THREAD_RICL_ICL)
35#ifndef __DSBT__
36 || MVKL .S2 current_ksp,B1
37#endif
38
39 STDW .D2T2 B15:B14,*+B5(THREAD_B15_14)
40 || STDW .D1T1 A15:A14,*+A4(THREAD_A15_14)
41#ifndef __DSBT__
42 || MVKH .S2 current_ksp,B1
43#endif
44
45 ;; Switch to next SP
46 MV .S2 B7,SP
47#ifdef __DSBT__
48 || STW .D2T2 B7,*+B14(current_ksp)
49#else
50 || STW .D2T2 B7,*B1
51 || MV .L2 B6,B14
52#endif
53 || LDDW .D1T1 *+A5(THREAD_RICL_ICL),A1:A0
54
55 STDW .D2T2 B11:B10,*+B5(THREAD_B11_10)
56 || LDDW .D1T1 *+A5(THREAD_A15_14),A15:A14
57
58 STDW .D2T2 B13:B12,*+B5(THREAD_B13_12)
59 || LDDW .D1T1 *+A5(THREAD_A11_10),A11:A10
60
61 B .S2 B3 ; return in next E1
62 || LDDW .D2T2 *+B4(THREAD_B13_12),B13:B12
63
64 LDDW .D2T2 *+B4(THREAD_B11_10),B11:B10
65 NOP
66
67 MV .L2X A0,B0
68 || MV .S1 A6,A4
69
70 MVC .S2 B0,ILC
71 || MV .L2X A1,B1
72
73 MVC .S2 B1,RILC
74ENDPROC(__switch_to)
diff --git a/arch/c6x/kernel/sys_c6x.c b/arch/c6x/kernel/sys_c6x.c
new file mode 100644
index 000000000000..3e9bdfbee8ad
--- /dev/null
+++ b/arch/c6x/kernel/sys_c6x.c
@@ -0,0 +1,74 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/syscalls.h>
13#include <linux/uaccess.h>
14
15#include <asm/syscalls.h>
16
17#ifdef CONFIG_ACCESS_CHECK
18int _access_ok(unsigned long addr, unsigned long size)
19{
20 if (!size)
21 return 1;
22
23 if (!addr || addr > (0xffffffffUL - (size - 1)))
24 goto _bad_access;
25
26 if (segment_eq(get_fs(), KERNEL_DS))
27 return 1;
28
29 if (memory_start <= addr && (addr + size - 1) < memory_end)
30 return 1;
31
32_bad_access:
33 pr_debug("Bad access attempt: pid[%d] addr[%08lx] size[0x%lx]\n",
34 current->pid, addr, size);
35 return 0;
36}
37EXPORT_SYMBOL(_access_ok);
38#endif
39
40/* sys_cache_sync -- sync caches over given range */
41asmlinkage int sys_cache_sync(unsigned long s, unsigned long e)
42{
43 L1D_cache_block_writeback_invalidate(s, e);
44 L1P_cache_block_invalidate(s, e);
45
46 return 0;
47}
48
49/* Provide the actual syscall number to call mapping. */
50#undef __SYSCALL
51#define __SYSCALL(nr, call) [nr] = (call),
52
53/*
54 * Use trampolines
55 */
56#define sys_pread64 sys_pread_c6x
57#define sys_pwrite64 sys_pwrite_c6x
58#define sys_truncate64 sys_truncate64_c6x
59#define sys_ftruncate64 sys_ftruncate64_c6x
60#define sys_fadvise64 sys_fadvise64_c6x
61#define sys_fadvise64_64 sys_fadvise64_64_c6x
62#define sys_fallocate sys_fallocate_c6x
63
64/* Use sys_mmap_pgoff directly */
65#define sys_mmap2 sys_mmap_pgoff
66
67/*
68 * Note that we can't include <linux/unistd.h> here since the header
69 * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
70 */
71void *sys_call_table[__NR_syscalls] = {
72 [0 ... __NR_syscalls-1] = sys_ni_syscall,
73#include <asm/unistd.h>
74};
diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c
new file mode 100644
index 000000000000..4c9f136165f7
--- /dev/null
+++ b/arch/c6x/kernel/time.c
@@ -0,0 +1,65 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/clocksource.h>
14#include <linux/errno.h>
15#include <linux/sched.h>
16#include <linux/param.h>
17#include <linux/string.h>
18#include <linux/mm.h>
19#include <linux/interrupt.h>
20#include <linux/timex.h>
21#include <linux/profile.h>
22
23#include <asm/timer64.h>
24
25static u32 sched_clock_multiplier;
26#define SCHED_CLOCK_SHIFT 16
27
28static cycle_t tsc_read(struct clocksource *cs)
29{
30 return get_cycles();
31}
32
33static struct clocksource clocksource_tsc = {
34 .name = "timestamp",
35 .rating = 300,
36 .read = tsc_read,
37 .mask = CLOCKSOURCE_MASK(64),
38 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
39};
40
41/*
42 * scheduler clock - returns current time in nanoseconds.
43 */
44u64 sched_clock(void)
45{
46 u64 tsc = get_cycles();
47
48 return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
49}
50
51void time_init(void)
52{
53 u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
54
55 do_div(tmp, c6x_core_freq);
56 sched_clock_multiplier = tmp;
57
58 clocksource_register_hz(&clocksource_tsc, c6x_core_freq);
59
60 /* write anything into TSCL to enable counting */
61 set_creg(TSCL, 0);
62
63 /* probe for timer64 event timer */
64 timer64_init();
65}
diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c
new file mode 100644
index 000000000000..f50e3edd6dad
--- /dev/null
+++ b/arch/c6x/kernel/traps.c
@@ -0,0 +1,423 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/ptrace.h>
13#include <linux/kallsyms.h>
14#include <linux/bug.h>
15
16#include <asm/soc.h>
17#include <asm/traps.h>
18
19int (*c6x_nmi_handler)(struct pt_regs *regs);
20
21void __init trap_init(void)
22{
23 ack_exception(EXCEPT_TYPE_NXF);
24 ack_exception(EXCEPT_TYPE_EXC);
25 ack_exception(EXCEPT_TYPE_IXF);
26 ack_exception(EXCEPT_TYPE_SXF);
27 enable_exception();
28}
29
30void show_regs(struct pt_regs *regs)
31{
32 pr_err("\n");
33 pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp);
34 pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4);
35 pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0);
36 pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1);
37 pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2);
38 pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3);
39 pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4);
40 pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5);
41 pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6);
42 pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7);
43 pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8);
44 pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9);
45 pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10);
46 pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11);
47 pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12);
48 pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13);
49 pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp);
50 pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp);
51 pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16);
52 pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17);
53 pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18);
54 pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19);
55 pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20);
56 pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21);
57 pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22);
58 pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23);
59 pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24);
60 pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25);
61 pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26);
62 pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27);
63 pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28);
64 pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29);
65 pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30);
66 pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31);
67}
68
69void dump_stack(void)
70{
71 unsigned long stack;
72
73 show_stack(current, &stack);
74}
75EXPORT_SYMBOL(dump_stack);
76
77
78void die(char *str, struct pt_regs *fp, int nr)
79{
80 console_verbose();
81 pr_err("%s: %08x\n", str, nr);
82 show_regs(fp);
83
84 pr_err("Process %s (pid: %d, stackpage=%08lx)\n",
85 current->comm, current->pid, (PAGE_SIZE +
86 (unsigned long) current));
87
88 dump_stack();
89 while (1)
90 ;
91}
92
93static void die_if_kernel(char *str, struct pt_regs *fp, int nr)
94{
95 if (user_mode(fp))
96 return;
97
98 die(str, fp, nr);
99}
100
101
102/* Internal exceptions */
103static struct exception_info iexcept_table[10] = {
104 { "Oops - instruction fetch", SIGBUS, BUS_ADRERR },
105 { "Oops - fetch packet", SIGBUS, BUS_ADRERR },
106 { "Oops - execute packet", SIGILL, ILL_ILLOPC },
107 { "Oops - undefined instruction", SIGILL, ILL_ILLOPC },
108 { "Oops - resource conflict", SIGILL, ILL_ILLOPC },
109 { "Oops - resource access", SIGILL, ILL_PRVREG },
110 { "Oops - privilege", SIGILL, ILL_PRVOPC },
111 { "Oops - loops buffer", SIGILL, ILL_ILLOPC },
112 { "Oops - software exception", SIGILL, ILL_ILLTRP },
113 { "Oops - unknown exception", SIGILL, ILL_ILLOPC }
114};
115
116/* External exceptions */
117static struct exception_info eexcept_table[128] = {
118 { "Oops - external exception", SIGBUS, BUS_ADRERR },
119 { "Oops - external exception", SIGBUS, BUS_ADRERR },
120 { "Oops - external exception", SIGBUS, BUS_ADRERR },
121 { "Oops - external exception", SIGBUS, BUS_ADRERR },
122 { "Oops - external exception", SIGBUS, BUS_ADRERR },
123 { "Oops - external exception", SIGBUS, BUS_ADRERR },
124 { "Oops - external exception", SIGBUS, BUS_ADRERR },
125 { "Oops - external exception", SIGBUS, BUS_ADRERR },
126 { "Oops - external exception", SIGBUS, BUS_ADRERR },
127 { "Oops - external exception", SIGBUS, BUS_ADRERR },
128 { "Oops - external exception", SIGBUS, BUS_ADRERR },
129 { "Oops - external exception", SIGBUS, BUS_ADRERR },
130 { "Oops - external exception", SIGBUS, BUS_ADRERR },
131 { "Oops - external exception", SIGBUS, BUS_ADRERR },
132 { "Oops - external exception", SIGBUS, BUS_ADRERR },
133 { "Oops - external exception", SIGBUS, BUS_ADRERR },
134 { "Oops - external exception", SIGBUS, BUS_ADRERR },
135 { "Oops - external exception", SIGBUS, BUS_ADRERR },
136 { "Oops - external exception", SIGBUS, BUS_ADRERR },
137 { "Oops - external exception", SIGBUS, BUS_ADRERR },
138 { "Oops - external exception", SIGBUS, BUS_ADRERR },
139 { "Oops - external exception", SIGBUS, BUS_ADRERR },
140 { "Oops - external exception", SIGBUS, BUS_ADRERR },
141 { "Oops - external exception", SIGBUS, BUS_ADRERR },
142 { "Oops - external exception", SIGBUS, BUS_ADRERR },
143 { "Oops - external exception", SIGBUS, BUS_ADRERR },
144 { "Oops - external exception", SIGBUS, BUS_ADRERR },
145 { "Oops - external exception", SIGBUS, BUS_ADRERR },
146 { "Oops - external exception", SIGBUS, BUS_ADRERR },
147 { "Oops - external exception", SIGBUS, BUS_ADRERR },
148 { "Oops - external exception", SIGBUS, BUS_ADRERR },
149 { "Oops - external exception", SIGBUS, BUS_ADRERR },
150
151 { "Oops - external exception", SIGBUS, BUS_ADRERR },
152 { "Oops - external exception", SIGBUS, BUS_ADRERR },
153 { "Oops - external exception", SIGBUS, BUS_ADRERR },
154 { "Oops - external exception", SIGBUS, BUS_ADRERR },
155 { "Oops - external exception", SIGBUS, BUS_ADRERR },
156 { "Oops - external exception", SIGBUS, BUS_ADRERR },
157 { "Oops - external exception", SIGBUS, BUS_ADRERR },
158 { "Oops - external exception", SIGBUS, BUS_ADRERR },
159 { "Oops - external exception", SIGBUS, BUS_ADRERR },
160 { "Oops - external exception", SIGBUS, BUS_ADRERR },
161 { "Oops - external exception", SIGBUS, BUS_ADRERR },
162 { "Oops - external exception", SIGBUS, BUS_ADRERR },
163 { "Oops - external exception", SIGBUS, BUS_ADRERR },
164 { "Oops - external exception", SIGBUS, BUS_ADRERR },
165 { "Oops - external exception", SIGBUS, BUS_ADRERR },
166 { "Oops - external exception", SIGBUS, BUS_ADRERR },
167 { "Oops - external exception", SIGBUS, BUS_ADRERR },
168 { "Oops - external exception", SIGBUS, BUS_ADRERR },
169 { "Oops - external exception", SIGBUS, BUS_ADRERR },
170 { "Oops - external exception", SIGBUS, BUS_ADRERR },
171 { "Oops - external exception", SIGBUS, BUS_ADRERR },
172 { "Oops - external exception", SIGBUS, BUS_ADRERR },
173 { "Oops - external exception", SIGBUS, BUS_ADRERR },
174 { "Oops - external exception", SIGBUS, BUS_ADRERR },
175 { "Oops - external exception", SIGBUS, BUS_ADRERR },
176 { "Oops - external exception", SIGBUS, BUS_ADRERR },
177 { "Oops - external exception", SIGBUS, BUS_ADRERR },
178 { "Oops - external exception", SIGBUS, BUS_ADRERR },
179 { "Oops - external exception", SIGBUS, BUS_ADRERR },
180 { "Oops - external exception", SIGBUS, BUS_ADRERR },
181 { "Oops - external exception", SIGBUS, BUS_ADRERR },
182 { "Oops - external exception", SIGBUS, BUS_ADRERR },
183
184 { "Oops - external exception", SIGBUS, BUS_ADRERR },
185 { "Oops - external exception", SIGBUS, BUS_ADRERR },
186 { "Oops - external exception", SIGBUS, BUS_ADRERR },
187 { "Oops - external exception", SIGBUS, BUS_ADRERR },
188 { "Oops - external exception", SIGBUS, BUS_ADRERR },
189 { "Oops - external exception", SIGBUS, BUS_ADRERR },
190 { "Oops - external exception", SIGBUS, BUS_ADRERR },
191 { "Oops - external exception", SIGBUS, BUS_ADRERR },
192 { "Oops - external exception", SIGBUS, BUS_ADRERR },
193 { "Oops - external exception", SIGBUS, BUS_ADRERR },
194 { "Oops - external exception", SIGBUS, BUS_ADRERR },
195 { "Oops - external exception", SIGBUS, BUS_ADRERR },
196 { "Oops - external exception", SIGBUS, BUS_ADRERR },
197 { "Oops - external exception", SIGBUS, BUS_ADRERR },
198 { "Oops - external exception", SIGBUS, BUS_ADRERR },
199 { "Oops - external exception", SIGBUS, BUS_ADRERR },
200 { "Oops - external exception", SIGBUS, BUS_ADRERR },
201 { "Oops - external exception", SIGBUS, BUS_ADRERR },
202 { "Oops - external exception", SIGBUS, BUS_ADRERR },
203 { "Oops - external exception", SIGBUS, BUS_ADRERR },
204 { "Oops - external exception", SIGBUS, BUS_ADRERR },
205 { "Oops - external exception", SIGBUS, BUS_ADRERR },
206 { "Oops - external exception", SIGBUS, BUS_ADRERR },
207 { "Oops - external exception", SIGBUS, BUS_ADRERR },
208 { "Oops - external exception", SIGBUS, BUS_ADRERR },
209 { "Oops - external exception", SIGBUS, BUS_ADRERR },
210 { "Oops - external exception", SIGBUS, BUS_ADRERR },
211 { "Oops - external exception", SIGBUS, BUS_ADRERR },
212 { "Oops - external exception", SIGBUS, BUS_ADRERR },
213 { "Oops - external exception", SIGBUS, BUS_ADRERR },
214 { "Oops - external exception", SIGBUS, BUS_ADRERR },
215 { "Oops - external exception", SIGBUS, BUS_ADRERR },
216
217 { "Oops - external exception", SIGBUS, BUS_ADRERR },
218 { "Oops - external exception", SIGBUS, BUS_ADRERR },
219 { "Oops - external exception", SIGBUS, BUS_ADRERR },
220 { "Oops - external exception", SIGBUS, BUS_ADRERR },
221 { "Oops - external exception", SIGBUS, BUS_ADRERR },
222 { "Oops - external exception", SIGBUS, BUS_ADRERR },
223 { "Oops - external exception", SIGBUS, BUS_ADRERR },
224 { "Oops - external exception", SIGBUS, BUS_ADRERR },
225 { "Oops - external exception", SIGBUS, BUS_ADRERR },
226 { "Oops - external exception", SIGBUS, BUS_ADRERR },
227 { "Oops - external exception", SIGBUS, BUS_ADRERR },
228 { "Oops - external exception", SIGBUS, BUS_ADRERR },
229 { "Oops - external exception", SIGBUS, BUS_ADRERR },
230 { "Oops - external exception", SIGBUS, BUS_ADRERR },
231 { "Oops - external exception", SIGBUS, BUS_ADRERR },
232 { "Oops - external exception", SIGBUS, BUS_ADRERR },
233 { "Oops - external exception", SIGBUS, BUS_ADRERR },
234 { "Oops - external exception", SIGBUS, BUS_ADRERR },
235 { "Oops - external exception", SIGBUS, BUS_ADRERR },
236 { "Oops - external exception", SIGBUS, BUS_ADRERR },
237 { "Oops - external exception", SIGBUS, BUS_ADRERR },
238 { "Oops - external exception", SIGBUS, BUS_ADRERR },
239 { "Oops - external exception", SIGBUS, BUS_ADRERR },
240 { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
241 { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
242 { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
243 { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
244 { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
245 { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
246 { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
247 { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
248 { "Oops - EMC bus error", SIGBUS, BUS_ADRERR }
249};
250
251static void do_trap(struct exception_info *except_info, struct pt_regs *regs)
252{
253 unsigned long addr = instruction_pointer(regs);
254 siginfo_t info;
255
256 if (except_info->code != TRAP_BRKPT)
257 pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n",
258 except_info->kernel_str, regs->pc,
259 except_info->signo, except_info->code);
260
261 die_if_kernel(except_info->kernel_str, regs, addr);
262
263 info.si_signo = except_info->signo;
264 info.si_errno = 0;
265 info.si_code = except_info->code;
266 info.si_addr = (void __user *)addr;
267
268 force_sig_info(except_info->signo, &info, current);
269}
270
271/*
272 * Process an internal exception (non maskable)
273 */
274static int process_iexcept(struct pt_regs *regs)
275{
276 unsigned int iexcept_report = get_iexcept();
277 unsigned int iexcept_num;
278
279 ack_exception(EXCEPT_TYPE_IXF);
280
281 pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc);
282
283 while (iexcept_report) {
284 iexcept_num = __ffs(iexcept_report);
285 iexcept_report &= ~(1 << iexcept_num);
286 set_iexcept(iexcept_report);
287 if (*(unsigned int *)regs->pc == BKPT_OPCODE) {
288 /* This is a breakpoint */
289 struct exception_info bkpt_exception = {
290 "Oops - undefined instruction",
291 SIGTRAP, TRAP_BRKPT
292 };
293 do_trap(&bkpt_exception, regs);
294 iexcept_report &= ~(0xFF);
295 set_iexcept(iexcept_report);
296 continue;
297 }
298
299 do_trap(&iexcept_table[iexcept_num], regs);
300 }
301 return 0;
302}
303
304/*
305 * Process an external exception (maskable)
306 */
307static void process_eexcept(struct pt_regs *regs)
308{
309 int evt;
310
311 pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc);
312
313 while ((evt = soc_get_exception()) >= 0)
314 do_trap(&eexcept_table[evt], regs);
315
316 ack_exception(EXCEPT_TYPE_EXC);
317}
318
319/*
320 * Main exception processing
321 */
322asmlinkage int process_exception(struct pt_regs *regs)
323{
324 unsigned int type;
325 unsigned int type_num;
326 unsigned int ie_num = 9; /* default is unknown exception */
327
328 while ((type = get_except_type()) != 0) {
329 type_num = fls(type) - 1;
330
331 switch (type_num) {
332 case EXCEPT_TYPE_NXF:
333 ack_exception(EXCEPT_TYPE_NXF);
334 if (c6x_nmi_handler)
335 (c6x_nmi_handler)(regs);
336 else
337 pr_alert("NMI interrupt!\n");
338 break;
339
340 case EXCEPT_TYPE_IXF:
341 if (process_iexcept(regs))
342 return 1;
343 break;
344
345 case EXCEPT_TYPE_EXC:
346 process_eexcept(regs);
347 break;
348
349 case EXCEPT_TYPE_SXF:
350 ie_num = 8;
351 default:
352 ack_exception(type_num);
353 do_trap(&iexcept_table[ie_num], regs);
354 break;
355 }
356 }
357 return 0;
358}
359
360static int kstack_depth_to_print = 48;
361
362static void show_trace(unsigned long *stack, unsigned long *endstack)
363{
364 unsigned long addr;
365 int i;
366
367 pr_debug("Call trace:");
368 i = 0;
369 while (stack + 1 <= endstack) {
370 addr = *stack++;
371 /*
372 * If the address is either in the text segment of the
373 * kernel, or in the region which contains vmalloc'ed
374 * memory, it *may* be the address of a calling
375 * routine; if so, print it so that someone tracing
376 * down the cause of the crash will be able to figure
377 * out the call path that was taken.
378 */
379 if (__kernel_text_address(addr)) {
380#ifndef CONFIG_KALLSYMS
381 if (i % 5 == 0)
382 pr_debug("\n ");
383#endif
384 pr_debug(" [<%08lx>]", addr);
385 print_symbol(" %s\n", addr);
386 i++;
387 }
388 }
389 pr_debug("\n");
390}
391
392void show_stack(struct task_struct *task, unsigned long *stack)
393{
394 unsigned long *p, *endstack;
395 int i;
396
397 if (!stack) {
398 if (task && task != current)
399 /* We know this is a kernel stack,
400 so this is the start/end */
401 stack = (unsigned long *)thread_saved_ksp(task);
402 else
403 stack = (unsigned long *)&stack;
404 }
405 endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1)
406 & -THREAD_SIZE);
407
408 pr_debug("Stack from %08lx:", (unsigned long)stack);
409 for (i = 0, p = stack; i < kstack_depth_to_print; i++) {
410 if (p + 1 > endstack)
411 break;
412 if (i % 8 == 0)
413 pr_cont("\n ");
414 pr_cont(" %08lx", *p++);
415 }
416 pr_cont("\n");
417 show_trace(stack, endstack);
418}
419
420int is_valid_bugaddr(unsigned long addr)
421{
422 return __kernel_text_address(addr);
423}
diff --git a/arch/c6x/kernel/vectors.S b/arch/c6x/kernel/vectors.S
new file mode 100644
index 000000000000..c95c66fc71e8
--- /dev/null
+++ b/arch/c6x/kernel/vectors.S
@@ -0,0 +1,81 @@
1;
2; Port on Texas Instruments TMS320C6x architecture
3;
4; Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6;
7; This program is free software; you can redistribute it and/or modify
8; it under the terms of the GNU General Public License version 2 as
9; published by the Free Software Foundation.
10;
11; This section handles all the interrupt vector routines.
12; At RESET the processor sets up the DRAM timing parameters and
13; branches to the label _c_int00 which handles initialization for the C code.
14;
15
16#define ALIGNMENT 5
17
18 .macro IRQVEC name, handler
19 .align ALIGNMENT
20 .hidden \name
21 .global \name
22\name:
23#ifdef CONFIG_C6X_BIG_KERNEL
24 STW .D2T1 A0,*B15--[2]
25 || MVKL .S1 \handler,A0
26 MVKH .S1 \handler,A0
27 B .S2X A0
28 LDW .D2T1 *++B15[2],A0
29 NOP 4
30 NOP
31 NOP
32 .endm
33#else /* CONFIG_C6X_BIG_KERNEL */
34 B .S2 \handler
35 NOP
36 NOP
37 NOP
38 NOP
39 NOP
40 NOP
41 NOP
42 .endm
43#endif /* CONFIG_C6X_BIG_KERNEL */
44
45 .sect ".vectors","ax"
46 .align ALIGNMENT
47 .global RESET
48 .hidden RESET
49RESET:
50#ifdef CONFIG_C6X_BIG_KERNEL
51 MVKL .S1 _c_int00,A0 ; branch to _c_int00
52 MVKH .S1 _c_int00,A0
53 B .S2X A0
54#else
55 B .S2 _c_int00
56 NOP
57 NOP
58#endif
59 NOP
60 NOP
61 NOP
62 NOP
63 NOP
64
65
66 IRQVEC NMI,_nmi_handler ; NMI interrupt
67 IRQVEC AINT,_bad_interrupt ; reserved
68 IRQVEC MSGINT,_bad_interrupt ; reserved
69
70 IRQVEC INT4,_int4_handler
71 IRQVEC INT5,_int5_handler
72 IRQVEC INT6,_int6_handler
73 IRQVEC INT7,_int7_handler
74 IRQVEC INT8,_int8_handler
75 IRQVEC INT9,_int9_handler
76 IRQVEC INT10,_int10_handler
77 IRQVEC INT11,_int11_handler
78 IRQVEC INT12,_int12_handler
79 IRQVEC INT13,_int13_handler
80 IRQVEC INT14,_int14_handler
81 IRQVEC INT15,_int15_handler
diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..1d81c4c129ec
--- /dev/null
+++ b/arch/c6x/kernel/vmlinux.lds.S
@@ -0,0 +1,162 @@
1/*
2 * ld script for the c6x kernel
3 *
4 * Copyright (C) 2010, 2011 Texas Instruments Incorporated
5 * Mark Salter <msalter@redhat.com>
6 */
7#include <asm-generic/vmlinux.lds.h>
8#include <asm/thread_info.h>
9#include <asm/page.h>
10
11ENTRY(_c_int00)
12
13#if defined(CONFIG_CPU_BIG_ENDIAN)
14jiffies = jiffies_64 + 4;
15#else
16jiffies = jiffies_64;
17#endif
18
19#define READONLY_SEGMENT_START \
20 . = PAGE_OFFSET;
21#define READWRITE_SEGMENT_START \
22 . = ALIGN(128); \
23 _data_lma = .;
24
25SECTIONS
26{
27 /*
28 * Start kernel read only segment
29 */
30 READONLY_SEGMENT_START
31
32 .vectors :
33 {
34 _vectors_start = .;
35 *(.vectors)
36 . = ALIGN(0x400);
37 _vectors_end = .;
38 }
39
40 . = ALIGN(0x1000);
41 .cmdline :
42 {
43 *(.cmdline)
44 }
45
46 /*
47 * This section contains data which may be shared with other
48 * cores. It needs to be a fixed offset from PAGE_OFFSET
49 * regardless of kernel configuration.
50 */
51 .virtio_ipc_dev :
52 {
53 *(.virtio_ipc_dev)
54 }
55
56 . = ALIGN(PAGE_SIZE);
57 .init :
58 {
59 _stext = .;
60 _sinittext = .;
61 HEAD_TEXT
62 INIT_TEXT
63 _einittext = .;
64 }
65
66 __init_begin = _stext;
67 INIT_DATA_SECTION(16)
68
69 PERCPU_SECTION(128)
70
71 . = ALIGN(PAGE_SIZE);
72 __init_end = .;
73
74 .text :
75 {
76 _text = .;
77 TEXT_TEXT
78 SCHED_TEXT
79 LOCK_TEXT
80 IRQENTRY_TEXT
81 KPROBES_TEXT
82 *(.fixup)
83 *(.gnu.warning)
84 }
85
86 EXCEPTION_TABLE(16)
87 NOTES
88
89 RO_DATA_SECTION(PAGE_SIZE)
90 .const :
91 {
92 *(.const .const.* .gnu.linkonce.r.*)
93 *(.switch)
94 }
95
96 . = ALIGN (8) ;
97 __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET)
98 {
99 _fdt_start = . ; /* place for fdt blob */
100 *(__fdt_blob) ; /* Any link-placed DTB */
101 BYTE(0); /* section always has contents */
102 . = _fdt_start + 0x4000; /* Pad up to 16kbyte */
103 _fdt_end = . ;
104 }
105
106 _etext = .;
107
108 /*
109 * Start kernel read-write segment.
110 */
111 READWRITE_SEGMENT_START
112 _sdata = .;
113
114 .fardata : AT(ADDR(.fardata) - LOAD_OFFSET)
115 {
116 INIT_TASK_DATA(THREAD_SIZE)
117 NOSAVE_DATA
118 PAGE_ALIGNED_DATA(PAGE_SIZE)
119 CACHELINE_ALIGNED_DATA(128)
120 READ_MOSTLY_DATA(128)
121 DATA_DATA
122 CONSTRUCTORS
123 *(.data1)
124 *(.fardata .fardata.*)
125 *(.data.debug_bpt)
126 }
127
128 .neardata ALIGN(8) : AT(ADDR(.neardata) - LOAD_OFFSET)
129 {
130 *(.neardata2 .neardata2.* .gnu.linkonce.s2.*)
131 *(.neardata .neardata.* .gnu.linkonce.s.*)
132 . = ALIGN(8);
133 }
134
135 _edata = .;
136
137 __bss_start = .;
138 SBSS(8)
139 BSS(8)
140 .far :
141 {
142 . = ALIGN(8);
143 *(.dynfar)
144 *(.far .far.* .gnu.linkonce.b.*)
145 . = ALIGN(8);
146 }
147 __bss_stop = .;
148
149 _end = .;
150
151 DWARF_DEBUG
152
153 /DISCARD/ :
154 {
155 EXIT_TEXT
156 EXIT_DATA
157 EXIT_CALL
158 *(.discard)
159 *(.discard.*)
160 *(.interp)
161 }
162}
diff --git a/arch/c6x/lib/Makefile b/arch/c6x/lib/Makefile
new file mode 100644
index 000000000000..ffd3c659091a
--- /dev/null
+++ b/arch/c6x/lib/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for arch/c6x/lib/
3#
4
5lib-y := divu.o divi.o pop_rts.o push_rts.o remi.o remu.o strasgi.o llshru.o
6lib-y += llshr.o llshl.o negll.o mpyll.o divremi.o divremu.o
7lib-y += checksum.o csum_64plus.o memcpy_64plus.o strasgi_64plus.o
diff --git a/arch/c6x/lib/checksum.c b/arch/c6x/lib/checksum.c
new file mode 100644
index 000000000000..67cc93b0b932
--- /dev/null
+++ b/arch/c6x/lib/checksum.c
@@ -0,0 +1,36 @@
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version
5 * 2 of the License, or (at your option) any later version.
6 */
7#include <linux/module.h>
8#include <net/checksum.h>
9
10#include <asm/byteorder.h>
11
12/*
13 * copy from fs while checksumming, otherwise like csum_partial
14 */
15__wsum
16csum_partial_copy_from_user(const void __user *src, void *dst, int len,
17 __wsum sum, int *csum_err)
18{
19 int missing;
20
21 missing = __copy_from_user(dst, src, len);
22 if (missing) {
23 memset(dst + len - missing, 0, missing);
24 *csum_err = -EFAULT;
25 } else
26 *csum_err = 0;
27
28 return csum_partial(dst, len, sum);
29}
30EXPORT_SYMBOL(csum_partial_copy_from_user);
31
32/* These are from csum_64plus.S */
33EXPORT_SYMBOL(csum_partial);
34EXPORT_SYMBOL(csum_partial_copy);
35EXPORT_SYMBOL(ip_compute_csum);
36EXPORT_SYMBOL(ip_fast_csum);
diff --git a/arch/c6x/lib/csum_64plus.S b/arch/c6x/lib/csum_64plus.S
new file mode 100644
index 000000000000..6d2589647227
--- /dev/null
+++ b/arch/c6x/lib/csum_64plus.S
@@ -0,0 +1,419 @@
1;
2; linux/arch/c6x/lib/csum_64plus.s
3;
4; Port on Texas Instruments TMS320C6x architecture
5;
6; Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated
7; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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#include <linux/linkage.h>
14
15;
16;unsigned int csum_partial_copy(const char *src, char * dst,
17; int len, int sum)
18;
19; A4: src
20; B4: dst
21; A6: len
22; B6: sum
23; return csum in A4
24;
25
26 .text
27ENTRY(csum_partial_copy)
28 MVC .S2 ILC,B30
29
30 MV .D1X B6,A31 ; given csum
31 ZERO .D1 A9 ; csum (a side)
32|| ZERO .D2 B9 ; csum (b side)
33|| SHRU .S2X A6,2,B5 ; len / 4
34
35 ;; Check alignment and size
36 AND .S1 3,A4,A1
37|| AND .S2 3,B4,B0
38 OR .L2X B0,A1,B0 ; non aligned condition
39|| MVC .S2 B5,ILC
40|| MVK .D2 1,B2
41|| MV .D1X B5,A1 ; words condition
42 [!A1] B .S1 L8
43 [B0] BNOP .S1 L6,5
44
45 SPLOOP 1
46
47 ;; Main loop for aligned words
48 LDW .D1T1 *A4++,A7
49 NOP 4
50 MV .S2X A7,B7
51|| EXTU .S1 A7,0,16,A16
52 STW .D2T2 B7,*B4++
53|| MPYU .M2 B7,B2,B8
54|| ADD .L1 A16,A9,A9
55 NOP
56 SPKERNEL 8,0
57|| ADD .L2 B8,B9,B9
58
59 ZERO .D1 A1
60|| ADD .L1X A9,B9,A9 ; add csum from a and b sides
61
62L6:
63 [!A1] BNOP .S1 L8,5
64
65 ;; Main loop for non-aligned words
66 SPLOOP 2
67 || MVK .L1 1,A2
68
69 LDNW .D1T1 *A4++,A7
70 NOP 3
71
72 NOP
73 MV .S2X A7,B7
74 || EXTU .S1 A7,0,16,A16
75 || MPYU .M1 A7,A2,A8
76
77 ADD .L1 A16,A9,A9
78 SPKERNEL 6,0
79 || STNW .D2T2 B7,*B4++
80 || ADD .L1 A8,A9,A9
81
82L8: AND .S2X 2,A6,B5
83 CMPGT .L2 B5,0,B0
84 [!B0] BNOP .S1 L82,4
85
86 ;; Manage half-word
87 ZERO .L1 A7
88|| ZERO .D1 A8
89
90#ifdef CONFIG_CPU_BIG_ENDIAN
91
92 LDBU .D1T1 *A4++,A7
93 LDBU .D1T1 *A4++,A8
94 NOP 3
95 SHL .S1 A7,8,A0
96 ADD .S1 A8,A9,A9
97 STB .D2T1 A7,*B4++
98|| ADD .S1 A0,A9,A9
99 STB .D2T1 A8,*B4++
100
101#else
102
103 LDBU .D1T1 *A4++,A7
104 LDBU .D1T1 *A4++,A8
105 NOP 3
106 ADD .S1 A7,A9,A9
107 SHL .S1 A8,8,A0
108
109 STB .D2T1 A7,*B4++
110|| ADD .S1 A0,A9,A9
111 STB .D2T1 A8,*B4++
112
113#endif
114
115 ;; Manage eventually the last byte
116L82: AND .S2X 1,A6,B0
117 [!B0] BNOP .S1 L9,5
118
119|| ZERO .L1 A7
120
121L83: LDBU .D1T1 *A4++,A7
122 NOP 4
123
124 MV .L2X A7,B7
125
126#ifdef CONFIG_CPU_BIG_ENDIAN
127
128 STB .D2T2 B7,*B4++
129|| SHL .S1 A7,8,A7
130 ADD .S1 A7,A9,A9
131
132#else
133
134 STB .D2T2 B7,*B4++
135|| ADD .S1 A7,A9,A9
136
137#endif
138
139 ;; Fold the csum
140L9: SHRU .S2X A9,16,B0
141 [!B0] BNOP .S1 L10,5
142
143L91: SHRU .S2X A9,16,B4
144|| EXTU .S1 A9,16,16,A3
145 ADD .D1X A3,B4,A9
146
147 SHRU .S1 A9,16,A0
148 [A0] BNOP .S1 L91,5
149
150L10: ADD .D1 A31,A9,A9
151 MV .D1 A9,A4
152
153 BNOP .S2 B3,4
154 MVC .S2 B30,ILC
155ENDPROC(csum_partial_copy)
156
157;
158;unsigned short
159;ip_fast_csum(unsigned char *iph, unsigned int ihl)
160;{
161; unsigned int checksum = 0;
162; unsigned short *tosum = (unsigned short *) iph;
163; int len;
164;
165; len = ihl*4;
166;
167; if (len <= 0)
168; return 0;
169;
170; while(len) {
171; len -= 2;
172; checksum += *tosum++;
173; }
174; if (len & 1)
175; checksum += *(unsigned char*) tosum;
176;
177; while(checksum >> 16)
178; checksum = (checksum & 0xffff) + (checksum >> 16);
179;
180; return ~checksum;
181;}
182;
183; A4: iph
184; B4: ihl
185; return checksum in A4
186;
187 .text
188
189ENTRY(ip_fast_csum)
190 ZERO .D1 A5
191 || MVC .S2 ILC,B30
192 SHL .S2 B4,2,B0
193 CMPGT .L2 B0,0,B1
194 [!B1] BNOP .S1 L15,4
195 [!B1] ZERO .D1 A3
196
197 [!B0] B .S1 L12
198 SHRU .S2 B0,1,B0
199 MVC .S2 B0,ILC
200 NOP 3
201
202 SPLOOP 1
203 LDHU .D1T1 *A4++,A3
204 NOP 3
205 NOP
206 SPKERNEL 5,0
207 || ADD .L1 A3,A5,A5
208
209L12: SHRU .S1 A5,16,A0
210 [!A0] BNOP .S1 L14,5
211
212L13: SHRU .S2X A5,16,B4
213 EXTU .S1 A5,16,16,A3
214 ADD .D1X A3,B4,A5
215 SHRU .S1 A5,16,A0
216 [A0] BNOP .S1 L13,5
217
218L14: NOT .D1 A5,A3
219 EXTU .S1 A3,16,16,A3
220
221L15: BNOP .S2 B3,3
222 MVC .S2 B30,ILC
223 MV .D1 A3,A4
224ENDPROC(ip_fast_csum)
225
226;
227;unsigned short
228;do_csum(unsigned char *buff, unsigned int len)
229;{
230; int odd, count;
231; unsigned int result = 0;
232;
233; if (len <= 0)
234; goto out;
235; odd = 1 & (unsigned long) buff;
236; if (odd) {
237;#ifdef __LITTLE_ENDIAN
238; result += (*buff << 8);
239;#else
240; result = *buff;
241;#endif
242; len--;
243; buff++;
244; }
245; count = len >> 1; /* nr of 16-bit words.. */
246; if (count) {
247; if (2 & (unsigned long) buff) {
248; result += *(unsigned short *) buff;
249; count--;
250; len -= 2;
251; buff += 2;
252; }
253; count >>= 1; /* nr of 32-bit words.. */
254; if (count) {
255; unsigned int carry = 0;
256; do {
257; unsigned int w = *(unsigned int *) buff;
258; count--;
259; buff += 4;
260; result += carry;
261; result += w;
262; carry = (w > result);
263; } while (count);
264; result += carry;
265; result = (result & 0xffff) + (result >> 16);
266; }
267; if (len & 2) {
268; result += *(unsigned short *) buff;
269; buff += 2;
270; }
271; }
272; if (len & 1)
273;#ifdef __LITTLE_ENDIAN
274; result += *buff;
275;#else
276; result += (*buff << 8);
277;#endif
278; result = (result & 0xffff) + (result >> 16);
279; /* add up carry.. */
280; result = (result & 0xffff) + (result >> 16);
281; if (odd)
282; result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
283;out:
284; return result;
285;}
286;
287; A4: buff
288; B4: len
289; return checksum in A4
290;
291
292ENTRY(do_csum)
293 CMPGT .L2 B4,0,B0
294 [!B0] BNOP .S1 L26,3
295 EXTU .S1 A4,31,31,A0
296
297 MV .L1 A0,A3
298|| MV .S1X B3,A5
299|| MV .L2 B4,B3
300|| ZERO .D1 A1
301
302#ifdef CONFIG_CPU_BIG_ENDIAN
303 [A0] SUB .L2 B3,1,B3
304|| [A0] LDBU .D1T1 *A4++,A1
305#else
306 [!A0] BNOP .S1 L21,5
307|| [A0] LDBU .D1T1 *A4++,A0
308 SUB .L2 B3,1,B3
309|| SHL .S1 A0,8,A1
310L21:
311#endif
312 SHR .S2 B3,1,B0
313 [!B0] BNOP .S1 L24,3
314 MVK .L1 2,A0
315 AND .L1 A4,A0,A0
316
317 [!A0] BNOP .S1 L22,5
318|| [A0] LDHU .D1T1 *A4++,A0
319 SUB .L2 B0,1,B0
320|| SUB .S2 B3,2,B3
321|| ADD .L1 A0,A1,A1
322L22:
323 SHR .S2 B0,1,B0
324|| ZERO .L1 A0
325
326 [!B0] BNOP .S1 L23,5
327|| [B0] MVC .S2 B0,ILC
328
329 SPLOOP 3
330 SPMASK L1
331|| MV .L1 A1,A2
332|| LDW .D1T1 *A4++,A1
333
334 NOP 4
335 ADD .L1 A0,A1,A0
336 ADD .L1 A2,A0,A2
337
338 SPKERNEL 1,2
339|| CMPGTU .L1 A1,A2,A0
340
341 ADD .L1 A0,A2,A6
342 EXTU .S1 A6,16,16,A7
343 SHRU .S2X A6,16,B0
344 NOP 1
345 ADD .L1X A7,B0,A1
346L23:
347 MVK .L2 2,B0
348 AND .L2 B3,B0,B0
349 [B0] LDHU .D1T1 *A4++,A0
350 NOP 4
351 [B0] ADD .L1 A0,A1,A1
352L24:
353 EXTU .S2 B3,31,31,B0
354#ifdef CONFIG_CPU_BIG_ENDIAN
355 [!B0] BNOP .S1 L25,4
356|| [B0] LDBU .D1T1 *A4,A0
357 SHL .S1 A0,8,A0
358 ADD .L1 A0,A1,A1
359L25:
360#else
361 [B0] LDBU .D1T1 *A4,A0
362 NOP 4
363 [B0] ADD .L1 A0,A1,A1
364#endif
365 EXTU .S1 A1,16,16,A0
366 SHRU .S2X A1,16,B0
367 NOP 1
368 ADD .L1X A0,B0,A0
369 SHRU .S1 A0,16,A1
370 ADD .L1 A0,A1,A0
371 EXTU .S1 A0,16,16,A1
372 EXTU .S1 A1,16,24,A2
373
374 EXTU .S1 A1,24,16,A0
375|| MV .L2X A3,B0
376
377 [B0] OR .L1 A0,A2,A1
378L26:
379 NOP 1
380 BNOP .S2X A5,4
381 MV .L1 A1,A4
382ENDPROC(do_csum)
383
384;__wsum csum_partial(const void *buff, int len, __wsum wsum)
385;{
386; unsigned int sum = (__force unsigned int)wsum;
387; unsigned int result = do_csum(buff, len);
388;
389; /* add in old sum, and carry.. */
390; result += sum;
391; if (sum > result)
392; result += 1;
393; return (__force __wsum)result;
394;}
395;
396ENTRY(csum_partial)
397 MV .L1X B3,A9
398|| CALLP .S2 do_csum,B3
399|| MV .S1 A6,A8
400 BNOP .S2X A9,2
401 ADD .L1 A8,A4,A1
402 CMPGTU .L1 A8,A1,A0
403 ADD .L1 A1,A0,A4
404ENDPROC(csum_partial)
405
406;unsigned short
407;ip_compute_csum(unsigned char *buff, unsigned int len)
408;
409; A4: buff
410; B4: len
411; return checksum in A4
412
413ENTRY(ip_compute_csum)
414 MV .L1X B3,A9
415|| CALLP .S2 do_csum,B3
416 BNOP .S2X A9,3
417 NOT .S1 A4,A4
418 CLR .S1 A4,16,31,A4
419ENDPROC(ip_compute_csum)
diff --git a/arch/c6x/lib/divi.S b/arch/c6x/lib/divi.S
new file mode 100644
index 000000000000..4bde924f2a98
--- /dev/null
+++ b/arch/c6x/lib/divi.S
@@ -0,0 +1,53 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 ;; ABI considerations for the divide functions
21 ;; The following registers are call-used:
22 ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
23 ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
24 ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
25 ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
26 ;;
27 ;; In our implementation, divu and remu are leaf functions,
28 ;; while both divi and remi call into divu.
29 ;; A0 is not clobbered by any of the functions.
30 ;; divu does not clobber B2 either, which is taken advantage of
31 ;; in remi.
32 ;; divi uses B5 to hold the original return address during
33 ;; the call to divu.
34 ;; remi uses B2 and A5 to hold the input values during the
35 ;; call to divu. It stores B3 in on the stack.
36
37 .text
38ENTRY(__c6xabi_divi)
39 call .s2 __c6xabi_divu
40|| mv .d2 B3, B5
41|| cmpgt .l1 0, A4, A1
42|| cmpgt .l2 0, B4, B1
43
44 [A1] neg .l1 A4, A4
45|| [B1] neg .l2 B4, B4
46|| xor .s1x A1, B1, A1
47 [A1] addkpc .s2 _divu_ret, B3, 4
48_divu_ret:
49 neg .l1 A4, A4
50|| mv .l2 B3,B5
51|| ret .s2 B5
52 nop 5
53ENDPROC(__c6xabi_divi)
diff --git a/arch/c6x/lib/divremi.S b/arch/c6x/lib/divremi.S
new file mode 100644
index 000000000000..64bc5aa95ad3
--- /dev/null
+++ b/arch/c6x/lib/divremi.S
@@ -0,0 +1,46 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21ENTRY(__c6xabi_divremi)
22 stw .d2t2 B3, *B15--[2]
23|| cmpgt .l1 0, A4, A1
24|| cmpgt .l2 0, B4, B2
25|| mv .s1 A4, A5
26|| call .s2 __c6xabi_divu
27
28 [A1] neg .l1 A4, A4
29|| [B2] neg .l2 B4, B4
30|| xor .s2x B2, A1, B0
31|| mv .d2 B4, B2
32
33 [B0] addkpc .s2 _divu_ret_1, B3, 1
34 [!B0] addkpc .s2 _divu_ret_2, B3, 1
35 nop 2
36_divu_ret_1:
37 neg .l1 A4, A4
38_divu_ret_2:
39 ldw .d2t2 *++B15[2], B3
40
41 mpy32 .m1x A4, B2, A6
42 nop 3
43 ret .s2 B3
44 sub .l1 A5, A6, A5
45 nop 4
46ENDPROC(__c6xabi_divremi)
diff --git a/arch/c6x/lib/divremu.S b/arch/c6x/lib/divremu.S
new file mode 100644
index 000000000000..caa9f23ee167
--- /dev/null
+++ b/arch/c6x/lib/divremu.S
@@ -0,0 +1,87 @@
1;; Copyright 2011 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21ENTRY(__c6xabi_divremu)
22 ;; We use a series of up to 31 subc instructions. First, we find
23 ;; out how many leading zero bits there are in the divisor. This
24 ;; gives us both a shift count for aligning (shifting) the divisor
25 ;; to the, and the number of times we have to execute subc.
26
27 ;; At the end, we have both the remainder and most of the quotient
28 ;; in A4. The top bit of the quotient is computed first and is
29 ;; placed in A2.
30
31 ;; Return immediately if the dividend is zero. Setting B4 to 1
32 ;; is a trick to allow us to leave the following insns in the jump
33 ;; delay slot without affecting the result.
34 mv .s2x A4, B1
35
36 [b1] lmbd .l2 1, B4, B1
37||[!b1] b .s2 B3 ; RETURN A
38||[!b1] mvk .d2 1, B4
39
40||[!b1] zero .s1 A5
41 mv .l1x B1, A6
42|| shl .s2 B4, B1, B4
43
44 ;; The loop performs a maximum of 28 steps, so we do the
45 ;; first 3 here.
46 cmpltu .l1x A4, B4, A2
47 [!A2] sub .l1x A4, B4, A4
48|| shru .s2 B4, 1, B4
49|| xor .s1 1, A2, A2
50
51 shl .s1 A2, 31, A2
52|| [b1] subc .l1x A4,B4,A4
53|| [b1] add .s2 -1, B1, B1
54 [b1] subc .l1x A4,B4,A4
55|| [b1] add .s2 -1, B1, B1
56
57 ;; RETURN A may happen here (note: must happen before the next branch)
58__divremu0:
59 cmpgt .l2 B1, 7, B0
60|| [b1] subc .l1x A4,B4,A4
61|| [b1] add .s2 -1, B1, B1
62 [b1] subc .l1x A4,B4,A4
63|| [b1] add .s2 -1, B1, B1
64|| [b0] b .s1 __divremu0
65 [b1] subc .l1x A4,B4,A4
66|| [b1] add .s2 -1, B1, B1
67 [b1] subc .l1x A4,B4,A4
68|| [b1] add .s2 -1, B1, B1
69 [b1] subc .l1x A4,B4,A4
70|| [b1] add .s2 -1, B1, B1
71 [b1] subc .l1x A4,B4,A4
72|| [b1] add .s2 -1, B1, B1
73 [b1] subc .l1x A4,B4,A4
74|| [b1] add .s2 -1, B1, B1
75 ;; loop backwards branch happens here
76
77 ret .s2 B3
78|| mvk .s1 32, A1
79 sub .l1 A1, A6, A6
80|| extu .s1 A4, A6, A5
81 shl .s1 A4, A6, A4
82 shru .s1 A4, 1, A4
83|| sub .l1 A6, 1, A6
84 or .l1 A2, A4, A4
85 shru .s1 A4, A6, A4
86 nop
87ENDPROC(__c6xabi_divremu)
diff --git a/arch/c6x/lib/divu.S b/arch/c6x/lib/divu.S
new file mode 100644
index 000000000000..64af3c006dd3
--- /dev/null
+++ b/arch/c6x/lib/divu.S
@@ -0,0 +1,98 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 ;; ABI considerations for the divide functions
21 ;; The following registers are call-used:
22 ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
23 ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
24 ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
25 ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
26 ;;
27 ;; In our implementation, divu and remu are leaf functions,
28 ;; while both divi and remi call into divu.
29 ;; A0 is not clobbered by any of the functions.
30 ;; divu does not clobber B2 either, which is taken advantage of
31 ;; in remi.
32 ;; divi uses B5 to hold the original return address during
33 ;; the call to divu.
34 ;; remi uses B2 and A5 to hold the input values during the
35 ;; call to divu. It stores B3 in on the stack.
36
37 .text
38ENTRY(__c6xabi_divu)
39 ;; We use a series of up to 31 subc instructions. First, we find
40 ;; out how many leading zero bits there are in the divisor. This
41 ;; gives us both a shift count for aligning (shifting) the divisor
42 ;; to the, and the number of times we have to execute subc.
43
44 ;; At the end, we have both the remainder and most of the quotient
45 ;; in A4. The top bit of the quotient is computed first and is
46 ;; placed in A2.
47
48 ;; Return immediately if the dividend is zero.
49 mv .s2x A4, B1
50 [B1] lmbd .l2 1, B4, B1
51|| [!B1] b .s2 B3 ; RETURN A
52|| [!B1] mvk .d2 1, B4
53 mv .l1x B1, A6
54|| shl .s2 B4, B1, B4
55
56 ;; The loop performs a maximum of 28 steps, so we do the
57 ;; first 3 here.
58 cmpltu .l1x A4, B4, A2
59 [!A2] sub .l1x A4, B4, A4
60|| shru .s2 B4, 1, B4
61|| xor .s1 1, A2, A2
62
63 shl .s1 A2, 31, A2
64|| [B1] subc .l1x A4,B4,A4
65|| [B1] add .s2 -1, B1, B1
66 [B1] subc .l1x A4,B4,A4
67|| [B1] add .s2 -1, B1, B1
68
69 ;; RETURN A may happen here (note: must happen before the next branch)
70_divu_loop:
71 cmpgt .l2 B1, 7, B0
72|| [B1] subc .l1x A4,B4,A4
73|| [B1] add .s2 -1, B1, B1
74 [B1] subc .l1x A4,B4,A4
75|| [B1] add .s2 -1, B1, B1
76|| [B0] b .s1 _divu_loop
77 [B1] subc .l1x A4,B4,A4
78|| [B1] add .s2 -1, B1, B1
79 [B1] subc .l1x A4,B4,A4
80|| [B1] add .s2 -1, B1, B1
81 [B1] subc .l1x A4,B4,A4
82|| [B1] add .s2 -1, B1, B1
83 [B1] subc .l1x A4,B4,A4
84|| [B1] add .s2 -1, B1, B1
85 [B1] subc .l1x A4,B4,A4
86|| [B1] add .s2 -1, B1, B1
87 ;; loop backwards branch happens here
88
89 ret .s2 B3
90|| mvk .s1 32, A1
91 sub .l1 A1, A6, A6
92 shl .s1 A4, A6, A4
93 shru .s1 A4, 1, A4
94|| sub .l1 A6, 1, A6
95 or .l1 A2, A4, A4
96 shru .s1 A4, A6, A4
97 nop
98ENDPROC(__c6xabi_divu)
diff --git a/arch/c6x/lib/llshl.S b/arch/c6x/lib/llshl.S
new file mode 100644
index 000000000000..7b105e2d1b78
--- /dev/null
+++ b/arch/c6x/lib/llshl.S
@@ -0,0 +1,37 @@
1;; Copyright (C) 2010 Texas Instruments Incorporated
2;; Contributed by Mark Salter <msalter@redhat.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18;; uint64_t __c6xabi_llshl(uint64_t val, uint shift)
19
20#include <linux/linkage.h>
21
22 .text
23ENTRY(__c6xabi_llshl)
24 mv .l1x B4,A1
25 [!A1] b .s2 B3 ; just return if zero shift
26 mvk .s1 32,A0
27 sub .d1 A0,A1,A0
28 cmplt .l1 0,A0,A2
29 [A2] shru .s1 A4,A0,A0
30 [!A2] neg .l1 A0,A5
31|| [A2] shl .s1 A5,A1,A5
32 [!A2] shl .s1 A4,A5,A5
33|| [A2] or .d1 A5,A0,A5
34|| [!A2] mvk .l1 0,A4
35 [A2] shl .s1 A4,A1,A4
36 bnop .s2 B3,5
37ENDPROC(__c6xabi_llshl)
diff --git a/arch/c6x/lib/llshr.S b/arch/c6x/lib/llshr.S
new file mode 100644
index 000000000000..fde1bec7cf5a
--- /dev/null
+++ b/arch/c6x/lib/llshr.S
@@ -0,0 +1,38 @@
1;; Copyright (C) 2010 Texas Instruments Incorporated
2;; Contributed by Mark Salter <msalter@redhat.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18;; uint64_t __c6xabi_llshr(uint64_t val, uint shift)
19
20#include <linux/linkage.h>
21
22 .text
23ENTRY(__c6xabi_llshr)
24 mv .l1x B4,A1
25 [!A1] b .s2 B3 ; return if zero shift count
26 mvk .s1 32,A0
27 sub .d1 A0,A1,A0
28 cmplt .l1 0,A0,A2
29 [A2] shl .s1 A5,A0,A0
30 nop
31 [!A2] neg .l1 A0,A4
32|| [A2] shru .s1 A4,A1,A4
33 [!A2] shr .s1 A5,A4,A4
34|| [A2] or .d1 A4,A0,A4
35 [!A2] shr .s1 A5,0x1f,A5
36 [A2] shr .s1 A5,A1,A5
37 bnop .s2 B3,5
38ENDPROC(__c6xabi_llshr)
diff --git a/arch/c6x/lib/llshru.S b/arch/c6x/lib/llshru.S
new file mode 100644
index 000000000000..596ae3ff5c0f
--- /dev/null
+++ b/arch/c6x/lib/llshru.S
@@ -0,0 +1,38 @@
1;; Copyright (C) 2010 Texas Instruments Incorporated
2;; Contributed by Mark Salter <msalter@redhat.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18;; uint64_t __c6xabi_llshru(uint64_t val, uint shift)
19
20#include <linux/linkage.h>
21
22 .text
23ENTRY(__c6xabi_llshru)
24 mv .l1x B4,A1
25 [!A1] b .s2 B3 ; return if zero shift count
26 mvk .s1 32,A0
27 sub .d1 A0,A1,A0
28 cmplt .l1 0,A0,A2
29 [A2] shl .s1 A5,A0,A0
30 nop
31 [!A2] neg .l1 A0,A4
32|| [A2] shru .s1 A4,A1,A4
33 [!A2] shru .s1 A5,A4,A4
34|| [A2] or .d1 A4,A0,A4
35|| [!A2] mvk .l1 0,A5
36 [A2] shru .s1 A5,A1,A5
37 bnop .s2 B3,5
38ENDPROC(__c6xabi_llshru)
diff --git a/arch/c6x/lib/memcpy_64plus.S b/arch/c6x/lib/memcpy_64plus.S
new file mode 100644
index 000000000000..0bbc2cbf9318
--- /dev/null
+++ b/arch/c6x/lib/memcpy_64plus.S
@@ -0,0 +1,46 @@
1; Port on Texas Instruments TMS320C6x architecture
2;
3; Copyright (C) 2006, 2009, 2010 Texas Instruments Incorporated
4; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
5;
6; This program is free software; you can redistribute it and/or modify
7; it under the terms of the GNU General Public License version 2 as
8; published by the Free Software Foundation.
9;
10
11#include <linux/linkage.h>
12
13 .text
14
15ENTRY(memcpy)
16 AND .L1 0x1,A6,A0
17 || AND .S1 0x2,A6,A1
18 || AND .L2X 0x4,A6,B0
19 || MV .D1 A4,A3
20 || MVC .S2 ILC,B2
21
22 [A0] LDB .D2T1 *B4++,A5
23 [A1] LDB .D2T1 *B4++,A7
24 [A1] LDB .D2T1 *B4++,A8
25 [B0] LDNW .D2T1 *B4++,A9
26 || SHRU .S2X A6,0x3,B1
27 [!B1] BNOP .S2 B3,1
28
29 [A0] STB .D1T1 A5,*A3++
30 ||[B1] MVC .S2 B1,ILC
31 [A1] STB .D1T1 A7,*A3++
32 [A1] STB .D1T1 A8,*A3++
33 [B0] STNW .D1T1 A9,*A3++ ; return when len < 8
34
35 SPLOOP 2
36
37 LDNDW .D2T1 *B4++,A9:A8
38 NOP 3
39
40 NOP
41 SPKERNEL 0,0
42 || STNDW .D1T1 A9:A8,*A3++
43
44 BNOP .S2 B3,4
45 MVC .S2 B2,ILC
46ENDPROC(memcpy)
diff --git a/arch/c6x/lib/mpyll.S b/arch/c6x/lib/mpyll.S
new file mode 100644
index 000000000000..f1034418b4db
--- /dev/null
+++ b/arch/c6x/lib/mpyll.S
@@ -0,0 +1,49 @@
1;; Copyright (C) 2010 Texas Instruments Incorporated
2;; Contributed by Mark Salter <msalter@redhat.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 ;; uint64_t __c6xabi_mpyll(uint64_t x, uint64_t y)
21 ;;
22 ;; 64x64 multiply
23 ;; First compute partial results using 32-bit parts of x and y:
24 ;;
25 ;; b63 b32 b31 b0
26 ;; -----------------------------
27 ;; | 1 | 0 |
28 ;; -----------------------------
29 ;;
30 ;; P0 = X0*Y0
31 ;; P1 = X0*Y1 + X1*Y0
32 ;; P2 = X1*Y1
33 ;;
34 ;; result = (P2 << 64) + (P1 << 32) + P0
35 ;;
36 ;; Since the result is also 64-bit, we can skip the P2 term.
37
38 .text
39ENTRY(__c6xabi_mpyll)
40 mpy32u .m1x A4,B4,A1:A0 ; X0*Y0
41 b .s2 B3
42 || mpy32u .m2x B5,A4,B1:B0 ; X0*Y1 (don't need upper 32-bits)
43 || mpy32u .m1x A5,B4,A3:A2 ; X1*Y0 (don't need upper 32-bits)
44 nop
45 nop
46 mv .s1 A0,A4
47 add .l1x A2,B0,A5
48 add .s1 A1,A5,A5
49ENDPROC(__c6xabi_mpyll)
diff --git a/arch/c6x/lib/negll.S b/arch/c6x/lib/negll.S
new file mode 100644
index 000000000000..82f4bcec9afb
--- /dev/null
+++ b/arch/c6x/lib/negll.S
@@ -0,0 +1,31 @@
1;; Copyright (C) 2010 Texas Instruments Incorporated
2;; Contributed by Mark Salter <msalter@redhat.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18;; int64_t __c6xabi_negll(int64_t val)
19
20#include <linux/linkage.h>
21
22 .text
23ENTRY(__c6xabi_negll)
24 b .s2 B3
25 mvk .l1 0,A0
26 subu .l1 A0,A4,A3:A2
27 sub .l1 A0,A5,A0
28|| ext .s1 A3,24,24,A5
29 add .l1 A5,A0,A5
30 mv .s1 A2,A4
31ENDPROC(__c6xabi_negll)
diff --git a/arch/c6x/lib/pop_rts.S b/arch/c6x/lib/pop_rts.S
new file mode 100644
index 000000000000..d7d96c70e9e7
--- /dev/null
+++ b/arch/c6x/lib/pop_rts.S
@@ -0,0 +1,32 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21
22ENTRY(__c6xabi_pop_rts)
23 lddw .d2t2 *++B15, B3:B2
24 lddw .d2t1 *++B15, A11:A10
25 lddw .d2t2 *++B15, B11:B10
26 lddw .d2t1 *++B15, A13:A12
27 lddw .d2t2 *++B15, B13:B12
28 lddw .d2t1 *++B15, A15:A14
29|| b .s2 B3
30 ldw .d2t2 *++B15[2], B14
31 nop 4
32ENDPROC(__c6xabi_pop_rts)
diff --git a/arch/c6x/lib/push_rts.S b/arch/c6x/lib/push_rts.S
new file mode 100644
index 000000000000..f6e3db3b6065
--- /dev/null
+++ b/arch/c6x/lib/push_rts.S
@@ -0,0 +1,31 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21
22ENTRY(__c6xabi_push_rts)
23 stw .d2t2 B14, *B15--[2]
24 stdw .d2t1 A15:A14, *B15--
25|| b .s2x A3
26 stdw .d2t2 B13:B12, *B15--
27 stdw .d2t1 A13:A12, *B15--
28 stdw .d2t2 B11:B10, *B15--
29 stdw .d2t1 A11:A10, *B15--
30 stdw .d2t2 B3:B2, *B15--
31ENDPROC(__c6xabi_push_rts)
diff --git a/arch/c6x/lib/remi.S b/arch/c6x/lib/remi.S
new file mode 100644
index 000000000000..6f2ca18c3f98
--- /dev/null
+++ b/arch/c6x/lib/remi.S
@@ -0,0 +1,64 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 ;; ABI considerations for the divide functions
21 ;; The following registers are call-used:
22 ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
23 ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
24 ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
25 ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
26 ;;
27 ;; In our implementation, divu and remu are leaf functions,
28 ;; while both divi and remi call into divu.
29 ;; A0 is not clobbered by any of the functions.
30 ;; divu does not clobber B2 either, which is taken advantage of
31 ;; in remi.
32 ;; divi uses B5 to hold the original return address during
33 ;; the call to divu.
34 ;; remi uses B2 and A5 to hold the input values during the
35 ;; call to divu. It stores B3 in on the stack.
36
37 .text
38
39ENTRY(__c6xabi_remi)
40 stw .d2t2 B3, *B15--[2]
41|| cmpgt .l1 0, A4, A1
42|| cmpgt .l2 0, B4, B2
43|| mv .s1 A4, A5
44|| call .s2 __c6xabi_divu
45
46 [A1] neg .l1 A4, A4
47|| [B2] neg .l2 B4, B4
48|| xor .s2x B2, A1, B0
49|| mv .d2 B4, B2
50
51 [B0] addkpc .s2 _divu_ret_1, B3, 1
52 [!B0] addkpc .s2 _divu_ret_2, B3, 1
53 nop 2
54_divu_ret_1:
55 neg .l1 A4, A4
56_divu_ret_2:
57 ldw .d2t2 *++B15[2], B3
58
59 mpy32 .m1x A4, B2, A6
60 nop 3
61 ret .s2 B3
62 sub .l1 A5, A6, A4
63 nop 4
64ENDPROC(__c6xabi_remi)
diff --git a/arch/c6x/lib/remu.S b/arch/c6x/lib/remu.S
new file mode 100644
index 000000000000..3fae719185ab
--- /dev/null
+++ b/arch/c6x/lib/remu.S
@@ -0,0 +1,82 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 ;; ABI considerations for the divide functions
21 ;; The following registers are call-used:
22 ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
23 ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
24 ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
25 ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
26 ;;
27 ;; In our implementation, divu and remu are leaf functions,
28 ;; while both divi and remi call into divu.
29 ;; A0 is not clobbered by any of the functions.
30 ;; divu does not clobber B2 either, which is taken advantage of
31 ;; in remi.
32 ;; divi uses B5 to hold the original return address during
33 ;; the call to divu.
34 ;; remi uses B2 and A5 to hold the input values during the
35 ;; call to divu. It stores B3 in on the stack.
36
37
38 .text
39
40ENTRY(__c6xabi_remu)
41 ;; The ABI seems designed to prevent these functions calling each other,
42 ;; so we duplicate most of the divsi3 code here.
43 mv .s2x A4, B1
44 lmbd .l2 1, B4, B1
45|| [!B1] b .s2 B3 ; RETURN A
46|| [!B1] mvk .d2 1, B4
47
48 mv .l1x B1, A7
49|| shl .s2 B4, B1, B4
50
51 cmpltu .l1x A4, B4, A1
52 [!A1] sub .l1x A4, B4, A4
53 shru .s2 B4, 1, B4
54
55_remu_loop:
56 cmpgt .l2 B1, 7, B0
57|| [B1] subc .l1x A4,B4,A4
58|| [B1] add .s2 -1, B1, B1
59 ;; RETURN A may happen here (note: must happen before the next branch)
60 [B1] subc .l1x A4,B4,A4
61|| [B1] add .s2 -1, B1, B1
62|| [B0] b .s1 _remu_loop
63 [B1] subc .l1x A4,B4,A4
64|| [B1] add .s2 -1, B1, B1
65 [B1] subc .l1x A4,B4,A4
66|| [B1] add .s2 -1, B1, B1
67 [B1] subc .l1x A4,B4,A4
68|| [B1] add .s2 -1, B1, B1
69 [B1] subc .l1x A4,B4,A4
70|| [B1] add .s2 -1, B1, B1
71 [B1] subc .l1x A4,B4,A4
72|| [B1] add .s2 -1, B1, B1
73 ;; loop backwards branch happens here
74
75 ret .s2 B3
76 [B1] subc .l1x A4,B4,A4
77|| [B1] add .s2 -1, B1, B1
78 [B1] subc .l1x A4,B4,A4
79
80 extu .s1 A4, A7, A4
81 nop 2
82ENDPROC(__c6xabi_remu)
diff --git a/arch/c6x/lib/strasgi.S b/arch/c6x/lib/strasgi.S
new file mode 100644
index 000000000000..de2740765536
--- /dev/null
+++ b/arch/c6x/lib/strasgi.S
@@ -0,0 +1,89 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21
22ENTRY(__c6xabi_strasgi)
23 ;; This is essentially memcpy, with alignment known to be at least
24 ;; 4, and the size a multiple of 4 greater than or equal to 28.
25 ldw .d2t1 *B4++, A0
26|| mvk .s2 16, B1
27 ldw .d2t1 *B4++, A1
28|| mvk .s2 20, B2
29|| sub .d1 A6, 24, A6
30 ldw .d2t1 *B4++, A5
31 ldw .d2t1 *B4++, A7
32|| mv .l2x A6, B7
33 ldw .d2t1 *B4++, A8
34 ldw .d2t1 *B4++, A9
35|| mv .s2x A0, B5
36|| cmpltu .l2 B2, B7, B0
37
38_strasgi_loop:
39 stw .d1t2 B5, *A4++
40|| [B0] ldw .d2t1 *B4++, A0
41|| mv .s2x A1, B5
42|| mv .l2 B7, B6
43
44 [B0] sub .d2 B6, 24, B7
45|| [B0] b .s2 _strasgi_loop
46|| cmpltu .l2 B1, B6, B0
47
48 [B0] ldw .d2t1 *B4++, A1
49|| stw .d1t2 B5, *A4++
50|| mv .s2x A5, B5
51|| cmpltu .l2 12, B6, B0
52
53 [B0] ldw .d2t1 *B4++, A5
54|| stw .d1t2 B5, *A4++
55|| mv .s2x A7, B5
56|| cmpltu .l2 8, B6, B0
57
58 [B0] ldw .d2t1 *B4++, A7
59|| stw .d1t2 B5, *A4++
60|| mv .s2x A8, B5
61|| cmpltu .l2 4, B6, B0
62
63 [B0] ldw .d2t1 *B4++, A8
64|| stw .d1t2 B5, *A4++
65|| mv .s2x A9, B5
66|| cmpltu .l2 0, B6, B0
67
68 [B0] ldw .d2t1 *B4++, A9
69|| stw .d1t2 B5, *A4++
70|| mv .s2x A0, B5
71|| cmpltu .l2 B2, B7, B0
72
73 ;; loop back branch happens here
74
75 cmpltu .l2 B1, B6, B0
76|| ret .s2 b3
77
78 [B0] stw .d1t1 A1, *A4++
79|| cmpltu .l2 12, B6, B0
80 [B0] stw .d1t1 A5, *A4++
81|| cmpltu .l2 8, B6, B0
82 [B0] stw .d1t1 A7, *A4++
83|| cmpltu .l2 4, B6, B0
84 [B0] stw .d1t1 A8, *A4++
85|| cmpltu .l2 0, B6, B0
86 [B0] stw .d1t1 A9, *A4++
87
88 ;; return happens here
89ENDPROC(__c6xabi_strasgi)
diff --git a/arch/c6x/lib/strasgi_64plus.S b/arch/c6x/lib/strasgi_64plus.S
new file mode 100644
index 000000000000..c9fd159b5fa2
--- /dev/null
+++ b/arch/c6x/lib/strasgi_64plus.S
@@ -0,0 +1,39 @@
1;; Copyright 2010 Free Software Foundation, Inc.
2;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
3;;
4;; This program is free software; you can redistribute it and/or modify
5;; it under the terms of the GNU General Public License as published by
6;; the Free Software Foundation; either version 2 of the License, or
7;; (at your option) any later version.
8;;
9;; This program is distributed in the hope that it will be useful,
10;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12;; GNU General Public License for more details.
13;;
14;; You should have received a copy of the GNU General Public License
15;; along with this program; if not, write to the Free Software
16;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18#include <linux/linkage.h>
19
20 .text
21
22ENTRY(__c6xabi_strasgi_64plus)
23 shru .s2x a6, 2, b31
24|| mv .s1 a4, a30
25|| mv .d2 b4, b30
26
27 add .s2 -4, b31, b31
28
29 sploopd 1
30|| mvc .s2 b31, ilc
31 ldw .d2t2 *b30++, b31
32 nop 4
33 mv .s1x b31,a31
34 spkernel 6, 0
35|| stw .d1t1 a31, *a30++
36
37 ret .s2 b3
38 nop 5
39ENDPROC(__c6xabi_strasgi_64plus)
diff --git a/arch/c6x/mm/Makefile b/arch/c6x/mm/Makefile
new file mode 100644
index 000000000000..136a97576c61
--- /dev/null
+++ b/arch/c6x/mm/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the linux c6x-specific parts of the memory manager.
3#
4
5obj-y := init.o dma-coherent.o
diff --git a/arch/c6x/mm/dma-coherent.c b/arch/c6x/mm/dma-coherent.c
new file mode 100644
index 000000000000..4187e5180373
--- /dev/null
+++ b/arch/c6x/mm/dma-coherent.c
@@ -0,0 +1,143 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot <aurelien.jacquiot@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * DMA uncached mapping support.
12 *
13 * Using code pulled from ARM
14 * Copyright (C) 2000-2004 Russell King
15 *
16 */
17#include <linux/slab.h>
18#include <linux/bitmap.h>
19#include <linux/bitops.h>
20#include <linux/module.h>
21#include <linux/interrupt.h>
22#include <linux/dma-mapping.h>
23#include <linux/memblock.h>
24
25#include <asm/page.h>
26
27/*
28 * DMA coherent memory management, can be redefined using the memdma=
29 * kernel command line
30 */
31
32/* none by default */
33static phys_addr_t dma_base;
34static u32 dma_size;
35static u32 dma_pages;
36
37static unsigned long *dma_bitmap;
38
39/* bitmap lock */
40static DEFINE_SPINLOCK(dma_lock);
41
42/*
43 * Return a DMA coherent and contiguous memory chunk from the DMA memory
44 */
45static inline u32 __alloc_dma_pages(int order)
46{
47 unsigned long flags;
48 u32 pos;
49
50 spin_lock_irqsave(&dma_lock, flags);
51 pos = bitmap_find_free_region(dma_bitmap, dma_pages, order);
52 spin_unlock_irqrestore(&dma_lock, flags);
53
54 return dma_base + (pos << PAGE_SHIFT);
55}
56
57static void __free_dma_pages(u32 addr, int order)
58{
59 unsigned long flags;
60 u32 pos = (addr - dma_base) >> PAGE_SHIFT;
61
62 if (addr < dma_base || (pos + (1 << order)) >= dma_pages) {
63 printk(KERN_ERR "%s: freeing outside range.\n", __func__);
64 BUG();
65 }
66
67 spin_lock_irqsave(&dma_lock, flags);
68 bitmap_release_region(dma_bitmap, pos, order);
69 spin_unlock_irqrestore(&dma_lock, flags);
70}
71
72/*
73 * Allocate DMA coherent memory space and return both the kernel
74 * virtual and DMA address for that space.
75 */
76void *dma_alloc_coherent(struct device *dev, size_t size,
77 dma_addr_t *handle, gfp_t gfp)
78{
79 u32 paddr;
80 int order;
81
82 if (!dma_size || !size)
83 return NULL;
84
85 order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
86
87 paddr = __alloc_dma_pages(order);
88
89 if (handle)
90 *handle = paddr;
91
92 if (!paddr)
93 return NULL;
94
95 return phys_to_virt(paddr);
96}
97EXPORT_SYMBOL(dma_alloc_coherent);
98
99/*
100 * Free DMA coherent memory as defined by the above mapping.
101 */
102void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
103 dma_addr_t dma_handle)
104{
105 int order;
106
107 if (!dma_size || !size)
108 return;
109
110 order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1);
111
112 __free_dma_pages(virt_to_phys(vaddr), order);
113}
114EXPORT_SYMBOL(dma_free_coherent);
115
116/*
117 * Initialise the coherent DMA memory allocator using the given uncached region.
118 */
119void __init coherent_mem_init(phys_addr_t start, u32 size)
120{
121 phys_addr_t bitmap_phys;
122
123 if (!size)
124 return;
125
126 printk(KERN_INFO
127 "Coherent memory (DMA) region start=0x%x size=0x%x\n",
128 start, size);
129
130 dma_base = start;
131 dma_size = size;
132
133 /* allocate bitmap */
134 dma_pages = dma_size >> PAGE_SHIFT;
135 if (dma_size & (PAGE_SIZE - 1))
136 ++dma_pages;
137
138 bitmap_phys = memblock_alloc(BITS_TO_LONGS(dma_pages) * sizeof(long),
139 sizeof(long));
140
141 dma_bitmap = phys_to_virt(bitmap_phys);
142 memset(dma_bitmap, 0, dma_pages * PAGE_SIZE);
143}
diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c
new file mode 100644
index 000000000000..89395f09648a
--- /dev/null
+++ b/arch/c6x/mm/init.c
@@ -0,0 +1,113 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
5 * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/mm.h>
12#include <linux/swap.h>
13#include <linux/module.h>
14#include <linux/bootmem.h>
15#ifdef CONFIG_BLK_DEV_RAM
16#include <linux/blkdev.h>
17#endif
18#include <linux/initrd.h>
19
20#include <asm/sections.h>
21
22/*
23 * ZERO_PAGE is a special page that is used for zero-initialized
24 * data and COW.
25 */
26unsigned long empty_zero_page;
27EXPORT_SYMBOL(empty_zero_page);
28
29/*
30 * paging_init() continues the virtual memory environment setup which
31 * was begun by the code in arch/head.S.
32 * The parameters are pointers to where to stick the starting and ending
33 * addresses of available kernel virtual memory.
34 */
35void __init paging_init(void)
36{
37 struct pglist_data *pgdat = NODE_DATA(0);
38 unsigned long zones_size[MAX_NR_ZONES] = {0, };
39
40 empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
41 memset((void *)empty_zero_page, 0, PAGE_SIZE);
42
43 /*
44 * Set up user data space
45 */
46 set_fs(KERNEL_DS);
47
48 /*
49 * Define zones
50 */
51 zones_size[ZONE_NORMAL] = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT;
52 pgdat->node_zones[ZONE_NORMAL].zone_start_pfn =
53 __pa(PAGE_OFFSET) >> PAGE_SHIFT;
54
55 free_area_init(zones_size);
56}
57
58void __init mem_init(void)
59{
60 int codek, datak;
61 unsigned long tmp;
62 unsigned long len = memory_end - memory_start;
63
64 high_memory = (void *)(memory_end & PAGE_MASK);
65
66 /* this will put all memory onto the freelists */
67 totalram_pages = free_all_bootmem();
68
69 codek = (_etext - _stext) >> 10;
70 datak = (_end - _sdata) >> 10;
71
72 tmp = nr_free_pages() << PAGE_SHIFT;
73 printk(KERN_INFO "Memory: %luk/%luk RAM (%dk kernel code, %dk data)\n",
74 tmp >> 10, len >> 10, codek, datak);
75}
76
77#ifdef CONFIG_BLK_DEV_INITRD
78void __init free_initrd_mem(unsigned long start, unsigned long end)
79{
80 int pages = 0;
81 for (; start < end; start += PAGE_SIZE) {
82 ClearPageReserved(virt_to_page(start));
83 init_page_count(virt_to_page(start));
84 free_page(start);
85 totalram_pages++;
86 pages++;
87 }
88 printk(KERN_INFO "Freeing initrd memory: %luk freed\n",
89 (pages * PAGE_SIZE) >> 10);
90}
91#endif
92
93void __init free_initmem(void)
94{
95 unsigned long addr;
96
97 /*
98 * The following code should be cool even if these sections
99 * are not page aligned.
100 */
101 addr = PAGE_ALIGN((unsigned long)(__init_begin));
102
103 /* next to check that the page we free is not a partial page */
104 for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
105 addr += PAGE_SIZE) {
106 ClearPageReserved(virt_to_page(addr));
107 init_page_count(virt_to_page(addr));
108 free_page(addr);
109 totalram_pages++;
110 }
111 printk(KERN_INFO "Freeing unused kernel memory: %dK freed\n",
112 (int) ((addr - PAGE_ALIGN((long) &__init_begin)) >> 10));
113}
diff --git a/arch/c6x/platforms/Kconfig b/arch/c6x/platforms/Kconfig
new file mode 100644
index 000000000000..401ee678fd01
--- /dev/null
+++ b/arch/c6x/platforms/Kconfig
@@ -0,0 +1,16 @@
1
2config SOC_TMS320C6455
3 bool "TMS320C6455"
4 default n
5
6config SOC_TMS320C6457
7 bool "TMS320C6457"
8 default n
9
10config SOC_TMS320C6472
11 bool "TMS320C6472"
12 default n
13
14config SOC_TMS320C6474
15 bool "TMS320C6474"
16 default n
diff --git a/arch/c6x/platforms/Makefile b/arch/c6x/platforms/Makefile
new file mode 100644
index 000000000000..9a95b9bca8d0
--- /dev/null
+++ b/arch/c6x/platforms/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for arch/c6x/platforms
3#
4# Copyright 2010, 2011 Texas Instruments Incorporated
5#
6
7obj-y = platform.o cache.o megamod-pic.o pll.o plldata.o timer64.o
8obj-y += dscr.o
9
10# SoC objects
11obj-$(CONFIG_SOC_TMS320C6455) += emif.o
12obj-$(CONFIG_SOC_TMS320C6457) += emif.o
diff --git a/arch/c6x/platforms/cache.c b/arch/c6x/platforms/cache.c
new file mode 100644
index 000000000000..86318a16a252
--- /dev/null
+++ b/arch/c6x/platforms/cache.c
@@ -0,0 +1,445 @@
1/*
2 * Copyright (C) 2011 Texas Instruments Incorporated
3 * Author: Mark Salter <msalter@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9#include <linux/of.h>
10#include <linux/of_address.h>
11#include <linux/io.h>
12
13#include <asm/cache.h>
14#include <asm/soc.h>
15
16/*
17 * Internal Memory Control Registers for caches
18 */
19#define IMCR_CCFG 0x0000
20#define IMCR_L1PCFG 0x0020
21#define IMCR_L1PCC 0x0024
22#define IMCR_L1DCFG 0x0040
23#define IMCR_L1DCC 0x0044
24#define IMCR_L2ALLOC0 0x2000
25#define IMCR_L2ALLOC1 0x2004
26#define IMCR_L2ALLOC2 0x2008
27#define IMCR_L2ALLOC3 0x200c
28#define IMCR_L2WBAR 0x4000
29#define IMCR_L2WWC 0x4004
30#define IMCR_L2WIBAR 0x4010
31#define IMCR_L2WIWC 0x4014
32#define IMCR_L2IBAR 0x4018
33#define IMCR_L2IWC 0x401c
34#define IMCR_L1PIBAR 0x4020
35#define IMCR_L1PIWC 0x4024
36#define IMCR_L1DWIBAR 0x4030
37#define IMCR_L1DWIWC 0x4034
38#define IMCR_L1DWBAR 0x4040
39#define IMCR_L1DWWC 0x4044
40#define IMCR_L1DIBAR 0x4048
41#define IMCR_L1DIWC 0x404c
42#define IMCR_L2WB 0x5000
43#define IMCR_L2WBINV 0x5004
44#define IMCR_L2INV 0x5008
45#define IMCR_L1PINV 0x5028
46#define IMCR_L1DWB 0x5040
47#define IMCR_L1DWBINV 0x5044
48#define IMCR_L1DINV 0x5048
49#define IMCR_MAR_BASE 0x8000
50#define IMCR_MAR96_111 0x8180
51#define IMCR_MAR128_191 0x8200
52#define IMCR_MAR224_239 0x8380
53#define IMCR_L2MPFAR 0xa000
54#define IMCR_L2MPFSR 0xa004
55#define IMCR_L2MPFCR 0xa008
56#define IMCR_L2MPLK0 0xa100
57#define IMCR_L2MPLK1 0xa104
58#define IMCR_L2MPLK2 0xa108
59#define IMCR_L2MPLK3 0xa10c
60#define IMCR_L2MPLKCMD 0xa110
61#define IMCR_L2MPLKSTAT 0xa114
62#define IMCR_L2MPPA_BASE 0xa200
63#define IMCR_L1PMPFAR 0xa400
64#define IMCR_L1PMPFSR 0xa404
65#define IMCR_L1PMPFCR 0xa408
66#define IMCR_L1PMPLK0 0xa500
67#define IMCR_L1PMPLK1 0xa504
68#define IMCR_L1PMPLK2 0xa508
69#define IMCR_L1PMPLK3 0xa50c
70#define IMCR_L1PMPLKCMD 0xa510
71#define IMCR_L1PMPLKSTAT 0xa514
72#define IMCR_L1PMPPA_BASE 0xa600
73#define IMCR_L1DMPFAR 0xac00
74#define IMCR_L1DMPFSR 0xac04
75#define IMCR_L1DMPFCR 0xac08
76#define IMCR_L1DMPLK0 0xad00
77#define IMCR_L1DMPLK1 0xad04
78#define IMCR_L1DMPLK2 0xad08
79#define IMCR_L1DMPLK3 0xad0c
80#define IMCR_L1DMPLKCMD 0xad10
81#define IMCR_L1DMPLKSTAT 0xad14
82#define IMCR_L1DMPPA_BASE 0xae00
83#define IMCR_L2PDWAKE0 0xc040
84#define IMCR_L2PDWAKE1 0xc044
85#define IMCR_L2PDSLEEP0 0xc050
86#define IMCR_L2PDSLEEP1 0xc054
87#define IMCR_L2PDSTAT0 0xc060
88#define IMCR_L2PDSTAT1 0xc064
89
90/*
91 * CCFG register values and bits
92 */
93#define L2MODE_0K_CACHE 0x0
94#define L2MODE_32K_CACHE 0x1
95#define L2MODE_64K_CACHE 0x2
96#define L2MODE_128K_CACHE 0x3
97#define L2MODE_256K_CACHE 0x7
98
99#define L2PRIO_URGENT 0x0
100#define L2PRIO_HIGH 0x1
101#define L2PRIO_MEDIUM 0x2
102#define L2PRIO_LOW 0x3
103
104#define CCFG_ID 0x100 /* Invalidate L1P bit */
105#define CCFG_IP 0x200 /* Invalidate L1D bit */
106
107static void __iomem *cache_base;
108
109/*
110 * L1 & L2 caches generic functions
111 */
112#define imcr_get(reg) soc_readl(cache_base + (reg))
113#define imcr_set(reg, value) \
114do { \
115 soc_writel((value), cache_base + (reg)); \
116 soc_readl(cache_base + (reg)); \
117} while (0)
118
119static void cache_block_operation_wait(unsigned int wc_reg)
120{
121 /* Wait for completion */
122 while (imcr_get(wc_reg))
123 cpu_relax();
124}
125
126static DEFINE_SPINLOCK(cache_lock);
127
128/*
129 * Generic function to perform a block cache operation as
130 * invalidate or writeback/invalidate
131 */
132static void cache_block_operation(unsigned int *start,
133 unsigned int *end,
134 unsigned int bar_reg,
135 unsigned int wc_reg)
136{
137 unsigned long flags;
138 unsigned int wcnt =
139 (L2_CACHE_ALIGN_CNT((unsigned int) end)
140 - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2;
141 unsigned int wc = 0;
142
143 for (; wcnt; wcnt -= wc, start += wc) {
144loop:
145 spin_lock_irqsave(&cache_lock, flags);
146
147 /*
148 * If another cache operation is occuring
149 */
150 if (unlikely(imcr_get(wc_reg))) {
151 spin_unlock_irqrestore(&cache_lock, flags);
152
153 /* Wait for previous operation completion */
154 cache_block_operation_wait(wc_reg);
155
156 /* Try again */
157 goto loop;
158 }
159
160 imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start));
161
162 if (wcnt > 0xffff)
163 wc = 0xffff;
164 else
165 wc = wcnt;
166
167 /* Set word count value in the WC register */
168 imcr_set(wc_reg, wc & 0xffff);
169
170 spin_unlock_irqrestore(&cache_lock, flags);
171
172 /* Wait for completion */
173 cache_block_operation_wait(wc_reg);
174 }
175}
176
177static void cache_block_operation_nowait(unsigned int *start,
178 unsigned int *end,
179 unsigned int bar_reg,
180 unsigned int wc_reg)
181{
182 unsigned long flags;
183 unsigned int wcnt =
184 (L2_CACHE_ALIGN_CNT((unsigned int) end)
185 - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2;
186 unsigned int wc = 0;
187
188 for (; wcnt; wcnt -= wc, start += wc) {
189
190 spin_lock_irqsave(&cache_lock, flags);
191
192 imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start));
193
194 if (wcnt > 0xffff)
195 wc = 0xffff;
196 else
197 wc = wcnt;
198
199 /* Set word count value in the WC register */
200 imcr_set(wc_reg, wc & 0xffff);
201
202 spin_unlock_irqrestore(&cache_lock, flags);
203
204 /* Don't wait for completion on last cache operation */
205 if (wcnt > 0xffff)
206 cache_block_operation_wait(wc_reg);
207 }
208}
209
210/*
211 * L1 caches management
212 */
213
214/*
215 * Disable L1 caches
216 */
217void L1_cache_off(void)
218{
219 unsigned int dummy;
220
221 imcr_set(IMCR_L1PCFG, 0);
222 dummy = imcr_get(IMCR_L1PCFG);
223
224 imcr_set(IMCR_L1DCFG, 0);
225 dummy = imcr_get(IMCR_L1DCFG);
226}
227
228/*
229 * Enable L1 caches
230 */
231void L1_cache_on(void)
232{
233 unsigned int dummy;
234
235 imcr_set(IMCR_L1PCFG, 7);
236 dummy = imcr_get(IMCR_L1PCFG);
237
238 imcr_set(IMCR_L1DCFG, 7);
239 dummy = imcr_get(IMCR_L1DCFG);
240}
241
242/*
243 * L1P global-invalidate all
244 */
245void L1P_cache_global_invalidate(void)
246{
247 unsigned int set = 1;
248 imcr_set(IMCR_L1PINV, set);
249 while (imcr_get(IMCR_L1PINV) & 1)
250 cpu_relax();
251}
252
253/*
254 * L1D global-invalidate all
255 *
256 * Warning: this operation causes all updated data in L1D to
257 * be discarded rather than written back to the lower levels of
258 * memory
259 */
260void L1D_cache_global_invalidate(void)
261{
262 unsigned int set = 1;
263 imcr_set(IMCR_L1DINV, set);
264 while (imcr_get(IMCR_L1DINV) & 1)
265 cpu_relax();
266}
267
268void L1D_cache_global_writeback(void)
269{
270 unsigned int set = 1;
271 imcr_set(IMCR_L1DWB, set);
272 while (imcr_get(IMCR_L1DWB) & 1)
273 cpu_relax();
274}
275
276void L1D_cache_global_writeback_invalidate(void)
277{
278 unsigned int set = 1;
279 imcr_set(IMCR_L1DWBINV, set);
280 while (imcr_get(IMCR_L1DWBINV) & 1)
281 cpu_relax();
282}
283
284/*
285 * L2 caches management
286 */
287
288/*
289 * Set L2 operation mode
290 */
291void L2_cache_set_mode(unsigned int mode)
292{
293 unsigned int ccfg = imcr_get(IMCR_CCFG);
294
295 /* Clear and set the L2MODE bits in CCFG */
296 ccfg &= ~7;
297 ccfg |= (mode & 7);
298 imcr_set(IMCR_CCFG, ccfg);
299 ccfg = imcr_get(IMCR_CCFG);
300}
301
302/*
303 * L2 global-writeback and global-invalidate all
304 */
305void L2_cache_global_writeback_invalidate(void)
306{
307 imcr_set(IMCR_L2WBINV, 1);
308 while (imcr_get(IMCR_L2WBINV))
309 cpu_relax();
310}
311
312/*
313 * L2 global-writeback all
314 */
315void L2_cache_global_writeback(void)
316{
317 imcr_set(IMCR_L2WB, 1);
318 while (imcr_get(IMCR_L2WB))
319 cpu_relax();
320}
321
322/*
323 * Cacheability controls
324 */
325void enable_caching(unsigned long start, unsigned long end)
326{
327 unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2);
328 unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2);
329
330 for (; mar <= mar_e; mar += 4)
331 imcr_set(mar, imcr_get(mar) | 1);
332}
333
334void disable_caching(unsigned long start, unsigned long end)
335{
336 unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2);
337 unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2);
338
339 for (; mar <= mar_e; mar += 4)
340 imcr_set(mar, imcr_get(mar) & ~1);
341}
342
343
344/*
345 * L1 block operations
346 */
347void L1P_cache_block_invalidate(unsigned int start, unsigned int end)
348{
349 cache_block_operation((unsigned int *) start,
350 (unsigned int *) end,
351 IMCR_L1PIBAR, IMCR_L1PIWC);
352}
353
354void L1D_cache_block_invalidate(unsigned int start, unsigned int end)
355{
356 cache_block_operation((unsigned int *) start,
357 (unsigned int *) end,
358 IMCR_L1DIBAR, IMCR_L1DIWC);
359}
360
361void L1D_cache_block_writeback_invalidate(unsigned int start, unsigned int end)
362{
363 cache_block_operation((unsigned int *) start,
364 (unsigned int *) end,
365 IMCR_L1DWIBAR, IMCR_L1DWIWC);
366}
367
368void L1D_cache_block_writeback(unsigned int start, unsigned int end)
369{
370 cache_block_operation((unsigned int *) start,
371 (unsigned int *) end,
372 IMCR_L1DWBAR, IMCR_L1DWWC);
373}
374
375/*
376 * L2 block operations
377 */
378void L2_cache_block_invalidate(unsigned int start, unsigned int end)
379{
380 cache_block_operation((unsigned int *) start,
381 (unsigned int *) end,
382 IMCR_L2IBAR, IMCR_L2IWC);
383}
384
385void L2_cache_block_writeback(unsigned int start, unsigned int end)
386{
387 cache_block_operation((unsigned int *) start,
388 (unsigned int *) end,
389 IMCR_L2WBAR, IMCR_L2WWC);
390}
391
392void L2_cache_block_writeback_invalidate(unsigned int start, unsigned int end)
393{
394 cache_block_operation((unsigned int *) start,
395 (unsigned int *) end,
396 IMCR_L2WIBAR, IMCR_L2WIWC);
397}
398
399void L2_cache_block_invalidate_nowait(unsigned int start, unsigned int end)
400{
401 cache_block_operation_nowait((unsigned int *) start,
402 (unsigned int *) end,
403 IMCR_L2IBAR, IMCR_L2IWC);
404}
405
406void L2_cache_block_writeback_nowait(unsigned int start, unsigned int end)
407{
408 cache_block_operation_nowait((unsigned int *) start,
409 (unsigned int *) end,
410 IMCR_L2WBAR, IMCR_L2WWC);
411}
412
413void L2_cache_block_writeback_invalidate_nowait(unsigned int start,
414 unsigned int end)
415{
416 cache_block_operation_nowait((unsigned int *) start,
417 (unsigned int *) end,
418 IMCR_L2WIBAR, IMCR_L2WIWC);
419}
420
421
422/*
423 * L1 and L2 caches configuration
424 */
425void __init c6x_cache_init(void)
426{
427 struct device_node *node;
428
429 node = of_find_compatible_node(NULL, NULL, "ti,c64x+cache");
430 if (!node)
431 return;
432
433 cache_base = of_iomap(node, 0);
434
435 of_node_put(node);
436
437 if (!cache_base)
438 return;
439
440 /* Set L2 caches on the the whole L2 SRAM memory */
441 L2_cache_set_mode(L2MODE_SIZE);
442
443 /* Enable L1 */
444 L1_cache_on();
445}
diff --git a/arch/c6x/platforms/dscr.c b/arch/c6x/platforms/dscr.c
new file mode 100644
index 000000000000..f848a65ee646
--- /dev/null
+++ b/arch/c6x/platforms/dscr.c
@@ -0,0 +1,598 @@
1/*
2 * Device State Control Registers driver
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12/*
13 * The Device State Control Registers (DSCR) provide SoC level control over
14 * a number of peripherals. Details vary considerably among the various SoC
15 * parts. In general, the DSCR block will provide one or more configuration
16 * registers often protected by a lock register. One or more key values must
17 * be written to a lock register in order to unlock the configuration register.
18 * The configuration register may be used to enable (and disable in some
19 * cases) SoC pin drivers, peripheral clock sources (internal or pin), etc.
20 * In some cases, a configuration register is write once or the individual
21 * bits are write once. That is, you may be able to enable a device, but
22 * will not be able to disable it.
23 *
24 * In addition to device configuration, the DSCR block may provide registers
25 * which are used to reset SoC peripherals, provide device ID information,
26 * provide MAC addresses, and other miscellaneous functions.
27 */
28
29#include <linux/of.h>
30#include <linux/of_address.h>
31#include <linux/of_platform.h>
32#include <linux/module.h>
33#include <linux/io.h>
34#include <linux/delay.h>
35#include <asm/soc.h>
36#include <asm/dscr.h>
37
38#define MAX_DEVSTATE_IDS 32
39#define MAX_DEVCTL_REGS 8
40#define MAX_DEVSTAT_REGS 8
41#define MAX_LOCKED_REGS 4
42#define MAX_SOC_EMACS 2
43
44struct rmii_reset_reg {
45 u32 reg;
46 u32 mask;
47};
48
49/*
50 * Some registerd may be locked. In order to write to these
51 * registers, the key value must first be written to the lockreg.
52 */
53struct locked_reg {
54 u32 reg; /* offset from base */
55 u32 lockreg; /* offset from base */
56 u32 key; /* unlock key */
57};
58
59/*
60 * This describes a contiguous area of like control bits used to enable/disable
61 * SoC devices. Each controllable device is given an ID which is used by the
62 * individual device drivers to control the device state. These IDs start at
63 * zero and are assigned sequentially to the control bitfield ranges described
64 * by this structure.
65 */
66struct devstate_ctl_reg {
67 u32 reg; /* register holding the control bits */
68 u8 start_id; /* start id of this range */
69 u8 num_ids; /* number of devices in this range */
70 u8 enable_only; /* bits are write-once to enable only */
71 u8 enable; /* value used to enable device */
72 u8 disable; /* value used to disable device */
73 u8 shift; /* starting (rightmost) bit in range */
74 u8 nbits; /* number of bits per device */
75};
76
77
78/*
79 * This describes a region of status bits indicating the state of
80 * various devices. This is used internally to wait for status
81 * change completion when enabling/disabling a device. Status is
82 * optional and not all device controls will have a corresponding
83 * status.
84 */
85struct devstate_stat_reg {
86 u32 reg; /* register holding the status bits */
87 u8 start_id; /* start id of this range */
88 u8 num_ids; /* number of devices in this range */
89 u8 enable; /* value indicating enabled state */
90 u8 disable; /* value indicating disabled state */
91 u8 shift; /* starting (rightmost) bit in range */
92 u8 nbits; /* number of bits per device */
93};
94
95struct devstate_info {
96 struct devstate_ctl_reg *ctl;
97 struct devstate_stat_reg *stat;
98};
99
100/* These are callbacks to SOC-specific code. */
101struct dscr_ops {
102 void (*init)(struct device_node *node);
103};
104
105struct dscr_regs {
106 spinlock_t lock;
107 void __iomem *base;
108 u32 kick_reg[2];
109 u32 kick_key[2];
110 struct locked_reg locked[MAX_LOCKED_REGS];
111 struct devstate_info devstate_info[MAX_DEVSTATE_IDS];
112 struct rmii_reset_reg rmii_resets[MAX_SOC_EMACS];
113 struct devstate_ctl_reg devctl[MAX_DEVCTL_REGS];
114 struct devstate_stat_reg devstat[MAX_DEVSTAT_REGS];
115};
116
117static struct dscr_regs dscr;
118
119static struct locked_reg *find_locked_reg(u32 reg)
120{
121 int i;
122
123 for (i = 0; i < MAX_LOCKED_REGS; i++)
124 if (dscr.locked[i].key && reg == dscr.locked[i].reg)
125 return &dscr.locked[i];
126 return NULL;
127}
128
129/*
130 * Write to a register with one lock
131 */
132static void dscr_write_locked1(u32 reg, u32 val,
133 u32 lock, u32 key)
134{
135 void __iomem *reg_addr = dscr.base + reg;
136 void __iomem *lock_addr = dscr.base + lock;
137
138 /*
139 * For some registers, the lock is relocked after a short number
140 * of cycles. We have to put the lock write and register write in
141 * the same fetch packet to meet this timing. The .align ensures
142 * the two stw instructions are in the same fetch packet.
143 */
144 asm volatile ("b .s2 0f\n"
145 "nop 5\n"
146 " .align 5\n"
147 "0:\n"
148 "stw .D1T2 %3,*%2\n"
149 "stw .D1T2 %1,*%0\n"
150 :
151 : "a"(reg_addr), "b"(val), "a"(lock_addr), "b"(key)
152 );
153
154 /* in case the hw doesn't reset the lock */
155 soc_writel(0, lock_addr);
156}
157
158/*
159 * Write to a register protected by two lock registers
160 */
161static void dscr_write_locked2(u32 reg, u32 val,
162 u32 lock0, u32 key0,
163 u32 lock1, u32 key1)
164{
165 soc_writel(key0, dscr.base + lock0);
166 soc_writel(key1, dscr.base + lock1);
167 soc_writel(val, dscr.base + reg);
168 soc_writel(0, dscr.base + lock0);
169 soc_writel(0, dscr.base + lock1);
170}
171
172static void dscr_write(u32 reg, u32 val)
173{
174 struct locked_reg *lock;
175
176 lock = find_locked_reg(reg);
177 if (lock)
178 dscr_write_locked1(reg, val, lock->lockreg, lock->key);
179 else if (dscr.kick_key[0])
180 dscr_write_locked2(reg, val, dscr.kick_reg[0], dscr.kick_key[0],
181 dscr.kick_reg[1], dscr.kick_key[1]);
182 else
183 soc_writel(val, dscr.base + reg);
184}
185
186
187/*
188 * Drivers can use this interface to enable/disable SoC IP blocks.
189 */
190void dscr_set_devstate(int id, enum dscr_devstate_t state)
191{
192 struct devstate_ctl_reg *ctl;
193 struct devstate_stat_reg *stat;
194 struct devstate_info *info;
195 u32 ctl_val, val;
196 int ctl_shift, ctl_mask;
197 unsigned long flags;
198
199 if (!dscr.base)
200 return;
201
202 if (id < 0 || id >= MAX_DEVSTATE_IDS)
203 return;
204
205 info = &dscr.devstate_info[id];
206 ctl = info->ctl;
207 stat = info->stat;
208
209 if (ctl == NULL)
210 return;
211
212 ctl_shift = ctl->shift + ctl->nbits * (id - ctl->start_id);
213 ctl_mask = ((1 << ctl->nbits) - 1) << ctl_shift;
214
215 switch (state) {
216 case DSCR_DEVSTATE_ENABLED:
217 ctl_val = ctl->enable << ctl_shift;
218 break;
219 case DSCR_DEVSTATE_DISABLED:
220 if (ctl->enable_only)
221 return;
222 ctl_val = ctl->disable << ctl_shift;
223 break;
224 default:
225 return;
226 }
227
228 spin_lock_irqsave(&dscr.lock, flags);
229
230 val = soc_readl(dscr.base + ctl->reg);
231 val &= ~ctl_mask;
232 val |= ctl_val;
233
234 dscr_write(ctl->reg, val);
235
236 spin_unlock_irqrestore(&dscr.lock, flags);
237
238 if (!stat)
239 return;
240
241 ctl_shift = stat->shift + stat->nbits * (id - stat->start_id);
242
243 if (state == DSCR_DEVSTATE_ENABLED)
244 ctl_val = stat->enable;
245 else
246 ctl_val = stat->disable;
247
248 do {
249 val = soc_readl(dscr.base + stat->reg);
250 val >>= ctl_shift;
251 val &= ((1 << stat->nbits) - 1);
252 } while (val != ctl_val);
253}
254EXPORT_SYMBOL(dscr_set_devstate);
255
256/*
257 * Drivers can use this to reset RMII module.
258 */
259void dscr_rmii_reset(int id, int assert)
260{
261 struct rmii_reset_reg *r;
262 unsigned long flags;
263 u32 val;
264
265 if (id < 0 || id >= MAX_SOC_EMACS)
266 return;
267
268 r = &dscr.rmii_resets[id];
269 if (r->mask == 0)
270 return;
271
272 spin_lock_irqsave(&dscr.lock, flags);
273
274 val = soc_readl(dscr.base + r->reg);
275 if (assert)
276 dscr_write(r->reg, val | r->mask);
277 else
278 dscr_write(r->reg, val & ~(r->mask));
279
280 spin_unlock_irqrestore(&dscr.lock, flags);
281}
282EXPORT_SYMBOL(dscr_rmii_reset);
283
284static void __init dscr_parse_devstat(struct device_node *node,
285 void __iomem *base)
286{
287 u32 val;
288 int err;
289
290 err = of_property_read_u32_array(node, "ti,dscr-devstat", &val, 1);
291 if (!err)
292 c6x_devstat = soc_readl(base + val);
293 printk(KERN_INFO "DEVSTAT: %08x\n", c6x_devstat);
294}
295
296static void __init dscr_parse_silicon_rev(struct device_node *node,
297 void __iomem *base)
298{
299 u32 vals[3];
300 int err;
301
302 err = of_property_read_u32_array(node, "ti,dscr-silicon-rev", vals, 3);
303 if (!err) {
304 c6x_silicon_rev = soc_readl(base + vals[0]);
305 c6x_silicon_rev >>= vals[1];
306 c6x_silicon_rev &= vals[2];
307 }
308}
309
310/*
311 * Some SoCs will have a pair of fuse registers which hold
312 * an ethernet MAC address. The "ti,dscr-mac-fuse-regs"
313 * property is a mapping from fuse register bytes to MAC
314 * address bytes. The expected format is:
315 *
316 * ti,dscr-mac-fuse-regs = <reg0 b3 b2 b1 b0
317 * reg1 b3 b2 b1 b0>
318 *
319 * reg0 and reg1 are the offsets of the two fuse registers.
320 * b3-b0 positionally represent bytes within the fuse register.
321 * b3 is the most significant byte and b0 is the least.
322 * Allowable values for b3-b0 are:
323 *
324 * 0 = fuse register byte not used in MAC address
325 * 1-6 = index+1 into c6x_fuse_mac[]
326 */
327static void __init dscr_parse_mac_fuse(struct device_node *node,
328 void __iomem *base)
329{
330 u32 vals[10], fuse;
331 int f, i, j, err;
332
333 err = of_property_read_u32_array(node, "ti,dscr-mac-fuse-regs",
334 vals, 10);
335 if (err)
336 return;
337
338 for (f = 0; f < 2; f++) {
339 fuse = soc_readl(base + vals[f * 5]);
340 for (j = (f * 5) + 1, i = 24; i >= 0; i -= 8, j++)
341 if (vals[j] && vals[j] <= 6)
342 c6x_fuse_mac[vals[j] - 1] = fuse >> i;
343 }
344}
345
346static void __init dscr_parse_rmii_resets(struct device_node *node,
347 void __iomem *base)
348{
349 const __be32 *p;
350 int i, size;
351
352 /* look for RMII reset registers */
353 p = of_get_property(node, "ti,dscr-rmii-resets", &size);
354 if (p) {
355 /* parse all the reg/mask pairs we can handle */
356 size /= (sizeof(*p) * 2);
357 if (size > MAX_SOC_EMACS)
358 size = MAX_SOC_EMACS;
359
360 for (i = 0; i < size; i++) {
361 dscr.rmii_resets[i].reg = be32_to_cpup(p++);
362 dscr.rmii_resets[i].mask = be32_to_cpup(p++);
363 }
364 }
365}
366
367
368static void __init dscr_parse_privperm(struct device_node *node,
369 void __iomem *base)
370{
371 u32 vals[2];
372 int err;
373
374 err = of_property_read_u32_array(node, "ti,dscr-privperm", vals, 2);
375 if (err)
376 return;
377 dscr_write(vals[0], vals[1]);
378}
379
380/*
381 * SoCs may have "locked" DSCR registers which can only be written
382 * to only after writing a key value to a lock registers. These
383 * regisers can be described with the "ti,dscr-locked-regs" property.
384 * This property provides a list of register descriptions with each
385 * description consisting of three values.
386 *
387 * ti,dscr-locked-regs = <reg0 lockreg0 key0
388 * ...
389 * regN lockregN keyN>;
390 *
391 * reg is the offset of the locked register
392 * lockreg is the offset of the lock register
393 * key is the unlock key written to lockreg
394 *
395 */
396static void __init dscr_parse_locked_regs(struct device_node *node,
397 void __iomem *base)
398{
399 struct locked_reg *r;
400 const __be32 *p;
401 int i, size;
402
403 p = of_get_property(node, "ti,dscr-locked-regs", &size);
404 if (p) {
405 /* parse all the register descriptions we can handle */
406 size /= (sizeof(*p) * 3);
407 if (size > MAX_LOCKED_REGS)
408 size = MAX_LOCKED_REGS;
409
410 for (i = 0; i < size; i++) {
411 r = &dscr.locked[i];
412
413 r->reg = be32_to_cpup(p++);
414 r->lockreg = be32_to_cpup(p++);
415 r->key = be32_to_cpup(p++);
416 }
417 }
418}
419
420/*
421 * SoCs may have DSCR registers which are only write enabled after
422 * writing specific key values to two registers. The two key registers
423 * and the key values can be parsed from a "ti,dscr-kick-regs"
424 * propety with the following layout:
425 *
426 * ti,dscr-kick-regs = <kickreg0 key0 kickreg1 key1>
427 *
428 * kickreg is the offset of the "kick" register
429 * key is the value which unlocks writing for protected regs
430 */
431static void __init dscr_parse_kick_regs(struct device_node *node,
432 void __iomem *base)
433{
434 u32 vals[4];
435 int err;
436
437 err = of_property_read_u32_array(node, "ti,dscr-kick-regs", vals, 4);
438 if (!err) {
439 dscr.kick_reg[0] = vals[0];
440 dscr.kick_key[0] = vals[1];
441 dscr.kick_reg[1] = vals[2];
442 dscr.kick_key[1] = vals[3];
443 }
444}
445
446
447/*
448 * SoCs may provide controls to enable/disable individual IP blocks. These
449 * controls in the DSCR usually control pin drivers but also may control
450 * clocking and or resets. The device tree is used to describe the bitfields
451 * in registers used to control device state. The number of bits and their
452 * values may vary even within the same register.
453 *
454 * The layout of these bitfields is described by the ti,dscr-devstate-ctl-regs
455 * property. This property is a list where each element describes a contiguous
456 * range of control fields with like properties. Each element of the list
457 * consists of 7 cells with the following values:
458 *
459 * start_id num_ids reg enable disable start_bit nbits
460 *
461 * start_id is device id for the first device control in the range
462 * num_ids is the number of device controls in the range
463 * reg is the offset of the register holding the control bits
464 * enable is the value to enable a device
465 * disable is the value to disable a device (0xffffffff if cannot disable)
466 * start_bit is the bit number of the first bit in the range
467 * nbits is the number of bits per device control
468 */
469static void __init dscr_parse_devstate_ctl_regs(struct device_node *node,
470 void __iomem *base)
471{
472 struct devstate_ctl_reg *r;
473 const __be32 *p;
474 int i, j, size;
475
476 p = of_get_property(node, "ti,dscr-devstate-ctl-regs", &size);
477 if (p) {
478 /* parse all the ranges we can handle */
479 size /= (sizeof(*p) * 7);
480 if (size > MAX_DEVCTL_REGS)
481 size = MAX_DEVCTL_REGS;
482
483 for (i = 0; i < size; i++) {
484 r = &dscr.devctl[i];
485
486 r->start_id = be32_to_cpup(p++);
487 r->num_ids = be32_to_cpup(p++);
488 r->reg = be32_to_cpup(p++);
489 r->enable = be32_to_cpup(p++);
490 r->disable = be32_to_cpup(p++);
491 if (r->disable == 0xffffffff)
492 r->enable_only = 1;
493 r->shift = be32_to_cpup(p++);
494 r->nbits = be32_to_cpup(p++);
495
496 for (j = r->start_id;
497 j < (r->start_id + r->num_ids);
498 j++)
499 dscr.devstate_info[j].ctl = r;
500 }
501 }
502}
503
504/*
505 * SoCs may provide status registers indicating the state (enabled/disabled) of
506 * devices on the SoC. The device tree is used to describe the bitfields in
507 * registers used to provide device status. The number of bits and their
508 * values used to provide status may vary even within the same register.
509 *
510 * The layout of these bitfields is described by the ti,dscr-devstate-stat-regs
511 * property. This property is a list where each element describes a contiguous
512 * range of status fields with like properties. Each element of the list
513 * consists of 7 cells with the following values:
514 *
515 * start_id num_ids reg enable disable start_bit nbits
516 *
517 * start_id is device id for the first device status in the range
518 * num_ids is the number of devices covered by the range
519 * reg is the offset of the register holding the status bits
520 * enable is the value indicating device is enabled
521 * disable is the value indicating device is disabled
522 * start_bit is the bit number of the first bit in the range
523 * nbits is the number of bits per device status
524 */
525static void __init dscr_parse_devstate_stat_regs(struct device_node *node,
526 void __iomem *base)
527{
528 struct devstate_stat_reg *r;
529 const __be32 *p;
530 int i, j, size;
531
532 p = of_get_property(node, "ti,dscr-devstate-stat-regs", &size);
533 if (p) {
534 /* parse all the ranges we can handle */
535 size /= (sizeof(*p) * 7);
536 if (size > MAX_DEVSTAT_REGS)
537 size = MAX_DEVSTAT_REGS;
538
539 for (i = 0; i < size; i++) {
540 r = &dscr.devstat[i];
541
542 r->start_id = be32_to_cpup(p++);
543 r->num_ids = be32_to_cpup(p++);
544 r->reg = be32_to_cpup(p++);
545 r->enable = be32_to_cpup(p++);
546 r->disable = be32_to_cpup(p++);
547 r->shift = be32_to_cpup(p++);
548 r->nbits = be32_to_cpup(p++);
549
550 for (j = r->start_id;
551 j < (r->start_id + r->num_ids);
552 j++)
553 dscr.devstate_info[j].stat = r;
554 }
555 }
556}
557
558static struct of_device_id dscr_ids[] __initdata = {
559 { .compatible = "ti,c64x+dscr" },
560 {}
561};
562
563/*
564 * Probe for DSCR area.
565 *
566 * This has to be done early on in case timer or interrupt controller
567 * needs something. e.g. On C6455 SoC, timer must be enabled through
568 * DSCR before it is functional.
569 */
570void __init dscr_probe(void)
571{
572 struct device_node *node;
573 void __iomem *base;
574
575 spin_lock_init(&dscr.lock);
576
577 node = of_find_matching_node(NULL, dscr_ids);
578 if (!node)
579 return;
580
581 base = of_iomap(node, 0);
582 if (!base) {
583 of_node_put(node);
584 return;
585 }
586
587 dscr.base = base;
588
589 dscr_parse_devstat(node, base);
590 dscr_parse_silicon_rev(node, base);
591 dscr_parse_mac_fuse(node, base);
592 dscr_parse_rmii_resets(node, base);
593 dscr_parse_locked_regs(node, base);
594 dscr_parse_kick_regs(node, base);
595 dscr_parse_devstate_ctl_regs(node, base);
596 dscr_parse_devstate_stat_regs(node, base);
597 dscr_parse_privperm(node, base);
598}
diff --git a/arch/c6x/platforms/emif.c b/arch/c6x/platforms/emif.c
new file mode 100644
index 000000000000..8b564dec241d
--- /dev/null
+++ b/arch/c6x/platforms/emif.c
@@ -0,0 +1,87 @@
1/*
2 * External Memory Interface
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/of.h>
12#include <linux/of_address.h>
13#include <linux/io.h>
14#include <asm/soc.h>
15#include <asm/dscr.h>
16
17#define NUM_EMIFA_CHIP_ENABLES 4
18
19struct emifa_regs {
20 u32 midr;
21 u32 stat;
22 u32 reserved1[6];
23 u32 bprio;
24 u32 reserved2[23];
25 u32 cecfg[NUM_EMIFA_CHIP_ENABLES];
26 u32 reserved3[4];
27 u32 awcc;
28 u32 reserved4[7];
29 u32 intraw;
30 u32 intmsk;
31 u32 intmskset;
32 u32 intmskclr;
33};
34
35static struct of_device_id emifa_match[] __initdata = {
36 { .compatible = "ti,c64x+emifa" },
37 {}
38};
39
40/*
41 * Parse device tree for existence of an EMIF (External Memory Interface)
42 * and initialize it if found.
43 */
44static int __init c6x_emifa_init(void)
45{
46 struct emifa_regs __iomem *regs;
47 struct device_node *node;
48 const __be32 *p;
49 u32 val;
50 int i, len, err;
51
52 node = of_find_matching_node(NULL, emifa_match);
53 if (!node)
54 return 0;
55
56 regs = of_iomap(node, 0);
57 if (!regs)
58 return 0;
59
60 /* look for a dscr-based enable for emifa pin buffers */
61 err = of_property_read_u32_array(node, "ti,dscr-dev-enable", &val, 1);
62 if (!err)
63 dscr_set_devstate(val, DSCR_DEVSTATE_ENABLED);
64
65 /* set up the chip enables */
66 p = of_get_property(node, "ti,emifa-ce-config", &len);
67 if (p) {
68 len /= sizeof(u32);
69 if (len > NUM_EMIFA_CHIP_ENABLES)
70 len = NUM_EMIFA_CHIP_ENABLES;
71 for (i = 0; i <= len; i++)
72 soc_writel(be32_to_cpup(&p[i]), &regs->cecfg[i]);
73 }
74
75 err = of_property_read_u32_array(node, "ti,emifa-burst-priority", &val, 1);
76 if (!err)
77 soc_writel(val, &regs->bprio);
78
79 err = of_property_read_u32_array(node, "ti,emifa-async-wait-control", &val, 1);
80 if (!err)
81 soc_writel(val, &regs->awcc);
82
83 iounmap(regs);
84 of_node_put(node);
85 return 0;
86}
87pure_initcall(c6x_emifa_init);
diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c
new file mode 100644
index 000000000000..7c37a947fb1c
--- /dev/null
+++ b/arch/c6x/platforms/megamod-pic.c
@@ -0,0 +1,349 @@
1/*
2 * Support for C64x+ Megamodule Interrupt Controller
3 *
4 * Copyright (C) 2010, 2011 Texas Instruments Incorporated
5 * Contributed by: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/module.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/of.h>
15#include <linux/of_irq.h>
16#include <linux/of_address.h>
17#include <linux/slab.h>
18#include <asm/soc.h>
19#include <asm/megamod-pic.h>
20
21#define NR_COMBINERS 4
22#define NR_MUX_OUTPUTS 12
23
24#define IRQ_UNMAPPED 0xffff
25
26/*
27 * Megamodule Interrupt Controller register layout
28 */
29struct megamod_regs {
30 u32 evtflag[8];
31 u32 evtset[8];
32 u32 evtclr[8];
33 u32 reserved0[8];
34 u32 evtmask[8];
35 u32 mevtflag[8];
36 u32 expmask[8];
37 u32 mexpflag[8];
38 u32 intmux_unused;
39 u32 intmux[7];
40 u32 reserved1[8];
41 u32 aegmux[2];
42 u32 reserved2[14];
43 u32 intxstat;
44 u32 intxclr;
45 u32 intdmask;
46 u32 reserved3[13];
47 u32 evtasrt;
48};
49
50struct megamod_pic {
51 struct irq_host *irqhost;
52 struct megamod_regs __iomem *regs;
53 raw_spinlock_t lock;
54
55 /* hw mux mapping */
56 unsigned int output_to_irq[NR_MUX_OUTPUTS];
57};
58
59static struct megamod_pic *mm_pic;
60
61struct megamod_cascade_data {
62 struct megamod_pic *pic;
63 int index;
64};
65
66static struct megamod_cascade_data cascade_data[NR_COMBINERS];
67
68static void mask_megamod(struct irq_data *data)
69{
70 struct megamod_pic *pic = irq_data_get_irq_chip_data(data);
71 irq_hw_number_t src = irqd_to_hwirq(data);
72 u32 __iomem *evtmask = &pic->regs->evtmask[src / 32];
73
74 raw_spin_lock(&pic->lock);
75 soc_writel(soc_readl(evtmask) | (1 << (src & 31)), evtmask);
76 raw_spin_unlock(&pic->lock);
77}
78
79static void unmask_megamod(struct irq_data *data)
80{
81 struct megamod_pic *pic = irq_data_get_irq_chip_data(data);
82 irq_hw_number_t src = irqd_to_hwirq(data);
83 u32 __iomem *evtmask = &pic->regs->evtmask[src / 32];
84
85 raw_spin_lock(&pic->lock);
86 soc_writel(soc_readl(evtmask) & ~(1 << (src & 31)), evtmask);
87 raw_spin_unlock(&pic->lock);
88}
89
90static struct irq_chip megamod_chip = {
91 .name = "megamod",
92 .irq_mask = mask_megamod,
93 .irq_unmask = unmask_megamod,
94};
95
96static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc)
97{
98 struct megamod_cascade_data *cascade;
99 struct megamod_pic *pic;
100 u32 events;
101 int n, idx;
102
103 cascade = irq_desc_get_handler_data(desc);
104
105 pic = cascade->pic;
106 idx = cascade->index;
107
108 while ((events = soc_readl(&pic->regs->mevtflag[idx])) != 0) {
109 n = __ffs(events);
110
111 irq = irq_linear_revmap(pic->irqhost, idx * 32 + n);
112
113 soc_writel(1 << n, &pic->regs->evtclr[idx]);
114
115 generic_handle_irq(irq);
116 }
117}
118
119static int megamod_map(struct irq_host *h, unsigned int virq,
120 irq_hw_number_t hw)
121{
122 struct megamod_pic *pic = h->host_data;
123 int i;
124
125 /* We shouldn't see a hwirq which is muxed to core controller */
126 for (i = 0; i < NR_MUX_OUTPUTS; i++)
127 if (pic->output_to_irq[i] == hw)
128 return -1;
129
130 irq_set_chip_data(virq, pic);
131 irq_set_chip_and_handler(virq, &megamod_chip, handle_level_irq);
132
133 /* Set default irq type */
134 irq_set_irq_type(virq, IRQ_TYPE_NONE);
135
136 return 0;
137}
138
139static int megamod_xlate(struct irq_host *h, struct device_node *ct,
140 const u32 *intspec, unsigned int intsize,
141 irq_hw_number_t *out_hwirq, unsigned int *out_type)
142
143{
144 /* megamod intspecs must have 1 cell */
145 BUG_ON(intsize != 1);
146 *out_hwirq = intspec[0];
147 *out_type = IRQ_TYPE_NONE;
148 return 0;
149}
150
151static struct irq_host_ops megamod_host_ops = {
152 .map = megamod_map,
153 .xlate = megamod_xlate,
154};
155
156static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output)
157{
158 int index, offset;
159 u32 val;
160
161 if (src < 0 || src >= (NR_COMBINERS * 32)) {
162 pic->output_to_irq[output] = IRQ_UNMAPPED;
163 return;
164 }
165
166 /* four mappings per mux register */
167 index = output / 4;
168 offset = (output & 3) * 8;
169
170 val = soc_readl(&pic->regs->intmux[index]);
171 val &= ~(0xff << offset);
172 val |= src << offset;
173 soc_writel(val, &pic->regs->intmux[index]);
174}
175
176/*
177 * Parse the MUX mapping, if one exists.
178 *
179 * The MUX map is an array of up to 12 cells; one for each usable core priority
180 * interrupt. The value of a given cell is the megamodule interrupt source
181 * which is to me MUXed to the output corresponding to the cell position
182 * withing the array. The first cell in the array corresponds to priority
183 * 4 and the last (12th) cell corresponds to priority 15. The allowed
184 * values are 4 - ((NR_COMBINERS * 32) - 1). Note that the combined interrupt
185 * sources (0 - 3) are not allowed to be mapped through this property. They
186 * are handled through the "interrupts" property. This allows us to use a
187 * value of zero as a "do not map" placeholder.
188 */
189static void __init parse_priority_map(struct megamod_pic *pic,
190 int *mapping, int size)
191{
192 struct device_node *np = pic->irqhost->of_node;
193 const __be32 *map;
194 int i, maplen;
195 u32 val;
196
197 map = of_get_property(np, "ti,c64x+megamod-pic-mux", &maplen);
198 if (map) {
199 maplen /= 4;
200 if (maplen > size)
201 maplen = size;
202
203 for (i = 0; i < maplen; i++) {
204 val = be32_to_cpup(map);
205 if (val && val >= 4)
206 mapping[i] = val;
207 ++map;
208 }
209 }
210}
211
212static struct megamod_pic * __init init_megamod_pic(struct device_node *np)
213{
214 struct megamod_pic *pic;
215 int i, irq;
216 int mapping[NR_MUX_OUTPUTS];
217
218 pr_info("Initializing C64x+ Megamodule PIC\n");
219
220 pic = kzalloc(sizeof(struct megamod_pic), GFP_KERNEL);
221 if (!pic) {
222 pr_err("%s: Could not alloc PIC structure.\n", np->full_name);
223 return NULL;
224 }
225
226 pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
227 NR_COMBINERS * 32, &megamod_host_ops,
228 IRQ_UNMAPPED);
229 if (!pic->irqhost) {
230 pr_err("%s: Could not alloc host.\n", np->full_name);
231 goto error_free;
232 }
233
234 pic->irqhost->host_data = pic;
235
236 raw_spin_lock_init(&pic->lock);
237
238 pic->regs = of_iomap(np, 0);
239 if (!pic->regs) {
240 pr_err("%s: Could not map registers.\n", np->full_name);
241 goto error_free;
242 }
243
244 /* Initialize MUX map */
245 for (i = 0; i < ARRAY_SIZE(mapping); i++)
246 mapping[i] = IRQ_UNMAPPED;
247
248 parse_priority_map(pic, mapping, ARRAY_SIZE(mapping));
249
250 /*
251 * We can have up to 12 interrupts cascading to the core controller.
252 * These cascades can be from the combined interrupt sources or for
253 * individual interrupt sources. The "interrupts" property only
254 * deals with the cascaded combined interrupts. The individual
255 * interrupts muxed to the core controller use the core controller
256 * as their interrupt parent.
257 */
258 for (i = 0; i < NR_COMBINERS; i++) {
259
260 irq = irq_of_parse_and_map(np, i);
261 if (irq == NO_IRQ)
262 continue;
263
264 /*
265 * We count on the core priority interrupts (4 - 15) being
266 * direct mapped. Check that device tree provided something
267 * in that range.
268 */
269 if (irq < 4 || irq >= NR_PRIORITY_IRQS) {
270 pr_err("%s: combiner-%d virq %d out of range!\n",
271 np->full_name, i, irq);
272 continue;
273 }
274
275 /* record the mapping */
276 mapping[irq - 4] = i;
277
278 pr_debug("%s: combiner-%d cascading to virq %d\n",
279 np->full_name, i, irq);
280
281 cascade_data[i].pic = pic;
282 cascade_data[i].index = i;
283
284 /* mask and clear all events in combiner */
285 soc_writel(~0, &pic->regs->evtmask[i]);
286 soc_writel(~0, &pic->regs->evtclr[i]);
287
288 irq_set_handler_data(irq, &cascade_data[i]);
289 irq_set_chained_handler(irq, megamod_irq_cascade);
290 }
291
292 /* Finally, set up the MUX registers */
293 for (i = 0; i < NR_MUX_OUTPUTS; i++) {
294 if (mapping[i] != IRQ_UNMAPPED) {
295 pr_debug("%s: setting mux %d to priority %d\n",
296 np->full_name, mapping[i], i + 4);
297 set_megamod_mux(pic, mapping[i], i);
298 }
299 }
300
301 return pic;
302
303error_free:
304 kfree(pic);
305
306 return NULL;
307}
308
309/*
310 * Return next active event after ACK'ing it.
311 * Return -1 if no events active.
312 */
313static int get_exception(void)
314{
315 int i, bit;
316 u32 mask;
317
318 for (i = 0; i < NR_COMBINERS; i++) {
319 mask = soc_readl(&mm_pic->regs->mexpflag[i]);
320 if (mask) {
321 bit = __ffs(mask);
322 soc_writel(1 << bit, &mm_pic->regs->evtclr[i]);
323 return (i * 32) + bit;
324 }
325 }
326 return -1;
327}
328
329static void assert_event(unsigned int val)
330{
331 soc_writel(val, &mm_pic->regs->evtasrt);
332}
333
334void __init megamod_pic_init(void)
335{
336 struct device_node *np;
337
338 np = of_find_compatible_node(NULL, NULL, "ti,c64x+megamod-pic");
339 if (!np)
340 return;
341
342 mm_pic = init_megamod_pic(np);
343 of_node_put(np);
344
345 soc_ops.get_exception = get_exception;
346 soc_ops.assert_event = assert_event;
347
348 return;
349}
diff --git a/arch/c6x/platforms/platform.c b/arch/c6x/platforms/platform.c
new file mode 100644
index 000000000000..26c1a355d600
--- /dev/null
+++ b/arch/c6x/platforms/platform.c
@@ -0,0 +1,17 @@
1/*
2 * Copyright 2011 Texas Instruments Incorporated
3 *
4 * This file is licensed under the terms of the GNU General Public License
5 * version 2. This program is licensed "as is" without any warranty of any
6 * kind, whether express or implied.
7 */
8
9#include <linux/init.h>
10#include <linux/of_platform.h>
11
12static int __init c6x_device_probe(void)
13{
14 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
15 return 0;
16}
17core_initcall(c6x_device_probe);
diff --git a/arch/c6x/platforms/pll.c b/arch/c6x/platforms/pll.c
new file mode 100644
index 000000000000..3aa898f7ce4d
--- /dev/null
+++ b/arch/c6x/platforms/pll.c
@@ -0,0 +1,444 @@
1/*
2 * Clock and PLL control for C64x+ devices
3 *
4 * Copyright (C) 2010, 2011 Texas Instruments.
5 * Contributed by: Mark Salter <msalter@redhat.com>
6 *
7 * Copied heavily from arm/mach-davinci/clock.c, so:
8 *
9 * Copyright (C) 2006-2007 Texas Instruments.
10 * Copyright (C) 2008-2009 Deep Root Systems, LLC
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18#include <linux/module.h>
19#include <linux/clkdev.h>
20#include <linux/clk.h>
21#include <linux/io.h>
22#include <linux/err.h>
23
24#include <asm/clock.h>
25#include <asm/soc.h>
26
27static LIST_HEAD(clocks);
28static DEFINE_MUTEX(clocks_mutex);
29static DEFINE_SPINLOCK(clockfw_lock);
30
31static void __clk_enable(struct clk *clk)
32{
33 if (clk->parent)
34 __clk_enable(clk->parent);
35 clk->usecount++;
36}
37
38static void __clk_disable(struct clk *clk)
39{
40 if (WARN_ON(clk->usecount == 0))
41 return;
42 --clk->usecount;
43
44 if (clk->parent)
45 __clk_disable(clk->parent);
46}
47
48int clk_enable(struct clk *clk)
49{
50 unsigned long flags;
51
52 if (clk == NULL || IS_ERR(clk))
53 return -EINVAL;
54
55 spin_lock_irqsave(&clockfw_lock, flags);
56 __clk_enable(clk);
57 spin_unlock_irqrestore(&clockfw_lock, flags);
58
59 return 0;
60}
61EXPORT_SYMBOL(clk_enable);
62
63void clk_disable(struct clk *clk)
64{
65 unsigned long flags;
66
67 if (clk == NULL || IS_ERR(clk))
68 return;
69
70 spin_lock_irqsave(&clockfw_lock, flags);
71 __clk_disable(clk);
72 spin_unlock_irqrestore(&clockfw_lock, flags);
73}
74EXPORT_SYMBOL(clk_disable);
75
76unsigned long clk_get_rate(struct clk *clk)
77{
78 if (clk == NULL || IS_ERR(clk))
79 return -EINVAL;
80
81 return clk->rate;
82}
83EXPORT_SYMBOL(clk_get_rate);
84
85long clk_round_rate(struct clk *clk, unsigned long rate)
86{
87 if (clk == NULL || IS_ERR(clk))
88 return -EINVAL;
89
90 if (clk->round_rate)
91 return clk->round_rate(clk, rate);
92
93 return clk->rate;
94}
95EXPORT_SYMBOL(clk_round_rate);
96
97/* Propagate rate to children */
98static void propagate_rate(struct clk *root)
99{
100 struct clk *clk;
101
102 list_for_each_entry(clk, &root->children, childnode) {
103 if (clk->recalc)
104 clk->rate = clk->recalc(clk);
105 propagate_rate(clk);
106 }
107}
108
109int clk_set_rate(struct clk *clk, unsigned long rate)
110{
111 unsigned long flags;
112 int ret = -EINVAL;
113
114 if (clk == NULL || IS_ERR(clk))
115 return ret;
116
117 if (clk->set_rate)
118 ret = clk->set_rate(clk, rate);
119
120 spin_lock_irqsave(&clockfw_lock, flags);
121 if (ret == 0) {
122 if (clk->recalc)
123 clk->rate = clk->recalc(clk);
124 propagate_rate(clk);
125 }
126 spin_unlock_irqrestore(&clockfw_lock, flags);
127
128 return ret;
129}
130EXPORT_SYMBOL(clk_set_rate);
131
132int clk_set_parent(struct clk *clk, struct clk *parent)
133{
134 unsigned long flags;
135
136 if (clk == NULL || IS_ERR(clk))
137 return -EINVAL;
138
139 /* Cannot change parent on enabled clock */
140 if (WARN_ON(clk->usecount))
141 return -EINVAL;
142
143 mutex_lock(&clocks_mutex);
144 clk->parent = parent;
145 list_del_init(&clk->childnode);
146 list_add(&clk->childnode, &clk->parent->children);
147 mutex_unlock(&clocks_mutex);
148
149 spin_lock_irqsave(&clockfw_lock, flags);
150 if (clk->recalc)
151 clk->rate = clk->recalc(clk);
152 propagate_rate(clk);
153 spin_unlock_irqrestore(&clockfw_lock, flags);
154
155 return 0;
156}
157EXPORT_SYMBOL(clk_set_parent);
158
159int clk_register(struct clk *clk)
160{
161 if (clk == NULL || IS_ERR(clk))
162 return -EINVAL;
163
164 if (WARN(clk->parent && !clk->parent->rate,
165 "CLK: %s parent %s has no rate!\n",
166 clk->name, clk->parent->name))
167 return -EINVAL;
168
169 mutex_lock(&clocks_mutex);
170 list_add_tail(&clk->node, &clocks);
171 if (clk->parent)
172 list_add_tail(&clk->childnode, &clk->parent->children);
173 mutex_unlock(&clocks_mutex);
174
175 /* If rate is already set, use it */
176 if (clk->rate)
177 return 0;
178
179 /* Else, see if there is a way to calculate it */
180 if (clk->recalc)
181 clk->rate = clk->recalc(clk);
182
183 /* Otherwise, default to parent rate */
184 else if (clk->parent)
185 clk->rate = clk->parent->rate;
186
187 return 0;
188}
189EXPORT_SYMBOL(clk_register);
190
191void clk_unregister(struct clk *clk)
192{
193 if (clk == NULL || IS_ERR(clk))
194 return;
195
196 mutex_lock(&clocks_mutex);
197 list_del(&clk->node);
198 list_del(&clk->childnode);
199 mutex_unlock(&clocks_mutex);
200}
201EXPORT_SYMBOL(clk_unregister);
202
203
204static u32 pll_read(struct pll_data *pll, int reg)
205{
206 return soc_readl(pll->base + reg);
207}
208
209static unsigned long clk_sysclk_recalc(struct clk *clk)
210{
211 u32 v, plldiv = 0;
212 struct pll_data *pll;
213 unsigned long rate = clk->rate;
214
215 if (WARN_ON(!clk->parent))
216 return rate;
217
218 rate = clk->parent->rate;
219
220 /* the parent must be a PLL */
221 if (WARN_ON(!clk->parent->pll_data))
222 return rate;
223
224 pll = clk->parent->pll_data;
225
226 /* If pre-PLL, source clock is before the multiplier and divider(s) */
227 if (clk->flags & PRE_PLL)
228 rate = pll->input_rate;
229
230 if (!clk->div) {
231 pr_debug("%s: (no divider) rate = %lu KHz\n",
232 clk->name, rate / 1000);
233 return rate;
234 }
235
236 if (clk->flags & FIXED_DIV_PLL) {
237 rate /= clk->div;
238 pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n",
239 clk->name, clk->div, rate / 1000);
240 return rate;
241 }
242
243 v = pll_read(pll, clk->div);
244 if (v & PLLDIV_EN)
245 plldiv = (v & PLLDIV_RATIO_MASK) + 1;
246
247 if (plldiv == 0)
248 plldiv = 1;
249
250 rate /= plldiv;
251
252 pr_debug("%s: (divide by %d) rate = %lu KHz\n",
253 clk->name, plldiv, rate / 1000);
254
255 return rate;
256}
257
258static unsigned long clk_leafclk_recalc(struct clk *clk)
259{
260 if (WARN_ON(!clk->parent))
261 return clk->rate;
262
263 pr_debug("%s: (parent %s) rate = %lu KHz\n",
264 clk->name, clk->parent->name, clk->parent->rate / 1000);
265
266 return clk->parent->rate;
267}
268
269static unsigned long clk_pllclk_recalc(struct clk *clk)
270{
271 u32 ctrl, mult = 0, prediv = 0, postdiv = 0;
272 u8 bypass;
273 struct pll_data *pll = clk->pll_data;
274 unsigned long rate = clk->rate;
275
276 if (clk->flags & FIXED_RATE_PLL)
277 return rate;
278
279 ctrl = pll_read(pll, PLLCTL);
280 rate = pll->input_rate = clk->parent->rate;
281
282 if (ctrl & PLLCTL_PLLEN)
283 bypass = 0;
284 else
285 bypass = 1;
286
287 if (pll->flags & PLL_HAS_MUL) {
288 mult = pll_read(pll, PLLM);
289 mult = (mult & PLLM_PLLM_MASK) + 1;
290 }
291 if (pll->flags & PLL_HAS_PRE) {
292 prediv = pll_read(pll, PLLPRE);
293 if (prediv & PLLDIV_EN)
294 prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
295 else
296 prediv = 0;
297 }
298 if (pll->flags & PLL_HAS_POST) {
299 postdiv = pll_read(pll, PLLPOST);
300 if (postdiv & PLLDIV_EN)
301 postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1;
302 else
303 postdiv = 1;
304 }
305
306 if (!bypass) {
307 if (prediv)
308 rate /= prediv;
309 if (mult)
310 rate *= mult;
311 if (postdiv)
312 rate /= postdiv;
313
314 pr_debug("PLL%d: input = %luMHz, pre[%d] mul[%d] post[%d] "
315 "--> %luMHz output.\n",
316 pll->num, clk->parent->rate / 1000000,
317 prediv, mult, postdiv, rate / 1000000);
318 } else
319 pr_debug("PLL%d: input = %luMHz, bypass mode.\n",
320 pll->num, clk->parent->rate / 1000000);
321
322 return rate;
323}
324
325
326static void __init __init_clk(struct clk *clk)
327{
328 INIT_LIST_HEAD(&clk->node);
329 INIT_LIST_HEAD(&clk->children);
330 INIT_LIST_HEAD(&clk->childnode);
331
332 if (!clk->recalc) {
333
334 /* Check if clock is a PLL */
335 if (clk->pll_data)
336 clk->recalc = clk_pllclk_recalc;
337
338 /* Else, if it is a PLL-derived clock */
339 else if (clk->flags & CLK_PLL)
340 clk->recalc = clk_sysclk_recalc;
341
342 /* Otherwise, it is a leaf clock (PSC clock) */
343 else if (clk->parent)
344 clk->recalc = clk_leafclk_recalc;
345 }
346}
347
348void __init c6x_clks_init(struct clk_lookup *clocks)
349{
350 struct clk_lookup *c;
351 struct clk *clk;
352 size_t num_clocks = 0;
353
354 for (c = clocks; c->clk; c++) {
355 clk = c->clk;
356
357 __init_clk(clk);
358 clk_register(clk);
359 num_clocks++;
360
361 /* Turn on clocks that Linux doesn't otherwise manage */
362 if (clk->flags & ALWAYS_ENABLED)
363 clk_enable(clk);
364 }
365
366 clkdev_add_table(clocks, num_clocks);
367}
368
369#ifdef CONFIG_DEBUG_FS
370
371#include <linux/debugfs.h>
372#include <linux/seq_file.h>
373
374#define CLKNAME_MAX 10 /* longest clock name */
375#define NEST_DELTA 2
376#define NEST_MAX 4
377
378static void
379dump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
380{
381 char *state;
382 char buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX];
383 struct clk *clk;
384 unsigned i;
385
386 if (parent->flags & CLK_PLL)
387 state = "pll";
388 else
389 state = "";
390
391 /* <nest spaces> name <pad to end> */
392 memset(buf, ' ', sizeof(buf) - 1);
393 buf[sizeof(buf) - 1] = 0;
394 i = strlen(parent->name);
395 memcpy(buf + nest, parent->name,
396 min(i, (unsigned)(sizeof(buf) - 1 - nest)));
397
398 seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
399 buf, parent->usecount, state, clk_get_rate(parent));
400 /* REVISIT show device associations too */
401
402 /* cost is now small, but not linear... */
403 list_for_each_entry(clk, &parent->children, childnode) {
404 dump_clock(s, nest + NEST_DELTA, clk);
405 }
406}
407
408static int c6x_ck_show(struct seq_file *m, void *v)
409{
410 struct clk *clk;
411
412 /*
413 * Show clock tree; We trust nonzero usecounts equate to PSC enables...
414 */
415 mutex_lock(&clocks_mutex);
416 list_for_each_entry(clk, &clocks, node)
417 if (!clk->parent)
418 dump_clock(m, 0, clk);
419 mutex_unlock(&clocks_mutex);
420
421 return 0;
422}
423
424static int c6x_ck_open(struct inode *inode, struct file *file)
425{
426 return single_open(file, c6x_ck_show, NULL);
427}
428
429static const struct file_operations c6x_ck_operations = {
430 .open = c6x_ck_open,
431 .read = seq_read,
432 .llseek = seq_lseek,
433 .release = single_release,
434};
435
436static int __init c6x_clk_debugfs_init(void)
437{
438 debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL,
439 &c6x_ck_operations);
440
441 return 0;
442}
443device_initcall(c6x_clk_debugfs_init);
444#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/c6x/platforms/plldata.c b/arch/c6x/platforms/plldata.c
new file mode 100644
index 000000000000..2cfd6f42968f
--- /dev/null
+++ b/arch/c6x/platforms/plldata.c
@@ -0,0 +1,404 @@
1/*
2 * Port on Texas Instruments TMS320C6x architecture
3 *
4 * Copyright (C) 2011 Texas Instruments Incorporated
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/kernel.h>
12#include <linux/delay.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/ioport.h>
16#include <linux/clkdev.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19
20#include <asm/clock.h>
21#include <asm/setup.h>
22#include <asm/irq.h>
23
24/*
25 * Common SoC clock support.
26 */
27
28/* Default input for PLL1 */
29struct clk clkin1 = {
30 .name = "clkin1",
31 .node = LIST_HEAD_INIT(clkin1.node),
32 .children = LIST_HEAD_INIT(clkin1.children),
33 .childnode = LIST_HEAD_INIT(clkin1.childnode),
34};
35
36struct pll_data c6x_soc_pll1 = {
37 .num = 1,
38 .sysclks = {
39 {
40 .name = "pll1",
41 .parent = &clkin1,
42 .pll_data = &c6x_soc_pll1,
43 .flags = CLK_PLL,
44 },
45 {
46 .name = "pll1_sysclk1",
47 .parent = &c6x_soc_pll1.sysclks[0],
48 .flags = CLK_PLL,
49 },
50 {
51 .name = "pll1_sysclk2",
52 .parent = &c6x_soc_pll1.sysclks[0],
53 .flags = CLK_PLL,
54 },
55 {
56 .name = "pll1_sysclk3",
57 .parent = &c6x_soc_pll1.sysclks[0],
58 .flags = CLK_PLL,
59 },
60 {
61 .name = "pll1_sysclk4",
62 .parent = &c6x_soc_pll1.sysclks[0],
63 .flags = CLK_PLL,
64 },
65 {
66 .name = "pll1_sysclk5",
67 .parent = &c6x_soc_pll1.sysclks[0],
68 .flags = CLK_PLL,
69 },
70 {
71 .name = "pll1_sysclk6",
72 .parent = &c6x_soc_pll1.sysclks[0],
73 .flags = CLK_PLL,
74 },
75 {
76 .name = "pll1_sysclk7",
77 .parent = &c6x_soc_pll1.sysclks[0],
78 .flags = CLK_PLL,
79 },
80 {
81 .name = "pll1_sysclk8",
82 .parent = &c6x_soc_pll1.sysclks[0],
83 .flags = CLK_PLL,
84 },
85 {
86 .name = "pll1_sysclk9",
87 .parent = &c6x_soc_pll1.sysclks[0],
88 .flags = CLK_PLL,
89 },
90 {
91 .name = "pll1_sysclk10",
92 .parent = &c6x_soc_pll1.sysclks[0],
93 .flags = CLK_PLL,
94 },
95 {
96 .name = "pll1_sysclk11",
97 .parent = &c6x_soc_pll1.sysclks[0],
98 .flags = CLK_PLL,
99 },
100 {
101 .name = "pll1_sysclk12",
102 .parent = &c6x_soc_pll1.sysclks[0],
103 .flags = CLK_PLL,
104 },
105 {
106 .name = "pll1_sysclk13",
107 .parent = &c6x_soc_pll1.sysclks[0],
108 .flags = CLK_PLL,
109 },
110 {
111 .name = "pll1_sysclk14",
112 .parent = &c6x_soc_pll1.sysclks[0],
113 .flags = CLK_PLL,
114 },
115 {
116 .name = "pll1_sysclk15",
117 .parent = &c6x_soc_pll1.sysclks[0],
118 .flags = CLK_PLL,
119 },
120 {
121 .name = "pll1_sysclk16",
122 .parent = &c6x_soc_pll1.sysclks[0],
123 .flags = CLK_PLL,
124 },
125 },
126};
127
128/* CPU core clock */
129struct clk c6x_core_clk = {
130 .name = "core",
131};
132
133/* miscellaneous IO clocks */
134struct clk c6x_i2c_clk = {
135 .name = "i2c",
136};
137
138struct clk c6x_watchdog_clk = {
139 .name = "watchdog",
140};
141
142struct clk c6x_mcbsp1_clk = {
143 .name = "mcbsp1",
144};
145
146struct clk c6x_mcbsp2_clk = {
147 .name = "mcbsp2",
148};
149
150struct clk c6x_mdio_clk = {
151 .name = "mdio",
152};
153
154
155#ifdef CONFIG_SOC_TMS320C6455
156static struct clk_lookup c6455_clks[] = {
157 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
158 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
159 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
160 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
161 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
162 CLK(NULL, "core", &c6x_core_clk),
163 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
164 CLK("watchdog", NULL, &c6x_watchdog_clk),
165 CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
166 CLK("", NULL, NULL)
167};
168
169
170static void __init c6455_setup_clocks(struct device_node *node)
171{
172 struct pll_data *pll = &c6x_soc_pll1;
173 struct clk *sysclks = pll->sysclks;
174
175 pll->flags = PLL_HAS_PRE | PLL_HAS_MUL;
176
177 sysclks[2].flags |= FIXED_DIV_PLL;
178 sysclks[2].div = 3;
179 sysclks[3].flags |= FIXED_DIV_PLL;
180 sysclks[3].div = 6;
181 sysclks[4].div = PLLDIV4;
182 sysclks[5].div = PLLDIV5;
183
184 c6x_core_clk.parent = &sysclks[0];
185 c6x_i2c_clk.parent = &sysclks[3];
186 c6x_watchdog_clk.parent = &sysclks[3];
187 c6x_mdio_clk.parent = &sysclks[3];
188
189 c6x_clks_init(c6455_clks);
190}
191#endif /* CONFIG_SOC_TMS320C6455 */
192
193#ifdef CONFIG_SOC_TMS320C6457
194static struct clk_lookup c6457_clks[] = {
195 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
196 CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]),
197 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
198 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
199 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
200 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
201 CLK(NULL, "core", &c6x_core_clk),
202 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
203 CLK("watchdog", NULL, &c6x_watchdog_clk),
204 CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
205 CLK("", NULL, NULL)
206};
207
208static void __init c6457_setup_clocks(struct device_node *node)
209{
210 struct pll_data *pll = &c6x_soc_pll1;
211 struct clk *sysclks = pll->sysclks;
212
213 pll->flags = PLL_HAS_MUL | PLL_HAS_POST;
214
215 sysclks[1].flags |= FIXED_DIV_PLL;
216 sysclks[1].div = 1;
217 sysclks[2].flags |= FIXED_DIV_PLL;
218 sysclks[2].div = 3;
219 sysclks[3].flags |= FIXED_DIV_PLL;
220 sysclks[3].div = 6;
221 sysclks[4].div = PLLDIV4;
222 sysclks[5].div = PLLDIV5;
223
224 c6x_core_clk.parent = &sysclks[1];
225 c6x_i2c_clk.parent = &sysclks[3];
226 c6x_watchdog_clk.parent = &sysclks[5];
227 c6x_mdio_clk.parent = &sysclks[5];
228
229 c6x_clks_init(c6457_clks);
230}
231#endif /* CONFIG_SOC_TMS320C6455 */
232
233#ifdef CONFIG_SOC_TMS320C6472
234static struct clk_lookup c6472_clks[] = {
235 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
236 CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]),
237 CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]),
238 CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]),
239 CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]),
240 CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]),
241 CLK(NULL, "pll1_sysclk6", &c6x_soc_pll1.sysclks[6]),
242 CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]),
243 CLK(NULL, "pll1_sysclk8", &c6x_soc_pll1.sysclks[8]),
244 CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]),
245 CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]),
246 CLK(NULL, "core", &c6x_core_clk),
247 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
248 CLK("watchdog", NULL, &c6x_watchdog_clk),
249 CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
250 CLK("", NULL, NULL)
251};
252
253/* assumptions used for delay loop calculations */
254#define MIN_CLKIN1_KHz 15625
255#define MAX_CORE_KHz 700000
256#define MIN_PLLOUT_KHz MIN_CLKIN1_KHz
257
258static void __init c6472_setup_clocks(struct device_node *node)
259{
260 struct pll_data *pll = &c6x_soc_pll1;
261 struct clk *sysclks = pll->sysclks;
262 int i;
263
264 pll->flags = PLL_HAS_MUL;
265
266 for (i = 1; i <= 6; i++) {
267 sysclks[i].flags |= FIXED_DIV_PLL;
268 sysclks[i].div = 1;
269 }
270
271 sysclks[7].flags |= FIXED_DIV_PLL;
272 sysclks[7].div = 3;
273 sysclks[8].flags |= FIXED_DIV_PLL;
274 sysclks[8].div = 6;
275 sysclks[9].flags |= FIXED_DIV_PLL;
276 sysclks[9].div = 2;
277 sysclks[10].div = PLLDIV10;
278
279 c6x_core_clk.parent = &sysclks[get_coreid() + 1];
280 c6x_i2c_clk.parent = &sysclks[8];
281 c6x_watchdog_clk.parent = &sysclks[8];
282 c6x_mdio_clk.parent = &sysclks[5];
283
284 c6x_clks_init(c6472_clks);
285}
286#endif /* CONFIG_SOC_TMS320C6472 */
287
288
289#ifdef CONFIG_SOC_TMS320C6474
290static struct clk_lookup c6474_clks[] = {
291 CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]),
292 CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]),
293 CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]),
294 CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]),
295 CLK(NULL, "pll1_sysclk11", &c6x_soc_pll1.sysclks[11]),
296 CLK(NULL, "pll1_sysclk12", &c6x_soc_pll1.sysclks[12]),
297 CLK(NULL, "pll1_sysclk13", &c6x_soc_pll1.sysclks[13]),
298 CLK(NULL, "core", &c6x_core_clk),
299 CLK("i2c_davinci.1", NULL, &c6x_i2c_clk),
300 CLK("mcbsp.1", NULL, &c6x_mcbsp1_clk),
301 CLK("mcbsp.2", NULL, &c6x_mcbsp2_clk),
302 CLK("watchdog", NULL, &c6x_watchdog_clk),
303 CLK("2c81800.mdio", NULL, &c6x_mdio_clk),
304 CLK("", NULL, NULL)
305};
306
307static void __init c6474_setup_clocks(struct device_node *node)
308{
309 struct pll_data *pll = &c6x_soc_pll1;
310 struct clk *sysclks = pll->sysclks;
311
312 pll->flags = PLL_HAS_MUL;
313
314 sysclks[7].flags |= FIXED_DIV_PLL;
315 sysclks[7].div = 1;
316 sysclks[9].flags |= FIXED_DIV_PLL;
317 sysclks[9].div = 3;
318 sysclks[10].flags |= FIXED_DIV_PLL;
319 sysclks[10].div = 6;
320
321 sysclks[11].div = PLLDIV11;
322
323 sysclks[12].flags |= FIXED_DIV_PLL;
324 sysclks[12].div = 2;
325
326 sysclks[13].div = PLLDIV13;
327
328 c6x_core_clk.parent = &sysclks[7];
329 c6x_i2c_clk.parent = &sysclks[10];
330 c6x_watchdog_clk.parent = &sysclks[10];
331 c6x_mcbsp1_clk.parent = &sysclks[10];
332 c6x_mcbsp2_clk.parent = &sysclks[10];
333
334 c6x_clks_init(c6474_clks);
335}
336#endif /* CONFIG_SOC_TMS320C6474 */
337
338static struct of_device_id c6x_clkc_match[] __initdata = {
339#ifdef CONFIG_SOC_TMS320C6455
340 { .compatible = "ti,c6455-pll", .data = c6455_setup_clocks },
341#endif
342#ifdef CONFIG_SOC_TMS320C6457
343 { .compatible = "ti,c6457-pll", .data = c6457_setup_clocks },
344#endif
345#ifdef CONFIG_SOC_TMS320C6472
346 { .compatible = "ti,c6472-pll", .data = c6472_setup_clocks },
347#endif
348#ifdef CONFIG_SOC_TMS320C6474
349 { .compatible = "ti,c6474-pll", .data = c6474_setup_clocks },
350#endif
351 { .compatible = "ti,c64x+pll" },
352 {}
353};
354
355void __init c64x_setup_clocks(void)
356{
357 void (*__setup_clocks)(struct device_node *np);
358 struct pll_data *pll = &c6x_soc_pll1;
359 struct device_node *node;
360 const struct of_device_id *id;
361 int err;
362 u32 val;
363
364 node = of_find_matching_node(NULL, c6x_clkc_match);
365 if (!node)
366 return;
367
368 pll->base = of_iomap(node, 0);
369 if (!pll->base)
370 goto out;
371
372 err = of_property_read_u32(node, "clock-frequency", &val);
373 if (err || val == 0) {
374 pr_err("%s: no clock-frequency found! Using %dMHz\n",
375 node->full_name, (int)val / 1000000);
376 val = 25000000;
377 }
378 clkin1.rate = val;
379
380 err = of_property_read_u32(node, "ti,c64x+pll-bypass-delay", &val);
381 if (err)
382 val = 5000;
383 pll->bypass_delay = val;
384
385 err = of_property_read_u32(node, "ti,c64x+pll-reset-delay", &val);
386 if (err)
387 val = 30000;
388 pll->reset_delay = val;
389
390 err = of_property_read_u32(node, "ti,c64x+pll-lock-delay", &val);
391 if (err)
392 val = 30000;
393 pll->lock_delay = val;
394
395 /* id->data is a pointer to SoC-specific setup */
396 id = of_match_node(c6x_clkc_match, node);
397 if (id && id->data) {
398 __setup_clocks = id->data;
399 __setup_clocks(node);
400 }
401
402out:
403 of_node_put(node);
404}
diff --git a/arch/c6x/platforms/timer64.c b/arch/c6x/platforms/timer64.c
new file mode 100644
index 000000000000..03c03c249191
--- /dev/null
+++ b/arch/c6x/platforms/timer64.c
@@ -0,0 +1,244 @@
1/*
2 * Copyright (C) 2010, 2011 Texas Instruments Incorporated
3 * Contributed by: Mark Salter (msalter@redhat.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/clockchips.h>
11#include <linux/interrupt.h>
12#include <linux/io.h>
13#include <linux/of.h>
14#include <linux/of_irq.h>
15#include <linux/of_address.h>
16#include <asm/soc.h>
17#include <asm/dscr.h>
18#include <asm/timer64.h>
19
20struct timer_regs {
21 u32 reserved0;
22 u32 emumgt;
23 u32 reserved1;
24 u32 reserved2;
25 u32 cntlo;
26 u32 cnthi;
27 u32 prdlo;
28 u32 prdhi;
29 u32 tcr;
30 u32 tgcr;
31 u32 wdtcr;
32};
33
34static struct timer_regs __iomem *timer;
35
36#define TCR_TSTATLO 0x001
37#define TCR_INVOUTPLO 0x002
38#define TCR_INVINPLO 0x004
39#define TCR_CPLO 0x008
40#define TCR_ENAMODELO_ONCE 0x040
41#define TCR_ENAMODELO_CONT 0x080
42#define TCR_ENAMODELO_MASK 0x0c0
43#define TCR_PWIDLO_MASK 0x030
44#define TCR_CLKSRCLO 0x100
45#define TCR_TIENLO 0x200
46#define TCR_TSTATHI (0x001 << 16)
47#define TCR_INVOUTPHI (0x002 << 16)
48#define TCR_CPHI (0x008 << 16)
49#define TCR_PWIDHI_MASK (0x030 << 16)
50#define TCR_ENAMODEHI_ONCE (0x040 << 16)
51#define TCR_ENAMODEHI_CONT (0x080 << 16)
52#define TCR_ENAMODEHI_MASK (0x0c0 << 16)
53
54#define TGCR_TIMLORS 0x001
55#define TGCR_TIMHIRS 0x002
56#define TGCR_TIMMODE_UD32 0x004
57#define TGCR_TIMMODE_WDT64 0x008
58#define TGCR_TIMMODE_CD32 0x00c
59#define TGCR_TIMMODE_MASK 0x00c
60#define TGCR_PSCHI_MASK (0x00f << 8)
61#define TGCR_TDDRHI_MASK (0x00f << 12)
62
63/*
64 * Timer clocks are divided down from the CPU clock
65 * The divisor is in the EMUMGTCLKSPD register
66 */
67#define TIMER_DIVISOR \
68 ((soc_readl(&timer->emumgt) & (0xf << 16)) >> 16)
69
70#define TIMER64_RATE (c6x_core_freq / TIMER_DIVISOR)
71
72#define TIMER64_MODE_DISABLED 0
73#define TIMER64_MODE_ONE_SHOT TCR_ENAMODELO_ONCE
74#define TIMER64_MODE_PERIODIC TCR_ENAMODELO_CONT
75
76static int timer64_mode;
77static int timer64_devstate_id = -1;
78
79static void timer64_config(unsigned long period)
80{
81 u32 tcr = soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK;
82
83 soc_writel(tcr, &timer->tcr);
84 soc_writel(period - 1, &timer->prdlo);
85 soc_writel(0, &timer->cntlo);
86 tcr |= timer64_mode;
87 soc_writel(tcr, &timer->tcr);
88}
89
90static void timer64_enable(void)
91{
92 u32 val;
93
94 if (timer64_devstate_id >= 0)
95 dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED);
96
97 /* disable timer, reset count */
98 soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
99 soc_writel(0, &timer->prdlo);
100
101 /* use internal clock and 1 cycle pulse width */
102 val = soc_readl(&timer->tcr);
103 soc_writel(val & ~(TCR_CLKSRCLO | TCR_PWIDLO_MASK), &timer->tcr);
104
105 /* dual 32-bit unchained mode */
106 val = soc_readl(&timer->tgcr) & ~TGCR_TIMMODE_MASK;
107 soc_writel(val, &timer->tgcr);
108 soc_writel(val | (TGCR_TIMLORS | TGCR_TIMMODE_UD32), &timer->tgcr);
109}
110
111static void timer64_disable(void)
112{
113 /* disable timer, reset count */
114 soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr);
115 soc_writel(0, &timer->prdlo);
116
117 if (timer64_devstate_id >= 0)
118 dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_DISABLED);
119}
120
121static int next_event(unsigned long delta,
122 struct clock_event_device *evt)
123{
124 timer64_config(delta);
125 return 0;
126}
127
128static void set_clock_mode(enum clock_event_mode mode,
129 struct clock_event_device *evt)
130{
131 switch (mode) {
132 case CLOCK_EVT_MODE_PERIODIC:
133 timer64_enable();
134 timer64_mode = TIMER64_MODE_PERIODIC;
135 timer64_config(TIMER64_RATE / HZ);
136 break;
137 case CLOCK_EVT_MODE_ONESHOT:
138 timer64_enable();
139 timer64_mode = TIMER64_MODE_ONE_SHOT;
140 break;
141 case CLOCK_EVT_MODE_UNUSED:
142 case CLOCK_EVT_MODE_SHUTDOWN:
143 timer64_mode = TIMER64_MODE_DISABLED;
144 timer64_disable();
145 break;
146 case CLOCK_EVT_MODE_RESUME:
147 break;
148 }
149}
150
151static struct clock_event_device t64_clockevent_device = {
152 .name = "TIMER64_EVT32_TIMER",
153 .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
154 .rating = 200,
155 .set_mode = set_clock_mode,
156 .set_next_event = next_event,
157};
158
159static irqreturn_t timer_interrupt(int irq, void *dev_id)
160{
161 struct clock_event_device *cd = &t64_clockevent_device;
162
163 cd->event_handler(cd);
164
165 return IRQ_HANDLED;
166}
167
168static struct irqaction timer_iact = {
169 .name = "timer",
170 .flags = IRQF_TIMER,
171 .handler = timer_interrupt,
172 .dev_id = &t64_clockevent_device,
173};
174
175void __init timer64_init(void)
176{
177 struct clock_event_device *cd = &t64_clockevent_device;
178 struct device_node *np, *first = NULL;
179 u32 val;
180 int err, found = 0;
181
182 for_each_compatible_node(np, NULL, "ti,c64x+timer64") {
183 err = of_property_read_u32(np, "ti,core-mask", &val);
184 if (!err) {
185 if (val & (1 << get_coreid())) {
186 found = 1;
187 break;
188 }
189 } else if (!first)
190 first = np;
191 }
192 if (!found) {
193 /* try first one with no core-mask */
194 if (first)
195 np = of_node_get(first);
196 else {
197 pr_debug("Cannot find ti,c64x+timer64 timer.\n");
198 return;
199 }
200 }
201
202 timer = of_iomap(np, 0);
203 if (!timer) {
204 pr_debug("%s: Cannot map timer registers.\n", np->full_name);
205 goto out;
206 }
207 pr_debug("%s: Timer registers=%p.\n", np->full_name, timer);
208
209 cd->irq = irq_of_parse_and_map(np, 0);
210 if (cd->irq == NO_IRQ) {
211 pr_debug("%s: Cannot find interrupt.\n", np->full_name);
212 iounmap(timer);
213 goto out;
214 }
215
216 /* If there is a device state control, save the ID. */
217 err = of_property_read_u32(np, "ti,dscr-dev-enable", &val);
218 if (!err) {
219 timer64_devstate_id = val;
220
221 /*
222 * It is necessary to enable the timer block here because
223 * the TIMER_DIVISOR macro needs to read a timer register
224 * to get the divisor.
225 */
226 dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED);
227 }
228
229 pr_debug("%s: Timer irq=%d.\n", np->full_name, cd->irq);
230
231 clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5);
232
233 cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
234 cd->min_delta_ns = clockevent_delta2ns(250, cd);
235
236 cd->cpumask = cpumask_of(smp_processor_id());
237
238 clockevents_register_device(cd);
239 setup_irq(cd->irq, &timer_iact);
240
241out:
242 of_node_put(np);
243 return;
244}
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index 912088773a69..c2cf2eda0626 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -327,7 +327,7 @@ static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
327#define ioremap_wc ioremap_nocache 327#define ioremap_wc ioremap_nocache
328#endif 328#endif
329 329
330static inline void iounmap(void *addr) 330static inline void iounmap(void __iomem *addr)
331{ 331{
332} 332}
333#endif /* CONFIG_MMU */ 333#endif /* CONFIG_MMU */
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
index 351889d1de19..37d1fe28960a 100644
--- a/include/asm-generic/page.h
+++ b/include/asm-generic/page.h
@@ -71,10 +71,14 @@ extern unsigned long memory_end;
71#define PAGE_OFFSET (0) 71#define PAGE_OFFSET (0)
72#endif 72#endif
73 73
74#ifndef ARCH_PFN_OFFSET
75#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT)
76#endif
77
74#ifndef __ASSEMBLY__ 78#ifndef __ASSEMBLY__
75 79
76#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET)) 80#define __va(x) ((void *)((unsigned long) (x)))
77#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET) 81#define __pa(x) ((unsigned long) (x))
78 82
79#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) 83#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
80#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) 84#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
@@ -86,7 +90,7 @@ extern unsigned long memory_end;
86#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) 90#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
87#endif 91#endif
88 92
89#define pfn_valid(pfn) ((pfn) < max_mapnr) 93#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
90 94
91#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ 95#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
92 ((void *)(kaddr) < (void *)memory_end)) 96 ((void *)(kaddr) < (void *)memory_end))
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index ac68c999b6c2..9788568f7978 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -289,9 +289,14 @@ strncpy_from_user(char *dst, const char __user *src, long count)
289 * Return 0 on exception, a value greater than N if too long 289 * Return 0 on exception, a value greater than N if too long
290 */ 290 */
291#ifndef __strnlen_user 291#ifndef __strnlen_user
292#define __strnlen_user strnlen 292#define __strnlen_user(s, n) (strnlen((s), (n)) + 1)
293#endif 293#endif
294 294
295/*
296 * Unlike strnlen, strnlen_user includes the nul terminator in
297 * its returned count. Callers should check for a returned value
298 * greater than N as an indication the string is too long.
299 */
295static inline long strnlen_user(const char __user *src, long n) 300static inline long strnlen_user(const char __user *src, long n)
296{ 301{
297 if (!access_ok(VERIFY_READ, src, 1)) 302 if (!access_ok(VERIFY_READ, src, 1))
diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
index 18bea78fe47b..8e2b7bac4378 100644
--- a/include/linux/elf-em.h
+++ b/include/linux/elf-em.h
@@ -33,6 +33,7 @@
33#define EM_H8_300 46 /* Renesas H8/300,300H,H8S */ 33#define EM_H8_300 46 /* Renesas H8/300,300H,H8S */
34#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */ 34#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */
35#define EM_BLACKFIN 106 /* ADI Blackfin Processor */ 35#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
36#define EM_TI_C6000 140 /* TI C6X DSPs */
36#define EM_FRV 0x5441 /* Fujitsu FR-V */ 37#define EM_FRV 0x5441 /* Fujitsu FR-V */
37#define EM_AVR32 0x18ad /* Atmel AVR32 */ 38#define EM_AVR32 0x18ad /* Atmel AVR32 */
38 39