The following changes since commit 3ee72ca992

are available in the git repository:
 
     git://linux-c6x.org/git/projects/linux-c6x-upstreaming.git for-linux-next
 
  Documentation/devicetree/bindings/c6x/clocks.txt   |   40 +
  Documentation/devicetree/bindings/c6x/dscr.txt     |  127 +++
  Documentation/devicetree/bindings/c6x/emifa.txt    |   62 ++
  .../devicetree/bindings/c6x/interrupt.txt          |  104 +++
  Documentation/devicetree/bindings/c6x/soc.txt      |   28 +
  Documentation/devicetree/bindings/c6x/timer64.txt  |   26 +
  MAINTAINERS                                        |    8 +
  arch/c6x/Kconfig                                   |  174 +++++
  arch/c6x/Makefile                                  |   60 ++
  arch/c6x/boot/Makefile                             |   30 +
  arch/c6x/boot/dts/dsk6455.dts                      |   62 ++
  arch/c6x/boot/dts/evmc6457.dts                     |   48 ++
  arch/c6x/boot/dts/evmc6472.dts                     |   73 ++
  arch/c6x/boot/dts/evmc6474.dts                     |   58 ++
  arch/c6x/boot/dts/tms320c6455.dtsi                 |   96 +++
  arch/c6x/boot/dts/tms320c6457.dtsi                 |   68 ++
  arch/c6x/boot/dts/tms320c6472.dtsi                 |  134 ++++
  arch/c6x/boot/dts/tms320c6474.dtsi                 |   89 +++
  arch/c6x/boot/linked_dtb.S                         |    2 +
  arch/c6x/configs/dsk6455_defconfig                 |   44 ++
  arch/c6x/configs/evmc6457_defconfig                |   41 +
  arch/c6x/configs/evmc6472_defconfig                |   42 +
  arch/c6x/configs/evmc6474_defconfig                |   42 +
  arch/c6x/include/asm/Kbuild                        |   54 ++
  arch/c6x/include/asm/asm-offsets.h                 |    1 +
  arch/c6x/include/asm/bitops.h                      |  105 +++
  arch/c6x/include/asm/byteorder.h                   |   12 +
  arch/c6x/include/asm/cache.h                       |   90 +++
  arch/c6x/include/asm/cacheflush.h                  |   65 ++
  arch/c6x/include/asm/checksum.h                    |   34 +
  arch/c6x/include/asm/clkdev.h                      |   22 +
  arch/c6x/include/asm/clock.h                       |  148 ++++
  arch/c6x/include/asm/delay.h                       |   67 ++
  arch/c6x/include/asm/dma-mapping.h                 |   91 +++
  arch/c6x/include/asm/dscr.h                        |   34 +
  arch/c6x/include/asm/elf.h                         |  113 +++
  arch/c6x/include/asm/ftrace.h                      |    6 +
  arch/c6x/include/asm/hardirq.h                     |   20 +
  arch/c6x/include/asm/irq.h                         |  302 ++++++++
  arch/c6x/include/asm/irqflags.h                    |   72 ++
  arch/c6x/include/asm/linkage.h                     |   30 +
  arch/c6x/include/asm/megamod-pic.h                 |    9 +
  arch/c6x/include/asm/mmu.h                         |   18 +
  arch/c6x/include/asm/module.h                      |   33 +
  arch/c6x/include/asm/mutex.h                       |    6 +
  arch/c6x/include/asm/page.h                        |   11 +
  arch/c6x/include/asm/pgtable.h                     |   81 ++
  arch/c6x/include/asm/processor.h                   |  132 ++++
  arch/c6x/include/asm/procinfo.h                    |   28 +
  arch/c6x/include/asm/prom.h                        |    1 +
  arch/c6x/include/asm/ptrace.h                      |  174 +++++
  arch/c6x/include/asm/sections.h                    |   12 +
  arch/c6x/include/asm/setup.h                       |   32 +
  arch/c6x/include/asm/sigcontext.h                  |   80 ++
  arch/c6x/include/asm/signal.h                      |   17 +
  arch/c6x/include/asm/soc.h                         |   35 +
  arch/c6x/include/asm/string.h                      |   21 +
  arch/c6x/include/asm/swab.h                        |   54 ++
  arch/c6x/include/asm/syscall.h                     |  123 +++
  arch/c6x/include/asm/syscalls.h                    |   55 ++
  arch/c6x/include/asm/system.h                      |  168 ++++
  arch/c6x/include/asm/thread_info.h                 |  121 +++
  arch/c6x/include/asm/timer64.h                     |    6 +
  arch/c6x/include/asm/timex.h                       |   33 +
  arch/c6x/include/asm/tlb.h                         |    8 +
  arch/c6x/include/asm/traps.h                       |   36 +
  arch/c6x/include/asm/uaccess.h                     |  107 +++
  arch/c6x/include/asm/unaligned.h                   |  170 +++++
  arch/c6x/include/asm/unistd.h                      |   26 +
  arch/c6x/kernel/Makefile                           |   12 +
  arch/c6x/kernel/asm-offsets.c                      |  123 +++
  arch/c6x/kernel/c6x_ksyms.c                        |   66 ++
  arch/c6x/kernel/devicetree.c                       |   53 ++
  arch/c6x/kernel/dma.c                              |  153 ++++
  arch/c6x/kernel/entry.S                            |  803 ++++++++++++++++++++
  arch/c6x/kernel/head.S                             |   84 ++
  arch/c6x/kernel/irq.c                              |  728 ++++++++++++++++++
  arch/c6x/kernel/module.c                           |  123 +++
  arch/c6x/kernel/process.c                          |  265 +++++++
  arch/c6x/kernel/ptrace.c                           |  187 +++++
  arch/c6x/kernel/setup.c                            |  510 +++++++++++++
  arch/c6x/kernel/signal.c                           |  377 +++++++++
  arch/c6x/kernel/soc.c                              |   91 +++
  arch/c6x/kernel/switch_to.S                        |   74 ++
  arch/c6x/kernel/sys_c6x.c                          |   74 ++
  arch/c6x/kernel/time.c                             |   65 ++
  arch/c6x/kernel/traps.c                            |  423 ++++++++++
  arch/c6x/kernel/vectors.S                          |   81 ++
  arch/c6x/kernel/vmlinux.lds.S                      |  162 ++++
  arch/c6x/lib/Makefile                              |    7 +
  arch/c6x/lib/checksum.c                            |   36 +
  arch/c6x/lib/csum_64plus.S                         |  419 ++++++++++
  arch/c6x/lib/divi.S                                |   53 ++
  arch/c6x/lib/divremi.S                             |   46 ++
  arch/c6x/lib/divremu.S                             |   87 +++
  arch/c6x/lib/divu.S                                |   98 +++
  arch/c6x/lib/llshl.S                               |   37 +
  arch/c6x/lib/llshr.S                               |   38 +
  arch/c6x/lib/llshru.S                              |   38 +
  arch/c6x/lib/memcpy_64plus.S                       |   46 ++
  arch/c6x/lib/mpyll.S                               |   49 ++
  arch/c6x/lib/negll.S                               |   31 +
  arch/c6x/lib/pop_rts.S                             |   32 +
  arch/c6x/lib/push_rts.S                            |   31 +
  arch/c6x/lib/remi.S                                |   64 ++
  arch/c6x/lib/remu.S                                |   82 ++
  arch/c6x/lib/strasgi.S                             |   89 +++
  arch/c6x/lib/strasgi_64plus.S                      |   39 +
  arch/c6x/mm/Makefile                               |    5 +
  arch/c6x/mm/dma-coherent.c                         |  143 ++++
  arch/c6x/mm/init.c                                 |  113 +++
  arch/c6x/platforms/Kconfig                         |   16 +
  arch/c6x/platforms/Makefile                        |   12 +
  arch/c6x/platforms/cache.c                         |  445 +++++++++++
  arch/c6x/platforms/dscr.c                          |  598 +++++++++++++++
  arch/c6x/platforms/emif.c                          |   87 +++
  arch/c6x/platforms/megamod-pic.c                   |  349 +++++++++
  arch/c6x/platforms/platform.c                      |   17 +
  arch/c6x/platforms/pll.c                           |  444 +++++++++++
  arch/c6x/platforms/plldata.c                       |  404 ++++++++++
  arch/c6x/platforms/timer64.c                       |  244 ++++++
  include/asm-generic/io.h                           |    2 +-
  include/asm-generic/page.h                         |   10 +-
  include/asm-generic/uaccess.h                      |    7 +-
  include/linux/elf-em.h                             |    1 +
  125 files changed, 12989 insertions(+), 5 deletions(-)
  create mode 100644 Documentation/devicetree/bindings/c6x/clocks.txt
  create mode 100644 Documentation/devicetree/bindings/c6x/dscr.txt
  create mode 100644 Documentation/devicetree/bindings/c6x/emifa.txt
  create mode 100644 Documentation/devicetree/bindings/c6x/interrupt.txt
  create mode 100644 Documentation/devicetree/bindings/c6x/soc.txt
  create mode 100644 Documentation/devicetree/bindings/c6x/timer64.txt
  create mode 100644 arch/c6x/Kconfig
  create mode 100644 arch/c6x/Makefile
  create mode 100644 arch/c6x/boot/Makefile
  create mode 100644 arch/c6x/boot/dts/dsk6455.dts
  create mode 100644 arch/c6x/boot/dts/evmc6457.dts
  create mode 100644 arch/c6x/boot/dts/evmc6472.dts
  create mode 100644 arch/c6x/boot/dts/evmc6474.dts
  create mode 100644 arch/c6x/boot/dts/tms320c6455.dtsi
  create mode 100644 arch/c6x/boot/dts/tms320c6457.dtsi
  create mode 100644 arch/c6x/boot/dts/tms320c6472.dtsi
  create mode 100644 arch/c6x/boot/dts/tms320c6474.dtsi
  create mode 100644 arch/c6x/boot/linked_dtb.S
  create mode 100644 arch/c6x/configs/dsk6455_defconfig
  create mode 100644 arch/c6x/configs/evmc6457_defconfig
  create mode 100644 arch/c6x/configs/evmc6472_defconfig
  create mode 100644 arch/c6x/configs/evmc6474_defconfig
  create mode 100644 arch/c6x/include/asm/Kbuild
  create mode 100644 arch/c6x/include/asm/asm-offsets.h
  create mode 100644 arch/c6x/include/asm/bitops.h
  create mode 100644 arch/c6x/include/asm/byteorder.h
  create mode 100644 arch/c6x/include/asm/cache.h
  create mode 100644 arch/c6x/include/asm/cacheflush.h
  create mode 100644 arch/c6x/include/asm/checksum.h
  create mode 100644 arch/c6x/include/asm/clkdev.h
  create mode 100644 arch/c6x/include/asm/clock.h
  create mode 100644 arch/c6x/include/asm/delay.h
  create mode 100644 arch/c6x/include/asm/dma-mapping.h
  create mode 100644 arch/c6x/include/asm/dscr.h
  create mode 100644 arch/c6x/include/asm/elf.h
  create mode 100644 arch/c6x/include/asm/ftrace.h
  create mode 100644 arch/c6x/include/asm/hardirq.h
  create mode 100644 arch/c6x/include/asm/irq.h
  create mode 100644 arch/c6x/include/asm/irqflags.h
  create mode 100644 arch/c6x/include/asm/linkage.h
  create mode 100644 arch/c6x/include/asm/megamod-pic.h
  create mode 100644 arch/c6x/include/asm/mmu.h
  create mode 100644 arch/c6x/include/asm/module.h
  create mode 100644 arch/c6x/include/asm/mutex.h
  create mode 100644 arch/c6x/include/asm/page.h
  create mode 100644 arch/c6x/include/asm/pgtable.h
  create mode 100644 arch/c6x/include/asm/processor.h
  create mode 100644 arch/c6x/include/asm/procinfo.h
  create mode 100644 arch/c6x/include/asm/prom.h
  create mode 100644 arch/c6x/include/asm/ptrace.h
  create mode 100644 arch/c6x/include/asm/sections.h
  create mode 100644 arch/c6x/include/asm/setup.h
  create mode 100644 arch/c6x/include/asm/sigcontext.h
  create mode 100644 arch/c6x/include/asm/signal.h
  create mode 100644 arch/c6x/include/asm/soc.h
  create mode 100644 arch/c6x/include/asm/string.h
  create mode 100644 arch/c6x/include/asm/swab.h
  create mode 100644 arch/c6x/include/asm/syscall.h
  create mode 100644 arch/c6x/include/asm/syscalls.h
  create mode 100644 arch/c6x/include/asm/system.h
  create mode 100644 arch/c6x/include/asm/thread_info.h
  create mode 100644 arch/c6x/include/asm/timer64.h
  create mode 100644 arch/c6x/include/asm/timex.h
  create mode 100644 arch/c6x/include/asm/tlb.h
  create mode 100644 arch/c6x/include/asm/traps.h
  create mode 100644 arch/c6x/include/asm/uaccess.h
  create mode 100644 arch/c6x/include/asm/unaligned.h
  create mode 100644 arch/c6x/include/asm/unistd.h
  create mode 100644 arch/c6x/kernel/Makefile
  create mode 100644 arch/c6x/kernel/asm-offsets.c
  create mode 100644 arch/c6x/kernel/c6x_ksyms.c
  create mode 100644 arch/c6x/kernel/devicetree.c
  create mode 100644 arch/c6x/kernel/dma.c
  create mode 100644 arch/c6x/kernel/entry.S
  create mode 100644 arch/c6x/kernel/head.S
  create mode 100644 arch/c6x/kernel/irq.c
  create mode 100644 arch/c6x/kernel/module.c
  create mode 100644 arch/c6x/kernel/process.c
  create mode 100644 arch/c6x/kernel/ptrace.c
  create mode 100644 arch/c6x/kernel/setup.c
  create mode 100644 arch/c6x/kernel/signal.c
  create mode 100644 arch/c6x/kernel/soc.c
  create mode 100644 arch/c6x/kernel/switch_to.S
  create mode 100644 arch/c6x/kernel/sys_c6x.c
  create mode 100644 arch/c6x/kernel/time.c
  create mode 100644 arch/c6x/kernel/traps.c
  create mode 100644 arch/c6x/kernel/vectors.S
  create mode 100644 arch/c6x/kernel/vmlinux.lds.S
  create mode 100644 arch/c6x/lib/Makefile
  create mode 100644 arch/c6x/lib/checksum.c
  create mode 100644 arch/c6x/lib/csum_64plus.S
  create mode 100644 arch/c6x/lib/divi.S
  create mode 100644 arch/c6x/lib/divremi.S
  create mode 100644 arch/c6x/lib/divremu.S
  create mode 100644 arch/c6x/lib/divu.S
  create mode 100644 arch/c6x/lib/llshl.S
  create mode 100644 arch/c6x/lib/llshr.S
  create mode 100644 arch/c6x/lib/llshru.S
  create mode 100644 arch/c6x/lib/memcpy_64plus.S
  create mode 100644 arch/c6x/lib/mpyll.S
  create mode 100644 arch/c6x/lib/negll.S
  create mode 100644 arch/c6x/lib/pop_rts.S
  create mode 100644 arch/c6x/lib/push_rts.S
  create mode 100644 arch/c6x/lib/remi.S
  create mode 100644 arch/c6x/lib/remu.S
  create mode 100644 arch/c6x/lib/strasgi.S
  create mode 100644 arch/c6x/lib/strasgi_64plus.S
  create mode 100644 arch/c6x/mm/Makefile
  create mode 100644 arch/c6x/mm/dma-coherent.c
  create mode 100644 arch/c6x/mm/init.c
  create mode 100644 arch/c6x/platforms/Kconfig
  create mode 100644 arch/c6x/platforms/Makefile
  create mode 100644 arch/c6x/platforms/cache.c
  create mode 100644 arch/c6x/platforms/dscr.c
  create mode 100644 arch/c6x/platforms/emif.c
  create mode 100644 arch/c6x/platforms/megamod-pic.c
  create mode 100644 arch/c6x/platforms/platform.c
  create mode 100644 arch/c6x/platforms/pll.c
  create mode 100644 arch/c6x/platforms/plldata.c
  create mode 100644 arch/c6x/platforms/timer64.c
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJPCgLhAAoJEOiN4VijXeFPGmIQAIom6TQ6IdjmSZwOdTgLlxvv
 D9eDC0MrDY6AUMwEwjSPaRjKnRFMicdQQTIEYPGTHCSV0sfMsGUgfEaY7uR9rbQR
 +rkk5uUekvJY8ONITL0otmP2WKC3TIZmH6kRyPezdYzfzV7mgY+8ssyPOnKiXapP
 PXTlugQMqcCpehtVPWTPJdL2nKWbtk40MkhP1V3B+YtPqf6sxGWl85p8S4NCkZ9p
 zyRTQnmYmRxbnwivxfvA5B6IfXmMXvs5GdTrjXW5FB/LFKdUTvEhY9KU+0dNikB5
 GWZNsuxTioWu0PgM4alrU25GRwakg3IJ7V4NbFZQ7WfJGHjF0dmzSNsSFIS2Lnpc
 p5bFLrIr7Uh7G8nA+8KBRlC2KM54PFN/reWvG69khhda1ZuGVFGx8DgzgF9YQt1E
 Gitok/1DgSohKLG00KSMv/B6mntNOqVZfjmo/mk2z/6NAdOUvbpLAiqBp3mHrUdA
 NyaUn2uWMud3SVk/6HCJOTfCkVwAzwacPHVvgjuMlR7DN2RtopJ9qnDAOU1oyWpm
 ZBJ2NC1ehRsNWl3O74pPf38Rd0kREmcZ08giO69qpqrdgL8vwsJaCTwyUqa4sDWL
 ot6U8FIL+Db9XqZnXjJIswgX9VXrQL8rrTfQ3Ofry8BiIclFynW0eLIXSerGZxtb
 5ayjDMyg5ZW3xRLvNSPG
 =/OBA
 -----END PGP SIGNATURE-----

Merge tag 'for-linux-3.3-merge-window' of git://linux-c6x.org/git/projects/linux-c6x-upstreaming

* tag 'for-linux-3.3-merge-window' of git://linux-c6x.org/git/projects/linux-c6x-upstreaming: (29 commits)
  C6X: replace tick_nohz_stop/restart_sched_tick calls
  C6X: add register_cpu call
  C6X: deal with memblock API changes
  C6X: fix timer64 initialization
  C6X: fix layout of EMIFA registers
  C6X: MAINTAINERS
  C6X: DSCR - Device State Configuration Registers
  C6X: EMIF - External Memory Interface
  C6X: general SoC support
  C6X: library code
  C6X: headers
  C6X: ptrace support
  C6X: loadable module support
  C6X: cache control
  C6X: clocks
  C6X: build infrastructure
  C6X: syscalls
  C6X: interrupt handling
  C6X: time management
  C6X: signal management
  ...
This commit is contained in:
Linus Torvalds 2012-01-10 17:39:40 -08:00
commit 06792c4dde
125 changed files with 12989 additions and 5 deletions

View File

@ -0,0 +1,40 @@
C6X PLL Clock Controllers
-------------------------
This is a first-cut support for the SoC clock controllers. This is still
under development and will probably change as the common device tree
clock support is added to the kernel.
Required properties:
- compatible: "ti,c64x+pll"
May also have SoC-specific value to support SoC-specific initialization
in the driver. One of:
"ti,c6455-pll"
"ti,c6457-pll"
"ti,c6472-pll"
"ti,c6474-pll"
- reg: base address and size of register area
- clock-frequency: input clock frequency in hz
Optional properties:
- ti,c64x+pll-bypass-delay: CPU cycles to delay when entering bypass mode
- ti,c64x+pll-reset-delay: CPU cycles to delay after PLL reset
- ti,c64x+pll-lock-delay: CPU cycles to delay after PLL frequency change
Example:
clock-controller@29a0000 {
compatible = "ti,c6472-pll", "ti,c64x+pll";
reg = <0x029a0000 0x200>;
clock-frequency = <25000000>;
ti,c64x+pll-bypass-delay = <200>;
ti,c64x+pll-reset-delay = <12000>;
ti,c64x+pll-lock-delay = <80000>;
};

View File

@ -0,0 +1,127 @@
Device State Configuration Registers
------------------------------------
TI C6X SoCs contain a region of miscellaneous registers which provide various
function for SoC control or status. Details vary considerably among from SoC
to SoC with no two being alike.
In general, the Device State Configuraion Registers (DSCR) will provide one or
more configuration registers often protected by a lock register where one or
more key values must be written to a lock register in order to unlock the
configuration register for writes. These configuration register may be used to
enable (and disable in some cases) SoC pin drivers, select peripheral clock
sources (internal or pin), etc. In some cases, a configuration register is
write once or the individual bits are write once. In addition to device config,
the DSCR block may provide registers which which are used to reset peripherals,
provide device ID information, provide ethernet MAC addresses, as well as other
miscellaneous functions.
For device state control (enable/disable), each device control is assigned an
id which is used by individual device drivers to control the state as needed.
Required properties:
- compatible: must be "ti,c64x+dscr"
- reg: register area base and size
Optional properties:
NOTE: These are optional in that not all SoCs will have all properties. For
SoCs which do support a given property, leaving the property out of the
device tree will result in reduced functionality or possibly driver
failure.
- ti,dscr-devstat
offset of the devstat register
- ti,dscr-silicon-rev
offset, start bit, and bitsize of silicon revision field
- ti,dscr-rmii-resets
offset and bitmask of RMII reset field. May have multiple tuples if more
than one ethernet port is available.
- ti,dscr-locked-regs
possibly multiple tuples describing registers which are write protected by
a lock register. Each tuple consists of the register offset, lock register
offsset, and the key value used to unlock the register.
- ti,dscr-kick-regs
offset and key values of two "kick" registers used to write protect other
registers in DSCR. On SoCs using kick registers, the first key must be
written to the first kick register and the second key must be written to
the second register before other registers in the area are write-enabled.
- ti,dscr-mac-fuse-regs
MAC addresses are contained in two registers. Each element of a MAC address
is contained in a single byte. This property has two tuples. Each tuple has
a register offset and four cells representing bytes in the register from
most significant to least. The value of these four cells is the MAC byte
index (1-6) of the byte within the register. A value of 0 means the byte
is unused in the MAC address.
- ti,dscr-devstate-ctl-regs
This property describes the bitfields used to control the state of devices.
Each tuple describes a range of identical bitfields used to control one or
more devices (one bitfield per device). The layout of each tuple is:
start_id num_ids reg enable disable start_bit nbits
Where:
start_id is device id for the first device control in the range
num_ids is the number of device controls in the range
reg is the offset of the register holding the control bits
enable is the value to enable a device
disable is the value to disable a device (0xffffffff if cannot disable)
start_bit is the bit number of the first bit in the range
nbits is the number of bits per device control
- ti,dscr-devstate-stat-regs
This property describes the bitfields used to provide device state status
for device states controlled by the DSCR. Each tuple describes a range of
identical bitfields used to provide status for one or more devices (one
bitfield per device). The layout of each tuple is:
start_id num_ids reg enable disable start_bit nbits
Where:
start_id is device id for the first device status in the range
num_ids is the number of devices covered by the range
reg is the offset of the register holding the status bits
enable is the value indicating device is enabled
disable is the value indicating device is disabled
start_bit is the bit number of the first bit in the range
nbits is the number of bits per device status
- ti,dscr-privperm
Offset and default value for register used to set access privilege for
some SoC devices.
Example:
device-state-config-regs@2a80000 {
compatible = "ti,c64x+dscr";
reg = <0x02a80000 0x41000>;
ti,dscr-devstat = <0>;
ti,dscr-silicon-rev = <8 28 0xf>;
ti,dscr-rmii-resets = <0x40020 0x00040000>;
ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
ti,dscr-devstate-ctl-regs =
<0 12 0x40008 1 0 0 2
12 1 0x40008 3 0 30 2
13 2 0x4002c 1 0xffffffff 0 1>;
ti,dscr-devstate-stat-regs =
<0 10 0x40014 1 0 0 3
10 2 0x40018 1 0 0 3>;
ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
0x704 5 6 0 0>;
ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
ti,dscr-kick-regs = <0x38 0x83E70B13
0x3c 0x95A4F1E0>;
};

View File

@ -0,0 +1,62 @@
External Memory Interface
-------------------------
The emifa node describes a simple external bus controller found on some C6X
SoCs. This interface provides external busses with a number of chip selects.
Required properties:
- compatible: must be "ti,c64x+emifa", "simple-bus"
- reg: register area base and size
- #address-cells: must be 2 (chip-select + offset)
- #size-cells: must be 1
- ranges: mapping from EMIFA space to parent space
Optional properties:
- ti,dscr-dev-enable: Device ID if EMIF is enabled/disabled from DSCR
- ti,emifa-burst-priority:
Number of memory transfers after which the EMIF will elevate the priority
of the oldest command in the command FIFO. Setting this field to 255
disables this feature, thereby allowing old commands to stay in the FIFO
indefinitely.
- ti,emifa-ce-config:
Configuration values for each of the supported chip selects.
Example:
emifa@70000000 {
compatible = "ti,c64x+emifa", "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
reg = <0x70000000 0x100>;
ranges = <0x2 0x0 0xa0000000 0x00000008
0x3 0x0 0xb0000000 0x00400000
0x4 0x0 0xc0000000 0x10000000
0x5 0x0 0xD0000000 0x10000000>;
ti,dscr-dev-enable = <13>;
ti,emifa-burst-priority = <255>;
ti,emifa-ce-config = <0x00240120
0x00240120
0x00240122
0x00240122>;
flash@3,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x3 0x0 0x400000>;
bank-width = <1>;
device-width = <1>;
partition@0 {
reg = <0x0 0x400000>;
label = "NOR";
};
};
};
This shows a flash chip attached to chip select 3.

View File

@ -0,0 +1,104 @@
C6X Interrupt Chips
-------------------
* C64X+ Core Interrupt Controller
The core interrupt controller provides 16 prioritized interrupts to the
C64X+ core. Priority 0 and 1 are used for reset and NMI respectively.
Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt
sources coming from outside the core.
Required properties:
--------------------
- compatible: Should be "ti,c64x+core-pic";
- #interrupt-cells: <1>
Interrupt Specifier Definition
------------------------------
Single cell specifying the core interrupt priority level (4-15) where
4 is highest priority and 15 is lowest priority.
Example
-------
core_pic: interrupt-controller@0 {
interrupt-controller;
#interrupt-cells = <1>;
compatible = "ti,c64x+core-pic";
};
* C64x+ Megamodule Interrupt Controller
The megamodule PIC consists of four interrupt mupliplexers each of which
combine up to 32 interrupt inputs into a single interrupt output which
may be cascaded into the core interrupt controller. The megamodule PIC
has a total of 12 outputs cascading into the core interrupt controller.
One for each core interrupt priority level. In addition to the combined
interrupt sources, individual megamodule interrupts may be cascaded to
the core interrupt controller. When an individual interrupt is cascaded,
it is no longer handled through a megamodule interrupt combiner and is
considered to have the core interrupt controller as the parent.
Required properties:
--------------------
- compatible: "ti,c64x+megamod-pic"
- interrupt-controller
- #interrupt-cells: <1>
- reg: base address and size of register area
- interrupt-parent: must be core interrupt controller
- interrupts: This should have four cells; one for each interrupt combiner.
The cells contain the core priority interrupt to which the
corresponding combiner output is wired.
Optional properties:
--------------------
- ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core
priority interrupts. The first cell corresponds to
core priority 4 and the last cell corresponds to
core priority 15. The value of each cell is the
megamodule interrupt source which is MUXed to
the core interrupt corresponding to the cell
position. Allowed values are 4 - 127. Mapping for
interrupts 0 - 3 (combined interrupt sources) are
ignored.
Interrupt Specifier Definition
------------------------------
Single cell specifying the megamodule interrupt source (4-127). Note that
interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will
use the core interrupt controller as their parent and the specifier will
be the core priority level, not the megamodule interrupt number.
Examples
--------
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x1800000 0x1000>;
interrupt-parent = <&core_pic>;
interrupts = < 12 13 14 15 >;
};
This is a minimal example where all individual interrupts go through a
combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped
to interrupt 13, etc.
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x1800000 0x1000>;
interrupt-parent = <&core_pic>;
interrupts = < 12 13 14 15 >;
ti,c64x+megamod-pic-mux = < 0 0 0 0
32 0 0 0
0 0 0 0 >;
};
This the same as the first example except that megamodule interrupt 32 is
mapped directly to core priority interrupt 8. The node using this interrupt
must set the core controller as its interrupt parent and use 8 in the
interrupt specifier value.

View File

@ -0,0 +1,28 @@
C6X System-on-Chip
------------------
Required properties:
- compatible: "simple-bus"
- #address-cells: must be 1
- #size-cells: must be 1
- ranges
Optional properties:
- model: specific SoC model
- nodes for IP blocks within SoC
Example:
soc {
compatible = "simple-bus";
model = "tms320c6455";
#address-cells = <1>;
#size-cells = <1>;
ranges;
...
};

View File

@ -0,0 +1,26 @@
Timer64
-------
The timer64 node describes C6X event timers.
Required properties:
- compatible: must be "ti,c64x+timer64"
- reg: base address and size of register region
- interrupt-parent: interrupt controller
- interrupts: interrupt id
Optional properties:
- ti,dscr-dev-enable: Device ID used to enable timer IP through DSCR interface.
- ti,core-mask: on multi-core SoCs, bitmask of cores allowed to use this timer.
Example:
timer0: timer@25e0000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x01 >;
reg = <0x25e0000 0x40>;
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};

View File

@ -1645,6 +1645,14 @@ T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained
F: sound/pci/oxygen/
C6X ARCHITECTURE
M: Mark Salter <msalter@redhat.com>
M: Aurelien Jacquiot <a-jacquiot@ti.com>
L: linux-c6x-dev@linux-c6x.org
W: http://www.linux-c6x.org/wiki/index.php/Main_Page
S: Maintained
F: arch/c6x/
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
M: David Howells <dhowells@redhat.com>
L: linux-cachefs@redhat.com

174
arch/c6x/Kconfig Normal file
View File

@ -0,0 +1,174 @@
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.txt.
#
config TMS320C6X
def_bool y
select CLKDEV_LOOKUP
select GENERIC_IRQ_SHOW
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
select HAVE_GENERIC_HARDIRQS
select HAVE_MEMBLOCK
select HAVE_SPARSE_IRQ
select OF
select OF_EARLY_FLATTREE
config MMU
def_bool n
config ZONE_DMA
def_bool y
config FPU
def_bool n
config HIGHMEM
def_bool n
config NUMA
def_bool n
config RWSEM_GENERIC_SPINLOCK
def_bool y
config RWSEM_XCHGADD_ALGORITHM
def_bool n
config GENERIC_CALIBRATE_DELAY
def_bool y
config GENERIC_HWEIGHT
def_bool y
config GENERIC_CLOCKEVENTS
def_bool y
config GENERIC_CLOCKEVENTS_BROADCAST
bool
config GENERIC_BUG
def_bool y
config COMMON_CLKDEV
def_bool y
config C6X_BIG_KERNEL
bool "Build a big kernel"
help
The C6X function call instruction has a limited range of +/- 2MiB.
This is sufficient for most kernels, but some kernel configurations
with lots of compiled-in functionality may require a larger range
for function calls. Use this option to have the compiler generate
function calls with 32-bit range. This will make the kernel both
larger and slower.
If unsure, say N.
source "init/Kconfig"
# Use the generic interrupt handling code in kernel/irq/
source "kernel/Kconfig.freezer"
config CMDLINE_BOOL
bool "Default bootloader kernel arguments"
config CMDLINE
string "Kernel command line"
depends on CMDLINE_BOOL
default "console=ttyS0,57600"
help
On some architectures there is currently no way for the boot loader
to pass arguments to the kernel. For these architectures, you should
supply some command-line options at build time by entering them
here.
config CMDLINE_FORCE
bool "Force default kernel command string"
depends on CMDLINE_BOOL
default n
help
Set this to have arguments from the default kernel command string
override those passed by the boot loader.
config CPU_BIG_ENDIAN
bool "Build big-endian kernel"
default n
help
Say Y if you plan on running a kernel in big-endian mode.
Note that your board must be properly built and your board
port must properly enable any big-endian related features
of your chipset/board/processor.
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
default "13"
help
The kernel memory allocator divides physically contiguous memory
blocks into "zones", where each zone is a power of two number of
pages. This option selects the largest power of two that the kernel
keeps in the memory allocator. If you need to allocate very large
blocks of physically contiguous memory, then you may need to
increase this value.
This config option is actually maximum order plus one. For example,
a value of 11 means that the largest free memory block is 2^10 pages.
menu "Processor type and features"
source "arch/c6x/platforms/Kconfig"
config TMS320C6X_CACHES_ON
bool "L2 cache support"
default y
config KERNEL_RAM_BASE_ADDRESS
hex "Virtual address of memory base"
default 0xe0000000 if SOC_TMS320C6455
default 0xe0000000 if SOC_TMS320C6457
default 0xe0000000 if SOC_TMS320C6472
default 0x80000000
source "mm/Kconfig"
source "kernel/Kconfig.preempt"
source "kernel/Kconfig.hz"
source "kernel/time/Kconfig"
endmenu
menu "Executable file formats"
source "fs/Kconfig.binfmt"
endmenu
source "net/Kconfig"
source "drivers/Kconfig"
source "fs/Kconfig"
source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
menu "Kernel hacking"
source "lib/Kconfig.debug"
config ACCESS_CHECK
bool "Check the user pointer address"
default y
help
Usually the pointer transfer from user space is checked to see if its
address is in the kernel space.
Say N here to disable that check to improve the performance.
endmenu

60
arch/c6x/Makefile Normal file
View File

@ -0,0 +1,60 @@
#
# linux/arch/c6x/Makefile
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
cflags-y += -mno-dsbt -msdata=none
cflags-$(CONFIG_C6X_BIG_KERNEL) += -mlong-calls
CFLAGS_MODULE += -mlong-calls -mno-dsbt -msdata=none
CHECKFLAGS +=
KBUILD_CFLAGS += $(cflags-y)
KBUILD_AFLAGS += $(cflags-y)
ifdef CONFIG_CPU_BIG_ENDIAN
KBUILD_CFLAGS += -mbig-endian
KBUILD_AFLAGS += -mbig-endian
LINKFLAGS += -mbig-endian
KBUILD_LDFLAGS += -mbig-endian
LDFLAGS += -EB
endif
head-y := arch/c6x/kernel/head.o
core-y += arch/c6x/kernel/ arch/c6x/mm/ arch/c6x/platforms/
libs-y += arch/c6x/lib/
# Default to vmlinux.bin, override when needed
all: vmlinux.bin
boot := arch/$(ARCH)/boot
# Are we making a dtbImage.<boardname> target? If so, crack out the boardname
DTB:=$(subst dtbImage.,,$(filter dtbImage.%, $(MAKECMDGOALS)))
export DTB
ifneq ($(DTB),)
core-y += $(boot)/
endif
# With make 3.82 we cannot mix normal and wildcard targets
vmlinux.bin: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
dtbImage.%: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
define archhelp
@echo ' vmlinux.bin - Binary kernel image (arch/$(ARCH)/boot/vmlinux.bin)'
@echo ' dtbImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in'
@echo ' - stripped elf with fdt blob'
endef

30
arch/c6x/boot/Makefile Normal file
View File

@ -0,0 +1,30 @@
#
# Makefile for bootable kernel images
#
OBJCOPYFLAGS_vmlinux.bin := -O binary
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
DTC_FLAGS ?= -p 1024
ifneq ($(DTB),)
obj-y += linked_dtb.o
endif
$(obj)/%.dtb: $(src)/dts/%.dts FORCE
$(call cmd,dtc)
quiet_cmd_cp = CP $< $@$2
cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false)
# Generate builtin.dtb from $(DTB).dtb
$(obj)/builtin.dtb: $(obj)/$(DTB).dtb
$(call if_changed,cp)
$(obj)/linked_dtb.o: $(obj)/builtin.dtb
$(obj)/dtbImage.%: vmlinux
$(call if_changed,objcopy)
clean-files := $(obj)/*.dtb

View File

@ -0,0 +1,62 @@
/*
* arch/c6x/boot/dts/dsk6455.dts
*
* DSK6455 Evaluation Platform For TMS320C6455
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
/dts-v1/;
/include/ "tms320c6455.dtsi"
/ {
model = "Spectrum Digital DSK6455";
compatible = "spectrum-digital,dsk6455";
chosen {
bootargs = "root=/dev/nfs ip=dhcp rw";
};
memory {
device_type = "memory";
reg = <0xE0000000 0x08000000>;
};
soc {
megamod_pic: interrupt-controller@1800000 {
interrupts = < 12 13 14 15 >;
};
emifa@70000000 {
flash@3,0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x3 0x0 0x400000>;
bank-width = <1>;
device-width = <1>;
partition@0 {
reg = <0x0 0x400000>;
label = "NOR";
};
};
};
timer1: timer@2980000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 69 >;
};
clock-controller@029a0000 {
clock-frequency = <50000000>;
};
};
};

View File

@ -0,0 +1,48 @@
/*
* arch/c6x/boot/dts/evmc6457.dts
*
* EVMC6457 Evaluation Platform For TMS320C6457
*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
/dts-v1/;
/include/ "tms320c6457.dtsi"
/ {
model = "eInfochips EVMC6457";
compatible = "einfochips,evmc6457";
chosen {
bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
};
memory {
device_type = "memory";
reg = <0xE0000000 0x10000000>;
};
soc {
megamod_pic: interrupt-controller@1800000 {
interrupts = < 12 13 14 15 >;
};
timer0: timer@2940000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 67 >;
};
clock-controller@29a0000 {
clock-frequency = <60000000>;
};
};
};

View File

@ -0,0 +1,73 @@
/*
* arch/c6x/boot/dts/evmc6472.dts
*
* EVMC6472 Evaluation Platform For TMS320C6472
*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
/dts-v1/;
/include/ "tms320c6472.dtsi"
/ {
model = "eInfochips EVMC6472";
compatible = "einfochips,evmc6472";
chosen {
bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
};
memory {
device_type = "memory";
reg = <0xE0000000 0x10000000>;
};
soc {
megamod_pic: interrupt-controller@1800000 {
interrupts = < 12 13 14 15 >;
};
timer0: timer@25e0000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
timer1: timer@25f0000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
timer2: timer@2600000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
timer3: timer@2610000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
timer4: timer@2620000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
timer5: timer@2630000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 16 >;
};
clock-controller@29a0000 {
clock-frequency = <25000000>;
};
};
};

View File

@ -0,0 +1,58 @@
/*
* arch/c6x/boot/dts/evmc6474.dts
*
* EVMC6474 Evaluation Platform For TMS320C6474
*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
/dts-v1/;
/include/ "tms320c6474.dtsi"
/ {
model = "Spectrum Digital EVMC6474";
compatible = "spectrum-digital,evmc6474";
chosen {
bootargs = "console=hvc root=/dev/nfs ip=dhcp rw";
};
memory {
device_type = "memory";
reg = <0x80000000 0x08000000>;
};
soc {
megamod_pic: interrupt-controller@1800000 {
interrupts = < 12 13 14 15 >;
};
timer3: timer@2940000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 39 >;
};
timer4: timer@2950000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 41 >;
};
timer5: timer@2960000 {
interrupt-parent = <&megamod_pic>;
interrupts = < 43 >;
};
clock-controller@29a0000 {
clock-frequency = <50000000>;
};
};
};

View File

@ -0,0 +1,96 @@
/ {
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
model = "ti,c64x+";
reg = <0>;
};
};
soc {
compatible = "simple-bus";
model = "tms320c6455";
#address-cells = <1>;
#size-cells = <1>;
ranges;
core_pic: interrupt-controller {
interrupt-controller;
#interrupt-cells = <1>;
compatible = "ti,c64x+core-pic";
};
/*
* Megamodule interrupt controller
*/
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x1800000 0x1000>;
interrupt-parent = <&core_pic>;
};
cache-controller@1840000 {
compatible = "ti,c64x+cache";
reg = <0x01840000 0x8400>;
};
emifa@70000000 {
compatible = "ti,c64x+emifa", "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
reg = <0x70000000 0x100>;
ranges = <0x2 0x0 0xa0000000 0x00000008
0x3 0x0 0xb0000000 0x00400000
0x4 0x0 0xc0000000 0x10000000
0x5 0x0 0xD0000000 0x10000000>;
ti,dscr-dev-enable = <13>;
ti,emifa-burst-priority = <255>;
ti,emifa-ce-config = <0x00240120
0x00240120
0x00240122
0x00240122>;
};
timer1: timer@2980000 {
compatible = "ti,c64x+timer64";
reg = <0x2980000 0x40>;
ti,dscr-dev-enable = <4>;
};
clock-controller@029a0000 {
compatible = "ti,c6455-pll", "ti,c64x+pll";
reg = <0x029a0000 0x200>;
ti,c64x+pll-bypass-delay = <1440>;
ti,c64x+pll-reset-delay = <15360>;
ti,c64x+pll-lock-delay = <24000>;
};
device-state-config-regs@2a80000 {
compatible = "ti,c64x+dscr";
reg = <0x02a80000 0x41000>;
ti,dscr-devstat = <0>;
ti,dscr-silicon-rev = <8 28 0xf>;
ti,dscr-rmii-resets = <0 0x40020 0x00040000>;
ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>;
ti,dscr-devstate-ctl-regs =
<0 12 0x40008 1 0 0 2
12 1 0x40008 3 0 30 2
13 2 0x4002c 1 0xffffffff 0 1>;
ti,dscr-devstate-stat-regs =
<0 10 0x40014 1 0 0 3
10 2 0x40018 1 0 0 3>;
};
};
};

View File

@ -0,0 +1,68 @@
/ {
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
model = "ti,c64x+";
reg = <0>;
};
};
soc {
compatible = "simple-bus";
model = "tms320c6457";
#address-cells = <1>;
#size-cells = <1>;
ranges;
core_pic: interrupt-controller {
interrupt-controller;
#interrupt-cells = <1>;
compatible = "ti,c64x+core-pic";
};
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&core_pic>;
reg = <0x1800000 0x1000>;
};
cache-controller@1840000 {
compatible = "ti,c64x+cache";
reg = <0x01840000 0x8400>;
};
device-state-controller@2880800 {
compatible = "ti,c64x+dscr";
reg = <0x02880800 0x400>;
ti,dscr-devstat = <0x20>;
ti,dscr-silicon-rev = <0x18 28 0xf>;
ti,dscr-mac-fuse-regs = <0x114 3 4 5 6
0x118 0 0 1 2>;
ti,dscr-kick-regs = <0x38 0x83E70B13
0x3c 0x95A4F1E0>;
};
timer0: timer@2940000 {
compatible = "ti,c64x+timer64";
reg = <0x2940000 0x40>;
};
clock-controller@29a0000 {
compatible = "ti,c6457-pll", "ti,c64x+pll";
reg = <0x029a0000 0x200>;
ti,c64x+pll-bypass-delay = <300>;
ti,c64x+pll-reset-delay = <24000>;
ti,c64x+pll-lock-delay = <50000>;
};
};
};

View File

@ -0,0 +1,134 @@
/ {
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
reg = <0>;
model = "ti,c64x+";
};
cpu@1 {
device_type = "cpu";
reg = <1>;
model = "ti,c64x+";
};
cpu@2 {
device_type = "cpu";
reg = <2>;
model = "ti,c64x+";
};
cpu@3 {
device_type = "cpu";
reg = <3>;
model = "ti,c64x+";
};
cpu@4 {
device_type = "cpu";
reg = <4>;
model = "ti,c64x+";
};
cpu@5 {
device_type = "cpu";
reg = <5>;
model = "ti,c64x+";
};
};
soc {
compatible = "simple-bus";
model = "tms320c6472";
#address-cells = <1>;
#size-cells = <1>;
ranges;
core_pic: interrupt-controller {
compatible = "ti,c64x+core-pic";
interrupt-controller;
#interrupt-cells = <1>;
};
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x1800000 0x1000>;
interrupt-parent = <&core_pic>;
};
cache-controller@1840000 {
compatible = "ti,c64x+cache";
reg = <0x01840000 0x8400>;
};
timer0: timer@25e0000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x01 >;
reg = <0x25e0000 0x40>;
};
timer1: timer@25f0000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x02 >;
reg = <0x25f0000 0x40>;
};
timer2: timer@2600000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x04 >;
reg = <0x2600000 0x40>;
};
timer3: timer@2610000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x08 >;
reg = <0x2610000 0x40>;
};
timer4: timer@2620000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x10 >;
reg = <0x2620000 0x40>;
};
timer5: timer@2630000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x20 >;
reg = <0x2630000 0x40>;
};
clock-controller@29a0000 {
compatible = "ti,c6472-pll", "ti,c64x+pll";
reg = <0x029a0000 0x200>;
ti,c64x+pll-bypass-delay = <200>;
ti,c64x+pll-reset-delay = <12000>;
ti,c64x+pll-lock-delay = <80000>;
};
device-state-controller@2a80000 {
compatible = "ti,c64x+dscr";
reg = <0x02a80000 0x1000>;
ti,dscr-devstat = <0>;
ti,dscr-silicon-rev = <0x70c 16 0xff>;
ti,dscr-mac-fuse-regs = <0x700 1 2 3 4
0x704 5 6 0 0>;
ti,dscr-rmii-resets = <0x208 1
0x20c 1>;
ti,dscr-locked-regs = <0x200 0x204 0x0a1e183a
0x40c 0x420 0xbea7
0x41c 0x420 0xbea7>;
ti,dscr-privperm = <0x41c 0xaaaaaaaa>;
ti,dscr-devstate-ctl-regs = <0 13 0x200 1 0 0 1>;
};
};
};

View File

@ -0,0 +1,89 @@
/ {
#address-cells = <1>;
#size-cells = <1>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
reg = <0>;
model = "ti,c64x+";
};
cpu@1 {
device_type = "cpu";
reg = <1>;
model = "ti,c64x+";
};
cpu@2 {
device_type = "cpu";
reg = <2>;
model = "ti,c64x+";
};
};
soc {
compatible = "simple-bus";
model = "tms320c6474";
#address-cells = <1>;
#size-cells = <1>;
ranges;
core_pic: interrupt-controller {
interrupt-controller;
#interrupt-cells = <1>;
compatible = "ti,c64x+core-pic";
};
megamod_pic: interrupt-controller@1800000 {
compatible = "ti,c64x+megamod-pic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x1800000 0x1000>;
interrupt-parent = <&core_pic>;
};
cache-controller@1840000 {
compatible = "ti,c64x+cache";
reg = <0x01840000 0x8400>;
};
timer3: timer@2940000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x04 >;
reg = <0x2940000 0x40>;
};
timer4: timer@2950000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x02 >;
reg = <0x2950000 0x40>;
};
timer5: timer@2960000 {
compatible = "ti,c64x+timer64";
ti,core-mask = < 0x01 >;
reg = <0x2960000 0x40>;
};
device-state-controller@2880800 {
compatible = "ti,c64x+dscr";
reg = <0x02880800 0x400>;
ti,dscr-devstat = <0x004>;
ti,dscr-silicon-rev = <0x014 28 0xf>;
ti,dscr-mac-fuse-regs = <0x34 3 4 5 6
0x38 0 0 1 2>;
};
clock-controller@29a0000 {
compatible = "ti,c6474-pll", "ti,c64x+pll";
reg = <0x029a0000 0x200>;
ti,c64x+pll-bypass-delay = <120>;
ti,c64x+pll-reset-delay = <30000>;
ti,c64x+pll-lock-delay = <60000>;
};
};
};

View File

@ -0,0 +1,2 @@
.section __fdt_blob,"a"
.incbin "arch/c6x/boot/builtin.dtb"

View File

@ -0,0 +1,44 @@
CONFIG_SOC_TMS320C6455=y
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EXPERT=y
# CONFIG_FUTEX is not set
# CONFIG_SLUB_DEBUG is not set
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=2
CONFIG_BLK_DEV_RAM_SIZE=17000
CONFIG_MISC_DEVICES=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_IOMMU_SUPPORT is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_CRC16=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_MTD=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_PHYSMAP_OF=y

View File

@ -0,0 +1,41 @@
CONFIG_SOC_TMS320C6457=y
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EXPERT=y
# CONFIG_FUTEX is not set
# CONFIG_SLUB_DEBUG is not set
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
CONFIG_BOARD_EVM6457=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=2
CONFIG_BLK_DEV_RAM_SIZE=17000
CONFIG_MISC_DEVICES=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_IOMMU_SUPPORT is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_CRC16=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_BUGVERBOSE is not set

View File

@ -0,0 +1,42 @@
CONFIG_SOC_TMS320C6472=y
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EXPERT=y
# CONFIG_FUTEX is not set
# CONFIG_SLUB_DEBUG is not set
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
# CONFIG_CMDLINE_FORCE is not set
CONFIG_BOARD_EVM6472=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=2
CONFIG_BLK_DEV_RAM_SIZE=17000
CONFIG_MISC_DEVICES=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_IOMMU_SUPPORT is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_CRC16=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_BUGVERBOSE is not set

View File

@ -0,0 +1,42 @@
CONFIG_SOC_TMS320C6474=y
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_USER_NS is not set
# CONFIG_PID_NS is not set
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EXPERT=y
# CONFIG_FUTEX is not set
# CONFIG_SLUB_DEBUG is not set
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE=""
# CONFIG_CMDLINE_FORCE is not set
CONFIG_BOARD_EVM6474=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=2
CONFIG_BLK_DEV_RAM_SIZE=17000
CONFIG_MISC_DEVICES=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_IOMMU_SUPPORT is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_CRC16=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_BUGVERBOSE is not set

View File

@ -0,0 +1,54 @@
include include/asm-generic/Kbuild.asm
generic-y += atomic.h
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bug.h
generic-y += bugs.h
generic-y += cputime.h
generic-y += current.h
generic-y += device.h
generic-y += div64.h
generic-y += dma.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += futex.h
generic-y += hw_irq.h
generic-y += io.h
generic-y += ioctl.h
generic-y += ioctls.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local.h
generic-y += mman.h
generic-y += mmu_context.h
generic-y += msgbuf.h
generic-y += param.h
generic-y += pci.h
generic-y += percpu.h
generic-y += pgalloc.h
generic-y += poll.h
generic-y += posix_types.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += segment.h
generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += shmparam.h
generic-y += siginfo.h
generic-y += socket.h
generic-y += sockios.h
generic-y += stat.h
generic-y += statfs.h
generic-y += termbits.h
generic-y += termios.h
generic-y += tlbflush.h
generic-y += topology.h
generic-y += types.h
generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h

View File

@ -0,0 +1 @@
#include <generated/asm-offsets.h>

View File

@ -0,0 +1,105 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_BITOPS_H
#define _ASM_C6X_BITOPS_H
#ifdef __KERNEL__
#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/byteorder.h>
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
/*
* We are lucky, DSP is perfect for bitops: do it in 3 cycles
*/
/**
* __ffs - find first bit in word.
* @word: The word to search
*
* Undefined if no bit exists, so code should check against 0 first.
* Note __ffs(0) = undef, __ffs(1) = 0, __ffs(0x80000000) = 31.
*
*/
static inline unsigned long __ffs(unsigned long x)
{
asm (" bitr .M1 %0,%0\n"
" nop\n"
" lmbd .L1 1,%0,%0\n"
: "+a"(x));
return x;
}
/*
* ffz - find first zero in word.
* @word: The word to search
*
* Undefined if no zero exists, so code should check against ~0UL first.
*/
#define ffz(x) __ffs(~(x))
/**
* fls - find last (most-significant) bit set
* @x: the word to search
*
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
static inline int fls(int x)
{
if (!x)
return 0;
asm (" lmbd .L1 1,%0,%0\n" : "+a"(x));
return 32 - x;
}
/**
* ffs - find first bit set
* @x: the word to search
*
* This is defined the same way as
* the libc and compiler builtin ffs routines, therefore
* differs in spirit from the above ffz (man ffs).
* Note ffs(0) = 0, ffs(1) = 1, ffs(0x80000000) = 32.
*/
static inline int ffs(int x)
{
if (!x)
return 0;
return __ffs(x) + 1;
}
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/find.h>
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
#include <asm-generic/bitops/atomic.h>
#include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h>
#endif /* __KERNEL__ */
#endif /* _ASM_C6X_BITOPS_H */

View File

@ -0,0 +1,12 @@
#ifndef _ASM_C6X_BYTEORDER_H
#define _ASM_C6X_BYTEORDER_H
#include <asm/types.h>
#ifdef _BIG_ENDIAN
#include <linux/byteorder/big_endian.h>
#else /* _BIG_ENDIAN */
#include <linux/byteorder/little_endian.h>
#endif /* _BIG_ENDIAN */
#endif /* _ASM_BYTEORDER_H */

View File

@ -0,0 +1,90 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_CACHE_H
#define _ASM_C6X_CACHE_H
#include <linux/irqflags.h>
/*
* Cache line size
*/
#define L1D_CACHE_BYTES 64
#define L1P_CACHE_BYTES 32
#define L2_CACHE_BYTES 128
/*
* L2 used as cache
*/
#define L2MODE_SIZE L2MODE_256K_CACHE
/*
* For practical reasons the L1_CACHE_BYTES defines should not be smaller than
* the L2 line size
*/
#define L1_CACHE_BYTES L2_CACHE_BYTES
#define L2_CACHE_ALIGN_LOW(x) \
(((x) & ~(L2_CACHE_BYTES - 1)))
#define L2_CACHE_ALIGN_UP(x) \
(((x) + (L2_CACHE_BYTES - 1)) & ~(L2_CACHE_BYTES - 1))
#define L2_CACHE_ALIGN_CNT(x) \
(((x) + (sizeof(int) - 1)) & ~(sizeof(int) - 1))
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES
/*
* This is the granularity of hardware cacheability control.
*/
#define CACHEABILITY_ALIGN 0x01000000
/*
* Align a physical address to MAR regions
*/
#define CACHE_REGION_START(v) \
(((u32) (v)) & ~(CACHEABILITY_ALIGN - 1))
#define CACHE_REGION_END(v) \
(((u32) (v) + (CACHEABILITY_ALIGN - 1)) & ~(CACHEABILITY_ALIGN - 1))
extern void __init c6x_cache_init(void);
extern void enable_caching(unsigned long start, unsigned long end);
extern void disable_caching(unsigned long start, unsigned long end);
extern void L1_cache_off(void);
extern void L1_cache_on(void);
extern void L1P_cache_global_invalidate(void);
extern void L1D_cache_global_invalidate(void);
extern void L1D_cache_global_writeback(void);
extern void L1D_cache_global_writeback_invalidate(void);
extern void L2_cache_set_mode(unsigned int mode);
extern void L2_cache_global_writeback_invalidate(void);
extern void L2_cache_global_writeback(void);
extern void L1P_cache_block_invalidate(unsigned int start, unsigned int end);
extern void L1D_cache_block_invalidate(unsigned int start, unsigned int end);
extern void L1D_cache_block_writeback_invalidate(unsigned int start,
unsigned int end);
extern void L1D_cache_block_writeback(unsigned int start, unsigned int end);
extern void L2_cache_block_invalidate(unsigned int start, unsigned int end);
extern void L2_cache_block_writeback(unsigned int start, unsigned int end);
extern void L2_cache_block_writeback_invalidate(unsigned int start,
unsigned int end);
extern void L2_cache_block_invalidate_nowait(unsigned int start,
unsigned int end);
extern void L2_cache_block_writeback_nowait(unsigned int start,
unsigned int end);
extern void L2_cache_block_writeback_invalidate_nowait(unsigned int start,
unsigned int end);
#endif /* _ASM_C6X_CACHE_H */

View File

@ -0,0 +1,65 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_CACHEFLUSH_H
#define _ASM_C6X_CACHEFLUSH_H
#include <linux/spinlock.h>
#include <asm/setup.h>
#include <asm/cache.h>
#include <asm/mman.h>
#include <asm/page.h>
#include <asm/string.h>
/*
* virtually-indexed cache management (our cache is physically indexed)
*/
#define flush_cache_all() do {} while (0)
#define flush_cache_mm(mm) do {} while (0)
#define flush_cache_dup_mm(mm) do {} while (0)
#define flush_cache_range(mm, start, end) do {} while (0)
#define flush_cache_page(vma, vmaddr, pfn) do {} while (0)
#define flush_cache_vmap(start, end) do {} while (0)
#define flush_cache_vunmap(start, end) do {} while (0)
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
#define flush_dcache_page(page) do {} while (0)
#define flush_dcache_mmap_lock(mapping) do {} while (0)
#define flush_dcache_mmap_unlock(mapping) do {} while (0)
/*
* physically-indexed cache management
*/
#define flush_icache_range(s, e) \
do { \
L1D_cache_block_writeback((s), (e)); \
L1P_cache_block_invalidate((s), (e)); \
} while (0)
#define flush_icache_page(vma, page) \
do { \
if ((vma)->vm_flags & PROT_EXEC) \
L1D_cache_block_writeback_invalidate(page_address(page), \
(unsigned long) page_address(page) + PAGE_SIZE)); \
L1P_cache_block_invalidate(page_address(page), \
(unsigned long) page_address(page) + PAGE_SIZE)); \
} while (0)
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
do { \
memcpy(dst, src, len); \
flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \
} while (0)
#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
memcpy(dst, src, len)
#endif /* _ASM_C6X_CACHEFLUSH_H */

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_CHECKSUM_H
#define _ASM_C6X_CHECKSUM_H
static inline __wsum
csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
unsigned short proto, __wsum sum)
{
unsigned long long tmp;
asm ("add .d1 %1,%5,%1\n"
"|| addu .l1 %3,%4,%0\n"
"addu .l1 %2,%0,%0\n"
#ifndef CONFIG_CPU_BIG_ENDIAN
"|| shl .s1 %1,8,%1\n"
#endif
"addu .l1 %1,%0,%0\n"
"add .l1 %P0,%p0,%2\n"
: "=&a"(tmp), "+a"(len), "+a"(sum)
: "a" (saddr), "a" (daddr), "a" (proto));
return sum;
}
#define csum_tcpudp_nofold csum_tcpudp_nofold
#include <asm-generic/checksum.h>
#endif /* _ASM_C6X_CHECKSUM_H */

View File

@ -0,0 +1,22 @@
#ifndef _ASM_CLKDEV_H
#define _ASM_CLKDEV_H
#include <linux/slab.h>
struct clk;
static inline int __clk_get(struct clk *clk)
{
return 1;
}
static inline void __clk_put(struct clk *clk)
{
}
static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
{
return kzalloc(size, GFP_KERNEL);
}
#endif /* _ASM_CLKDEV_H */

View File

@ -0,0 +1,148 @@
/*
* TI C64X clock definitions
*
* Copyright (C) 2010, 2011 Texas Instruments.
* Contributed by: Mark Salter <msalter@redhat.com>
*
* Copied heavily from arm/mach-davinci/clock.h, so:
*
* Copyright (C) 2006-2007 Texas Instruments.
* Copyright (C) 2008-2009 Deep Root Systems, LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_CLOCK_H
#define _ASM_C6X_CLOCK_H
#ifndef __ASSEMBLER__
#include <linux/list.h>
/* PLL/Reset register offsets */
#define PLLCTL 0x100
#define PLLM 0x110
#define PLLPRE 0x114
#define PLLDIV1 0x118
#define PLLDIV2 0x11c
#define PLLDIV3 0x120
#define PLLPOST 0x128
#define PLLCMD 0x138
#define PLLSTAT 0x13c
#define PLLALNCTL 0x140
#define PLLDCHANGE 0x144
#define PLLCKEN 0x148
#define PLLCKSTAT 0x14c
#define PLLSYSTAT 0x150
#define PLLDIV4 0x160
#define PLLDIV5 0x164
#define PLLDIV6 0x168
#define PLLDIV7 0x16c
#define PLLDIV8 0x170
#define PLLDIV9 0x174
#define PLLDIV10 0x178
#define PLLDIV11 0x17c
#define PLLDIV12 0x180
#define PLLDIV13 0x184
#define PLLDIV14 0x188
#define PLLDIV15 0x18c
#define PLLDIV16 0x190
/* PLLM register bits */
#define PLLM_PLLM_MASK 0xff
#define PLLM_VAL(x) ((x) - 1)
/* PREDIV register bits */
#define PLLPREDIV_EN BIT(15)
#define PLLPREDIV_VAL(x) ((x) - 1)
/* PLLCTL register bits */
#define PLLCTL_PLLEN BIT(0)
#define PLLCTL_PLLPWRDN BIT(1)
#define PLLCTL_PLLRST BIT(3)
#define PLLCTL_PLLDIS BIT(4)
#define PLLCTL_PLLENSRC BIT(5)
#define PLLCTL_CLKMODE BIT(8)
/* PLLCMD register bits */
#define PLLCMD_GOSTAT BIT(0)
/* PLLSTAT register bits */
#define PLLSTAT_GOSTAT BIT(0)
/* PLLDIV register bits */
#define PLLDIV_EN BIT(15)
#define PLLDIV_RATIO_MASK 0x1f
#define PLLDIV_RATIO(x) ((x) - 1)
struct pll_data;
struct clk {
struct list_head node;
struct module *owner;
const char *name;
unsigned long rate;
int usecount;
u32 flags;
struct clk *parent;
struct list_head children; /* list of children */
struct list_head childnode; /* parent's child list node */
struct pll_data *pll_data;
u32 div;
unsigned long (*recalc) (struct clk *);
int (*set_rate) (struct clk *clk, unsigned long rate);
int (*round_rate) (struct clk *clk, unsigned long rate);
};
/* Clock flags: SoC-specific flags start at BIT(16) */
#define ALWAYS_ENABLED BIT(1)
#define CLK_PLL BIT(2) /* PLL-derived clock */
#define PRE_PLL BIT(3) /* source is before PLL mult/div */
#define FIXED_DIV_PLL BIT(4) /* fixed divisor from PLL */
#define FIXED_RATE_PLL BIT(5) /* fixed ouput rate PLL */
#define MAX_PLL_SYSCLKS 16
struct pll_data {
void __iomem *base;
u32 num;
u32 flags;
u32 input_rate;
u32 bypass_delay; /* in loops */
u32 reset_delay; /* in loops */
u32 lock_delay; /* in loops */
struct clk sysclks[MAX_PLL_SYSCLKS + 1];
};
/* pll_data flag bit */
#define PLL_HAS_PRE BIT(0)
#define PLL_HAS_MUL BIT(1)
#define PLL_HAS_POST BIT(2)
#define CLK(dev, con, ck) \
{ \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
} \
extern void c6x_clks_init(struct clk_lookup *clocks);
extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk);
extern void c64x_setup_clocks(void);
extern struct pll_data c6x_soc_pll1;
extern struct clk clkin1;
extern struct clk c6x_core_clk;
extern struct clk c6x_i2c_clk;
extern struct clk c6x_watchdog_clk;
extern struct clk c6x_mcbsp1_clk;
extern struct clk c6x_mcbsp2_clk;
extern struct clk c6x_mdio_clk;
#endif
#endif /* _ASM_C6X_CLOCK_H */

View File

@ -0,0 +1,67 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_DELAY_H
#define _ASM_C6X_DELAY_H
#include <linux/kernel.h>
extern unsigned int ticks_per_ns_scaled;
static inline void __delay(unsigned long loops)
{
uint32_t tmp;
/* 6 cycles per loop */
asm volatile (" mv .s1 %0,%1\n"
"0: [%1] b .s1 0b\n"
" add .l1 -6,%0,%0\n"
" cmplt .l1 1,%0,%1\n"
" nop 3\n"
: "+a"(loops), "=A"(tmp));
}
static inline void _c6x_tickdelay(unsigned int x)
{
uint32_t cnt, endcnt;
asm volatile (" mvc .s2 TSCL,%0\n"
" add .s2x %0,%1,%2\n"
" || mvk .l2 1,B0\n"
"0: [B0] b .s2 0b\n"
" mvc .s2 TSCL,%0\n"
" sub .s2 %0,%2,%0\n"
" cmpgt .l2 0,%0,B0\n"
" nop 2\n"
: "=b"(cnt), "+a"(x), "=b"(endcnt) : : "B0");
}
/* use scaled math to avoid slow division */
#define C6X_NDELAY_SCALE 10
static inline void _ndelay(unsigned int n)
{
_c6x_tickdelay((ticks_per_ns_scaled * n) >> C6X_NDELAY_SCALE);
}
static inline void _udelay(unsigned int n)
{
while (n >= 10) {
_ndelay(10000);
n -= 10;
}
while (n-- > 0)
_ndelay(1000);
}
#define udelay(x) _udelay((unsigned int)(x))
#define ndelay(x) _ndelay((unsigned int)(x))
#endif /* _ASM_C6X_DELAY_H */

View File

@ -0,0 +1,91 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot <aurelien.jacquiot@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _ASM_C6X_DMA_MAPPING_H
#define _ASM_C6X_DMA_MAPPING_H
#include <linux/dma-debug.h>
#include <asm-generic/dma-coherent.h>
#define dma_supported(d, m) 1
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
{
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO;
*dev->dma_mask = dma_mask;
return 0;
}
/*
* DMA errors are defined by all-bits-set in the DMA address.
*/
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return dma_addr == ~0;
}
extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
size_t size, enum dma_data_direction dir);
extern void dma_unmap_single(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir);
extern int dma_map_sg(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction direction);
extern void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction direction);
static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir)
{
dma_addr_t handle;
handle = dma_map_single(dev, page_address(page) + offset, size, dir);
debug_dma_map_page(dev, page, offset, size, dir, handle, false);
return handle;
}
static inline void dma_unmap_page(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
dma_unmap_single(dev, handle, size, dir);
debug_dma_unmap_page(dev, handle, size, dir, false);
}
extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir);
extern void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
size_t size,
enum dma_data_direction dir);
extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir);
extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir);
extern void coherent_mem_init(u32 start, u32 size);
extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent((d), (s), (v), (h))
#endif /* _ASM_C6X_DMA_MAPPING_H */

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _ASM_C6X_DSCR_H
#define _ASM_C6X_DSCR_H
enum dscr_devstate_t {
DSCR_DEVSTATE_ENABLED,
DSCR_DEVSTATE_DISABLED,
};
/*
* Set the device state of the device with the given ID.
*
* Individual drivers should use this to enable or disable the
* hardware device. The devid used to identify the device being
* controlled should be a property in the device's tree node.
*/
extern void dscr_set_devstate(int devid, enum dscr_devstate_t state);
/*
* Assert or de-assert an RMII reset.
*/
extern void dscr_rmii_reset(int id, int assert);
extern void dscr_probe(void);
#endif /* _ASM_C6X_DSCR_H */

113
arch/c6x/include/asm/elf.h Normal file
View File

@ -0,0 +1,113 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_ELF_H
#define _ASM_C6X_ELF_H
/*
* ELF register definitions..
*/
#include <asm/ptrace.h>
typedef unsigned long elf_greg_t;
typedef unsigned long elf_fpreg_t;
#define ELF_NGREG 58
#define ELF_NFPREG 1
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) ((x)->e_machine == EM_TI_C6000)
#define elf_check_const_displacement(x) (1)
/*
* These are used to set parameters in the core dumps.
*/
#ifdef __LITTLE_ENDIAN__
#define ELF_DATA ELFDATA2LSB
#else
#define ELF_DATA ELFDATA2MSB
#endif
#define ELF_CLASS ELFCLASS32
#define ELF_ARCH EM_TI_C6000
/* Nothing for now. Need to setup DP... */
#define ELF_PLAT_INIT(_r)
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#define ELF_CORE_COPY_REGS(_dest, _regs) \
memcpy((char *) &_dest, (char *) _regs, \
sizeof(struct pt_regs));
/* This yields a mask that user programs can use to figure out what
instruction set this cpu supports. */
#define ELF_HWCAP (0)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo. */
#define ELF_PLATFORM (NULL)
#define SET_PERSONALITY(ex) set_personality(PER_LINUX)
/* C6X specific section types */
#define SHT_C6000_UNWIND 0x70000001
#define SHT_C6000_PREEMPTMAP 0x70000002
#define SHT_C6000_ATTRIBUTES 0x70000003
/* C6X specific DT_ tags */
#define DT_C6000_DSBT_BASE 0x70000000
#define DT_C6000_DSBT_SIZE 0x70000001
#define DT_C6000_PREEMPTMAP 0x70000002
#define DT_C6000_DSBT_INDEX 0x70000003
/* C6X specific relocs */
#define R_C6000_NONE 0
#define R_C6000_ABS32 1
#define R_C6000_ABS16 2
#define R_C6000_ABS8 3
#define R_C6000_PCR_S21 4
#define R_C6000_PCR_S12 5
#define R_C6000_PCR_S10 6
#define R_C6000_PCR_S7 7
#define R_C6000_ABS_S16 8
#define R_C6000_ABS_L16 9
#define R_C6000_ABS_H16 10
#define R_C6000_SBR_U15_B 11
#define R_C6000_SBR_U15_H 12
#define R_C6000_SBR_U15_W 13
#define R_C6000_SBR_S16 14
#define R_C6000_SBR_L16_B 15
#define R_C6000_SBR_L16_H 16
#define R_C6000_SBR_L16_W 17
#define R_C6000_SBR_H16_B 18
#define R_C6000_SBR_H16_H 19
#define R_C6000_SBR_H16_W 20
#define R_C6000_SBR_GOT_U15_W 21
#define R_C6000_SBR_GOT_L16_W 22
#define R_C6000_SBR_GOT_H16_W 23
#define R_C6000_DSBT_INDEX 24
#define R_C6000_PREL31 25
#define R_C6000_COPY 26
#define R_C6000_ALIGN 253
#define R_C6000_FPHEAD 254
#define R_C6000_NOCMP 255
#endif /*_ASM_C6X_ELF_H */

View File

@ -0,0 +1,6 @@
#ifndef _ASM_C6X_FTRACE_H
#define _ASM_C6X_FTRACE_H
/* empty */
#endif /* _ASM_C6X_FTRACE_H */

View File

@ -0,0 +1,20 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_HARDIRQ_H
#define _ASM_C6X_HARDIRQ_H
extern void ack_bad_irq(int irq);
#define ack_bad_irq ack_bad_irq
#include <asm-generic/hardirq.h>
#endif /* _ASM_C6X_HARDIRQ_H */

302
arch/c6x/include/asm/irq.h Normal file
View File

@ -0,0 +1,302 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Large parts taken directly from powerpc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_IRQ_H
#define _ASM_C6X_IRQ_H
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
#include <asm/percpu.h>
#define irq_canonicalize(irq) (irq)
/*
* The C64X+ core has 16 IRQ vectors. One each is used by Reset and NMI. Two
* are reserved. The remaining 12 vectors are used to route SoC interrupts.
* These interrupt vectors are prioritized with IRQ 4 having the highest
* priority and IRQ 15 having the lowest.
*
* The C64x+ megamodule provides a PIC which combines SoC IRQ sources into a
* single core IRQ vector. There are four combined sources, each of which
* feed into one of the 12 general interrupt vectors. The remaining 8 vectors
* can each route a single SoC interrupt directly.
*/
#define NR_PRIORITY_IRQS 16
#define NR_IRQS_LEGACY NR_PRIORITY_IRQS
/* Total number of virq in the platform */
#define NR_IRQS 256
/* This number is used when no interrupt has been assigned */
#define NO_IRQ 0
/* This type is the placeholder for a hardware interrupt number. It has to
* be big enough to enclose whatever representation is used by a given
* platform.
*/
typedef unsigned long irq_hw_number_t;
/* Interrupt controller "host" data structure. This could be defined as a
* irq domain controller. That is, it handles the mapping between hardware
* and virtual interrupt numbers for a given interrupt domain. The host
* structure is generally created by the PIC code for a given PIC instance
* (though a host can cover more than one PIC if they have a flat number
* model). It's the host callbacks that are responsible for setting the
* irq_chip on a given irq_desc after it's been mapped.
*
* The host code and data structures are fairly agnostic to the fact that
* we use an open firmware device-tree. We do have references to struct
* device_node in two places: in irq_find_host() to find the host matching
* a given interrupt controller node, and of course as an argument to its
* counterpart host->ops->match() callback. However, those are treated as
* generic pointers by the core and the fact that it's actually a device-node
* pointer is purely a convention between callers and implementation. This
* code could thus be used on other architectures by replacing those two
* by some sort of arch-specific void * "token" used to identify interrupt
* controllers.
*/
struct irq_host;
struct radix_tree_root;
struct device_node;
/* Functions below are provided by the host and called whenever a new mapping
* is created or an old mapping is disposed. The host can then proceed to
* whatever internal data structures management is required. It also needs
* to setup the irq_desc when returning from map().
*/
struct irq_host_ops {
/* Match an interrupt controller device node to a host, returns
* 1 on a match
*/
int (*match)(struct irq_host *h, struct device_node *node);
/* Create or update a mapping between a virtual irq number and a hw
* irq number. This is called only once for a given mapping.
*/
int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
/* Dispose of such a mapping */
void (*unmap)(struct irq_host *h, unsigned int virq);
/* Translate device-tree interrupt specifier from raw format coming
* from the firmware to a irq_hw_number_t (interrupt line number) and
* type (sense) that can be passed to set_irq_type(). In the absence
* of this callback, irq_create_of_mapping() and irq_of_parse_and_map()
* will return the hw number in the first cell and IRQ_TYPE_NONE for
* the type (which amount to keeping whatever default value the
* interrupt controller has for that line)
*/
int (*xlate)(struct irq_host *h, struct device_node *ctrler,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type);
};
struct irq_host {
struct list_head link;
/* type of reverse mapping technique */
unsigned int revmap_type;
#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */
#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */
#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */
#define IRQ_HOST_MAP_TREE 3 /* radix tree */
union {
struct {
unsigned int size;
unsigned int *revmap;
} linear;
struct radix_tree_root tree;
} revmap_data;
struct irq_host_ops *ops;
void *host_data;
irq_hw_number_t inval_irq;
/* Optional device node pointer */
struct device_node *of_node;
};
struct irq_data;
extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
extern irq_hw_number_t virq_to_hw(unsigned int virq);
extern bool virq_is_host(unsigned int virq, struct irq_host *host);
/**
* irq_alloc_host - Allocate a new irq_host data structure
* @of_node: optional device-tree node of the interrupt controller
* @revmap_type: type of reverse mapping to use
* @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map
* @ops: map/unmap host callbacks
* @inval_irq: provide a hw number in that host space that is always invalid
*
* Allocates and initialize and irq_host structure. Note that in the case of
* IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns
* for all legacy interrupts except 0 (which is always the invalid irq for
* a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by
* this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated
* later during boot automatically (the reverse mapping will use the slow path
* until that happens).
*/
extern struct irq_host *irq_alloc_host(struct device_node *of_node,
unsigned int revmap_type,
unsigned int revmap_arg,
struct irq_host_ops *ops,
irq_hw_number_t inval_irq);
/**
* irq_find_host - Locates a host for a given device node
* @node: device-tree node of the interrupt controller
*/
extern struct irq_host *irq_find_host(struct device_node *node);
/**
* irq_set_default_host - Set a "default" host
* @host: default host pointer
*
* For convenience, it's possible to set a "default" host that will be used
* whenever NULL is passed to irq_create_mapping(). It makes life easier for
* platforms that want to manipulate a few hard coded interrupt numbers that
* aren't properly represented in the device-tree.
*/
extern void irq_set_default_host(struct irq_host *host);
/**
* irq_set_virq_count - Set the maximum number of virt irqs
* @count: number of linux virtual irqs, capped with NR_IRQS
*
* This is mainly for use by platforms like iSeries who want to program
* the virtual irq number in the controller to avoid the reverse mapping
*/
extern void irq_set_virq_count(unsigned int count);
/**
* irq_create_mapping - Map a hardware interrupt into linux virq space
* @host: host owning this hardware interrupt or NULL for default host
* @hwirq: hardware irq number in that host space
*
* Only one mapping per hardware interrupt is permitted. Returns a linux
* virq number.
* If the sense/trigger is to be specified, set_irq_type() should be called
* on the number returned from that call.
*/
extern unsigned int irq_create_mapping(struct irq_host *host,
irq_hw_number_t hwirq);
/**
* irq_dispose_mapping - Unmap an interrupt
* @virq: linux virq number of the interrupt to unmap
*/
extern void irq_dispose_mapping(unsigned int virq);
/**
* irq_find_mapping - Find a linux virq from an hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a slow path, for use by generic code. It's expected that an
* irq controller implementation directly calls the appropriate low level
* mapping function.
*/
extern unsigned int irq_find_mapping(struct irq_host *host,
irq_hw_number_t hwirq);
/**
* irq_create_direct_mapping - Allocate a virq for direct mapping
* @host: host to allocate the virq for or NULL for default host
*
* This routine is used for irq controllers which can choose the hardware
* interrupt numbers they generate. In such a case it's simplest to use
* the linux virq as the hardware interrupt number.
*/
extern unsigned int irq_create_direct_mapping(struct irq_host *host);
/**
* irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
* @host: host owning this hardware interrupt
* @virq: linux irq number
* @hwirq: hardware irq number in that host space
*
* This is for use by irq controllers that use a radix tree reverse
* mapping for fast lookup.
*/
extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq);
/**
* irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses radix tree
* revmaps
*/
extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
irq_hw_number_t hwirq);
/**
* irq_linear_revmap - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses linear
* revmaps. It does fallback to the slow path if the revmap doesn't exist
* yet and will create the revmap entry with appropriate locking
*/
extern unsigned int irq_linear_revmap(struct irq_host *host,
irq_hw_number_t hwirq);
/**
* irq_alloc_virt - Allocate virtual irq numbers
* @host: host owning these new virtual irqs
* @count: number of consecutive numbers to allocate
* @hint: pass a hint number, the allocator will try to use a 1:1 mapping
*
* This is a low level function that is used internally by irq_create_mapping()
* and that can be used by some irq controllers implementations for things
* like allocating ranges of numbers for MSIs. The revmaps are left untouched.
*/
extern unsigned int irq_alloc_virt(struct irq_host *host,
unsigned int count,
unsigned int hint);
/**
* irq_free_virt - Free virtual irq numbers
* @virq: virtual irq number of the first interrupt to free
* @count: number of interrupts to free
*
* This function is the opposite of irq_alloc_virt. It will not clear reverse
* maps, this should be done previously by unmap'ing the interrupt. In fact,
* all interrupts covered by the range being freed should have been unmapped
* prior to calling this.
*/
extern void irq_free_virt(unsigned int virq, unsigned int count);
extern void __init init_pic_c64xplus(void);
extern void init_IRQ(void);
struct pt_regs;
extern asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs);
extern unsigned long irq_err_count;
#endif /* _ASM_C6X_IRQ_H */

View File

@ -0,0 +1,72 @@
/*
* C6X IRQ flag handling
*
* Copyright (C) 2010 Texas Instruments Incorporated
* Written by Mark Salter (msalter@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _ASM_IRQFLAGS_H
#define _ASM_IRQFLAGS_H
#ifndef __ASSEMBLY__
/* read interrupt enabled status */
static inline unsigned long arch_local_save_flags(void)
{
unsigned long flags;
asm volatile (" mvc .s2 CSR,%0\n" : "=b"(flags));
return flags;
}
/* set interrupt enabled status */
static inline void arch_local_irq_restore(unsigned long flags)
{
asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags));
}
/* unconditionally enable interrupts */
static inline void arch_local_irq_enable(void)
{
unsigned long flags = arch_local_save_flags();
flags |= 1;
arch_local_irq_restore(flags);
}
/* unconditionally disable interrupts */
static inline void arch_local_irq_disable(void)
{
unsigned long flags = arch_local_save_flags();
flags &= ~1;
arch_local_irq_restore(flags);
}
/* get status and disable interrupts */
static inline unsigned long arch_local_irq_save(void)
{
unsigned long flags;
flags = arch_local_save_flags();
arch_local_irq_restore(flags & ~1);
return flags;
}
/* test flags */
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return (flags & 1) == 0;
}
/* test hardware interrupt enable bit */
static inline int arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
#endif /* __ASSEMBLY__ */
#endif /* __ASM_IRQFLAGS_H */

View File

@ -0,0 +1,30 @@
#ifndef _ASM_C6X_LINKAGE_H
#define _ASM_C6X_LINKAGE_H
#ifdef __ASSEMBLER__
#define __ALIGN .align 2
#define __ALIGN_STR ".align 2"
#ifndef __DSBT__
#define ENTRY(name) \
.global name @ \
__ALIGN @ \
name:
#else
#define ENTRY(name) \
.global name @ \
.hidden name @ \
__ALIGN @ \
name:
#endif
#define ENDPROC(name) \
.type name, @function @ \
.size name, . - name
#endif
#include <asm-generic/linkage.h>
#endif /* _ASM_C6X_LINKAGE_H */

View File

@ -0,0 +1,9 @@
#ifndef _C6X_MEGAMOD_PIC_H
#define _C6X_MEGAMOD_PIC_H
#ifdef __KERNEL__
extern void __init megamod_pic_init(void);
#endif /* __KERNEL__ */
#endif /* _C6X_MEGAMOD_PIC_H */

View File

@ -0,0 +1,18 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_MMU_H
#define _ASM_C6X_MMU_H
typedef struct {
unsigned long end_brk;
} mm_context_t;
#endif /* _ASM_C6X_MMU_H */

View File

@ -0,0 +1,33 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.34 by: Mark Salter (msalter@redhat.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_MODULE_H
#define _ASM_C6X_MODULE_H
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#define Elf_Word Elf32_Word
/*
* This file contains the C6x architecture specific module code.
*/
struct mod_arch_specific {
};
struct loaded_sections {
unsigned int new_vaddr;
unsigned int loaded;
};
#endif /* _ASM_C6X_MODULE_H */

View File

@ -0,0 +1,6 @@
#ifndef _ASM_C6X_MUTEX_H
#define _ASM_C6X_MUTEX_H
#include <asm-generic/mutex-null.h>
#endif /* _ASM_C6X_MUTEX_H */

View File

@ -0,0 +1,11 @@
#ifndef _ASM_C6X_PAGE_H
#define _ASM_C6X_PAGE_H
#define VM_DATA_DEFAULT_FLAGS \
(VM_READ | VM_WRITE | \
((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
#include <asm-generic/page.h>
#endif /* _ASM_C6X_PAGE_H */

View File

@ -0,0 +1,81 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_PGTABLE_H
#define _ASM_C6X_PGTABLE_H
#include <asm-generic/4level-fixup.h>
#include <asm/setup.h>
#include <asm/page.h>
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
*/
#define VMALLOC_START 0
#define VMALLOC_END 0xffffffff
#define pgd_present(pgd) (1)
#define pgd_none(pgd) (0)
#define pgd_bad(pgd) (0)
#define pgd_clear(pgdp)
#define kern_addr_valid(addr) (1)
#define pmd_offset(a, b) ((void *)0)
#define pmd_none(x) (!pmd_val(x))
#define pmd_present(x) (pmd_val(x))
#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK)
#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */
#define pgprot_noncached(prot) (prot)
extern void paging_init(void);
#define __swp_type(x) (0)
#define __swp_offset(x) (0)
#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
static inline int pte_file(pte_t pte)
{
return 0;
}
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
extern unsigned long empty_zero_page;
#define swapper_pg_dir ((pgd_t *) 0)
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
#define io_remap_pfn_range remap_pfn_range
#define io_remap_page_range(vma, vaddr, paddr, size, prot) \
remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot)
#include <asm-generic/pgtable.h>
#endif /* _ASM_C6X_PGTABLE_H */

View File

@ -0,0 +1,132 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.34: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_PROCESSOR_H
#define _ASM_C6X_PROCESSOR_H
#include <asm/ptrace.h>
#include <asm/page.h>
#include <asm/current.h>
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
#define current_text_addr() \
({ \
void *__pc; \
asm("mvc .S2 pce1,%0\n" : "=b"(__pc)); \
__pc; \
})
/*
* User space process size. This is mostly meaningless for NOMMU
* but some C6X processors may have RAM addresses up to 0xFFFFFFFF.
* Since calls like mmap() can return an address or an error, we
* have to allow room for error returns when code does something
* like:
*
* addr = do_mmap(...)
* if ((unsigned long)addr >= TASK_SIZE)
* ... its an error code, not an address ...
*
* Here, we allow for 4096 error codes which means we really can't
* use the last 4K page on systems with RAM extending all the way
* to the end of the 32-bit address space.
*/
#define TASK_SIZE 0xFFFFF000
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's. We won't be using it
*/
#define TASK_UNMAPPED_BASE 0
struct thread_struct {
unsigned long long b15_14;
unsigned long long a15_14;
unsigned long long b13_12;
unsigned long long a13_12;
unsigned long long b11_10;
unsigned long long a11_10;
unsigned long long ricl_icl;
unsigned long usp; /* user stack pointer */
unsigned long pc; /* kernel pc */
unsigned long wchan;
};
#define INIT_THREAD \
{ \
.usp = 0, \
.wchan = 0, \
}
#define INIT_MMAP { \
&init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, \
NULL, NULL }
#define task_pt_regs(task) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(task)) - 1)
#define alloc_kernel_stack() __get_free_page(GFP_KERNEL)
#define free_kernel_stack(page) free_page((page))
/* Forward declaration, a strange C thing */
struct task_struct;
extern void start_thread(struct pt_regs *regs, unsigned int pc,
unsigned long usp);
/* Free all resources held by a thread. */
static inline void release_thread(struct task_struct *dead_task)
{
}
/* Prepare to copy thread state - unlazy all lazy status */
#define prepare_to_copy(tsk) do { } while (0)
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
/*
* saved PC of a blocked thread.
*/
#define thread_saved_pc(tsk) (task_pt_regs(tsk)->pc)
/*
* saved kernel SP and DP of a blocked thread.
*/
#ifdef _BIG_ENDIAN
#define thread_saved_ksp(tsk) \
(*(unsigned long *)&(tsk)->thread.b15_14)
#define thread_saved_dp(tsk) \
(*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
#else
#define thread_saved_ksp(tsk) \
(*(((unsigned long *)&(tsk)->thread.b15_14) + 1))
#define thread_saved_dp(tsk) \
(*(unsigned long *)&(tsk)->thread.b15_14)
#endif
extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(task)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(task)->sp)
#define cpu_relax() do { } while (0)
extern const struct seq_operations cpuinfo_op;
#endif /* ASM_C6X_PROCESSOR_H */

View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2010 Texas Instruments Incorporated
* Author: Mark Salter (msalter@redhat.com)
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_PROCINFO_H
#define _ASM_C6X_PROCINFO_H
#ifdef __KERNEL__
struct proc_info_list {
unsigned int cpu_val;
unsigned int cpu_mask;
const char *arch_name;
const char *elf_name;
unsigned int elf_hwcap;
};
#else /* __KERNEL__ */
#include <asm/elf.h>
#warning "Please include asm/elf.h instead"
#endif /* __KERNEL__ */
#endif /* _ASM_C6X_PROCINFO_H */

View File

@ -0,0 +1 @@
/* dummy prom.h; here to make linux/of.h's #includes happy */

View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2004, 2006, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.34: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_PTRACE_H
#define _ASM_C6X_PTRACE_H
#define BKPT_OPCODE 0x56454314 /* illegal opcode */
#ifdef _BIG_ENDIAN
#define PT_LO(odd, even) odd
#define PT_HI(odd, even) even
#else
#define PT_LO(odd, even) even
#define PT_HI(odd, even) odd
#endif
#define PT_A4_ORG PT_LO(1, 0)
#define PT_TSR PT_HI(1, 0)
#define PT_ILC PT_LO(3, 2)
#define PT_RILC PT_HI(3, 2)
#define PT_CSR PT_LO(5, 4)
#define PT_PC PT_HI(5, 4)
#define PT_B16 PT_LO(7, 6)
#define PT_B17 PT_HI(7, 6)
#define PT_B18 PT_LO(9, 8)
#define PT_B19 PT_HI(9, 8)
#define PT_B20 PT_LO(11, 10)
#define PT_B21 PT_HI(11, 10)
#define PT_B22 PT_LO(13, 12)
#define PT_B23 PT_HI(13, 12)
#define PT_B24 PT_LO(15, 14)
#define PT_B25 PT_HI(15, 14)
#define PT_B26 PT_LO(17, 16)
#define PT_B27 PT_HI(17, 16)
#define PT_B28 PT_LO(19, 18)
#define PT_B29 PT_HI(19, 18)
#define PT_B30 PT_LO(21, 20)
#define PT_B31 PT_HI(21, 20)
#define PT_B0 PT_LO(23, 22)
#define PT_B1 PT_HI(23, 22)
#define PT_B2 PT_LO(25, 24)
#define PT_B3 PT_HI(25, 24)
#define PT_B4 PT_LO(27, 26)
#define PT_B5 PT_HI(27, 26)
#define PT_B6 PT_LO(29, 28)
#define PT_B7 PT_HI(29, 28)
#define PT_B8 PT_LO(31, 30)
#define PT_B9 PT_HI(31, 30)
#define PT_B10 PT_LO(33, 32)
#define PT_B11 PT_HI(33, 32)
#define PT_B12 PT_LO(35, 34)
#define PT_B13 PT_HI(35, 34)
#define PT_A16 PT_LO(37, 36)
#define PT_A17 PT_HI(37, 36)
#define PT_A18 PT_LO(39, 38)
#define PT_A19 PT_HI(39, 38)
#define PT_A20 PT_LO(41, 40)
#define PT_A21 PT_HI(41, 40)
#define PT_A22 PT_LO(43, 42)
#define PT_A23 PT_HI(43, 42)
#define PT_A24 PT_LO(45, 44)
#define PT_A25 PT_HI(45, 44)
#define PT_A26 PT_LO(47, 46)
#define PT_A27 PT_HI(47, 46)
#define PT_A28 PT_LO(49, 48)
#define PT_A29 PT_HI(49, 48)
#define PT_A30 PT_LO(51, 50)
#define PT_A31 PT_HI(51, 50)
#define PT_A0 PT_LO(53, 52)
#define PT_A1 PT_HI(53, 52)
#define PT_A2 PT_LO(55, 54)
#define PT_A3 PT_HI(55, 54)
#define PT_A4 PT_LO(57, 56)
#define PT_A5 PT_HI(57, 56)
#define PT_A6 PT_LO(59, 58)
#define PT_A7 PT_HI(59, 58)
#define PT_A8 PT_LO(61, 60)
#define PT_A9 PT_HI(61, 60)
#define PT_A10 PT_LO(63, 62)
#define PT_A11 PT_HI(63, 62)
#define PT_A12 PT_LO(65, 64)
#define PT_A13 PT_HI(65, 64)
#define PT_A14 PT_LO(67, 66)
#define PT_A15 PT_HI(67, 66)
#define PT_B14 PT_LO(69, 68)
#define PT_B15 PT_HI(69, 68)
#define NR_PTREGS 70
#define PT_DP PT_B14 /* Data Segment Pointer (B14) */
#define PT_SP PT_B15 /* Stack Pointer (B15) */
#ifndef __ASSEMBLY__
#ifdef _BIG_ENDIAN
#define REG_PAIR(odd, even) unsigned long odd; unsigned long even
#else
#define REG_PAIR(odd, even) unsigned long even; unsigned long odd
#endif
/*
* this struct defines the way the registers are stored on the
* stack during a system call. fields defined with REG_PAIR
* are saved and restored using double-word memory operations
* which means the word ordering of the pair depends on endianess.
*/
struct pt_regs {
REG_PAIR(tsr, orig_a4);
REG_PAIR(rilc, ilc);
REG_PAIR(pc, csr);
REG_PAIR(b17, b16);
REG_PAIR(b19, b18);
REG_PAIR(b21, b20);
REG_PAIR(b23, b22);
REG_PAIR(b25, b24);
REG_PAIR(b27, b26);
REG_PAIR(b29, b28);
REG_PAIR(b31, b30);
REG_PAIR(b1, b0);
REG_PAIR(b3, b2);
REG_PAIR(b5, b4);
REG_PAIR(b7, b6);
REG_PAIR(b9, b8);
REG_PAIR(b11, b10);
REG_PAIR(b13, b12);
REG_PAIR(a17, a16);
REG_PAIR(a19, a18);
REG_PAIR(a21, a20);
REG_PAIR(a23, a22);
REG_PAIR(a25, a24);
REG_PAIR(a27, a26);
REG_PAIR(a29, a28);
REG_PAIR(a31, a30);
REG_PAIR(a1, a0);
REG_PAIR(a3, a2);
REG_PAIR(a5, a4);
REG_PAIR(a7, a6);
REG_PAIR(a9, a8);
REG_PAIR(a11, a10);
REG_PAIR(a13, a12);
REG_PAIR(a15, a14);
REG_PAIR(sp, dp);
};
#ifdef __KERNEL__
#include <linux/linkage.h>
#define user_mode(regs) ((((regs)->tsr) & 0x40) != 0)
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
#define user_stack_pointer(regs) ((regs)->sp)
extern void show_regs(struct pt_regs *);
extern asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs);
extern asmlinkage void syscall_trace_exit(struct pt_regs *regs);
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif /* _ASM_C6X_PTRACE_H */

View File

@ -0,0 +1,12 @@
#ifndef _ASM_C6X_SECTIONS_H
#define _ASM_C6X_SECTIONS_H
#include <asm-generic/sections.h>
extern char _vectors_start[];
extern char _vectors_end[];
extern char _data_lma[];
extern char _fdt_start[], _fdt_end[];
#endif /* _ASM_C6X_SECTIONS_H */

View File

@ -0,0 +1,32 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_SETUP_H
#define _ASM_C6X_SETUP_H
#define COMMAND_LINE_SIZE 1024
#ifndef __ASSEMBLY__
extern char c6x_command_line[COMMAND_LINE_SIZE];
extern int c6x_add_memory(phys_addr_t start, unsigned long size);
extern unsigned long ram_start;
extern unsigned long ram_end;
extern int c6x_num_cores;
extern unsigned int c6x_silicon_rev;
extern unsigned int c6x_devstat;
extern unsigned char c6x_fuse_mac[6];
extern void machine_init(unsigned long dt_ptr);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_C6X_SETUP_H */

View File

@ -0,0 +1,80 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_SIGCONTEXT_H
#define _ASM_C6X_SIGCONTEXT_H
struct sigcontext {
unsigned long sc_mask; /* old sigmask */
unsigned long sc_sp; /* old user stack pointer */
unsigned long sc_a4;
unsigned long sc_b4;
unsigned long sc_a6;
unsigned long sc_b6;
unsigned long sc_a8;
unsigned long sc_b8;
unsigned long sc_a0;
unsigned long sc_a1;
unsigned long sc_a2;
unsigned long sc_a3;
unsigned long sc_a5;
unsigned long sc_a7;
unsigned long sc_a9;
unsigned long sc_b0;
unsigned long sc_b1;
unsigned long sc_b2;
unsigned long sc_b3;
unsigned long sc_b5;
unsigned long sc_b7;
unsigned long sc_b9;
unsigned long sc_a16;
unsigned long sc_a17;
unsigned long sc_a18;
unsigned long sc_a19;
unsigned long sc_a20;
unsigned long sc_a21;
unsigned long sc_a22;
unsigned long sc_a23;
unsigned long sc_a24;
unsigned long sc_a25;
unsigned long sc_a26;
unsigned long sc_a27;
unsigned long sc_a28;
unsigned long sc_a29;
unsigned long sc_a30;
unsigned long sc_a31;
unsigned long sc_b16;
unsigned long sc_b17;
unsigned long sc_b18;
unsigned long sc_b19;
unsigned long sc_b20;
unsigned long sc_b21;
unsigned long sc_b22;
unsigned long sc_b23;
unsigned long sc_b24;
unsigned long sc_b25;
unsigned long sc_b26;
unsigned long sc_b27;
unsigned long sc_b28;
unsigned long sc_b29;
unsigned long sc_b30;
unsigned long sc_b31;
unsigned long sc_csr;
unsigned long sc_pc;
};
#endif /* _ASM_C6X_SIGCONTEXT_H */

View File

@ -0,0 +1,17 @@
#ifndef _ASM_C6X_SIGNAL_H
#define _ASM_C6X_SIGNAL_H
#include <asm-generic/signal.h>
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
struct pt_regs;
extern asmlinkage int do_rt_sigreturn(struct pt_regs *regs);
extern asmlinkage void do_notify_resume(struct pt_regs *regs,
u32 thread_info_flags,
int syscall);
#endif
#endif /* _ASM_C6X_SIGNAL_H */

View File

@ -0,0 +1,35 @@
/*
* Miscellaneous SoC-specific hooks.
*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Author: Mark Salter <msalter@redhat.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef _ASM_C6X_SOC_H
#define _ASM_C6X_SOC_H
struct soc_ops {
/* Return active exception event or -1 if none */
int (*get_exception)(void);
/* Assert an event */
void (*assert_event)(unsigned int evt);
};
extern struct soc_ops soc_ops;
extern int soc_get_exception(void);
extern void soc_assert_event(unsigned int event);
extern int soc_mac_addr(unsigned int index, u8 *addr);
/*
* for mmio on SoC devices. regs are always same byte order as cpu.
*/
#define soc_readl(addr) __raw_readl(addr)
#define soc_writel(b, addr) __raw_writel((b), (addr))
#endif /* _ASM_C6X_SOC_H */

View File

@ -0,0 +1,21 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_STRING_H
#define _ASM_C6X_STRING_H
#include <asm/page.h>
#include <linux/linkage.h>
asmlinkage extern void *memcpy(void *to, const void *from, size_t n);
#define __HAVE_ARCH_MEMCPY
#endif /* _ASM_C6X_STRING_H */

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_SWAB_H
#define _ASM_C6X_SWAB_H
static inline __attribute_const__ __u16 __c6x_swab16(__u16 val)
{
asm("swap4 .l1 %0,%0\n" : "+a"(val));
return val;
}
static inline __attribute_const__ __u32 __c6x_swab32(__u32 val)
{
asm("swap4 .l1 %0,%0\n"
"swap2 .l1 %0,%0\n"
: "+a"(val));
return val;
}
static inline __attribute_const__ __u64 __c6x_swab64(__u64 val)
{
asm(" swap2 .s1 %p0,%P0\n"
"|| swap2 .l1 %P0,%p0\n"
" swap4 .l1 %p0,%p0\n"
" swap4 .l1 %P0,%P0\n"
: "+a"(val));
return val;
}
static inline __attribute_const__ __u32 __c6x_swahw32(__u32 val)
{
asm("swap2 .l1 %0,%0\n" : "+a"(val));
return val;
}
static inline __attribute_const__ __u32 __c6x_swahb32(__u32 val)
{
asm("swap4 .l1 %0,%0\n" : "+a"(val));
return val;
}
#define __arch_swab16 __c6x_swab16
#define __arch_swab32 __c6x_swab32
#define __arch_swab64 __c6x_swab64
#define __arch_swahw32 __c6x_swahw32
#define __arch_swahb32 __c6x_swahb32
#endif /* _ASM_C6X_SWAB_H */

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __ASM_C6X_SYSCALL_H
#define __ASM_C6X_SYSCALL_H
#include <linux/err.h>
#include <linux/sched.h>
static inline int syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
return regs->b0;
}
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
/* do nothing */
}
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
return IS_ERR_VALUE(regs->a4) ? regs->a4 : 0;
}
static inline long syscall_get_return_value(struct task_struct *task,
struct pt_regs *regs)
{
return regs->a4;
}
static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
regs->a4 = error ?: val;
}
static inline void syscall_get_arguments(struct task_struct *task,
struct pt_regs *regs, unsigned int i,
unsigned int n, unsigned long *args)
{
switch (i) {
case 0:
if (!n--)
break;
*args++ = regs->a4;
case 1:
if (!n--)
break;
*args++ = regs->b4;
case 2:
if (!n--)
break;
*args++ = regs->a6;
case 3:
if (!n--)
break;
*args++ = regs->b6;
case 4:
if (!n--)
break;
*args++ = regs->a8;
case 5:
if (!n--)
break;
*args++ = regs->b8;
case 6:
if (!n--)
break;
default:
BUG();
}
}
static inline void syscall_set_arguments(struct task_struct *task,
struct pt_regs *regs,
unsigned int i, unsigned int n,
const unsigned long *args)
{
switch (i) {
case 0:
if (!n--)
break;
regs->a4 = *args++;
case 1:
if (!n--)
break;
regs->b4 = *args++;
case 2:
if (!n--)
break;
regs->a6 = *args++;
case 3:
if (!n--)
break;
regs->b6 = *args++;
case 4:
if (!n--)
break;
regs->a8 = *args++;
case 5:
if (!n--)
break;
regs->a9 = *args++;
case 6:
if (!n)
break;
default:
BUG();
}
}
#endif /* __ASM_C6X_SYSCALLS_H */

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
#ifndef __ASM_C6X_SYSCALLS_H
#define __ASM_C6X_SYSCALLS_H
#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/types.h>
/* The array of function pointers for syscalls. */
extern void *sys_call_table[];
/* The following are trampolines in entry.S to handle 64-bit arguments */
extern long sys_pread_c6x(unsigned int fd, char __user *buf,
size_t count, off_t pos_low, off_t pos_high);
extern long sys_pwrite_c6x(unsigned int fd, const char __user *buf,
size_t count, off_t pos_low, off_t pos_high);
extern long sys_truncate64_c6x(const char __user *path,
off_t length_low, off_t length_high);
extern long sys_ftruncate64_c6x(unsigned int fd,
off_t length_low, off_t length_high);
extern long sys_fadvise64_c6x(int fd, u32 offset_lo, u32 offset_hi,
u32 len, int advice);
extern long sys_fadvise64_64_c6x(int fd, u32 offset_lo, u32 offset_hi,
u32 len_lo, u32 len_hi, int advice);
extern long sys_fallocate_c6x(int fd, int mode,
u32 offset_lo, u32 offset_hi,
u32 len_lo, u32 len_hi);
extern int sys_cache_sync(unsigned long s, unsigned long e);
struct pt_regs;
extern asmlinkage long sys_c6x_clone(struct pt_regs *regs);
extern asmlinkage long sys_c6x_execve(const char __user *name,
const char __user *const __user *argv,
const char __user *const __user *envp,
struct pt_regs *regs);
#include <asm-generic/syscalls.h>
#endif /* __ASM_C6X_SYSCALLS_H */

View File

@ -0,0 +1,168 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_SYSTEM_H
#define _ASM_C6X_SYSTEM_H
#include <linux/linkage.h>
#include <linux/irqflags.h>
#define prepare_to_switch() do { } while (0)
struct task_struct;
struct thread_struct;
asmlinkage void *__switch_to(struct thread_struct *prev,
struct thread_struct *next,
struct task_struct *tsk);
#define switch_to(prev, next, last) \
do { \
current->thread.wchan = (u_long) __builtin_return_address(0); \
(last) = __switch_to(&(prev)->thread, \
&(next)->thread, (prev)); \
mb(); \
current->thread.wchan = 0; \
} while (0)
/* Reset the board */
#define HARD_RESET_NOW()
#define get_creg(reg) \
({ unsigned int __x; \
asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; })
#define set_creg(reg, v) \
do { unsigned int __x = (unsigned int)(v); \
asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \
} while (0)
#define or_creg(reg, n) \
do { unsigned __x, __n = (unsigned)(n); \
asm volatile ("mvc .s2 " #reg ",%0\n" \
"or .l2 %1,%0,%0\n" \
"mvc .s2 %0," #reg "\n" \
"nop\n" \
: "=&b"(__x) : "b"(__n)); \
} while (0)
#define and_creg(reg, n) \
do { unsigned __x, __n = (unsigned)(n); \
asm volatile ("mvc .s2 " #reg ",%0\n" \
"and .l2 %1,%0,%0\n" \
"mvc .s2 %0," #reg "\n" \
"nop\n" \
: "=&b"(__x) : "b"(__n)); \
} while (0)
#define get_coreid() (get_creg(DNUM) & 0xff)
/* Set/get IST */
#define set_ist(x) set_creg(ISTP, x)
#define get_ist() get_creg(ISTP)
/*
* Exception management
*/
asmlinkage void enable_exception(void);
#define disable_exception()
#define get_except_type() get_creg(EFR)
#define ack_exception(type) set_creg(ECR, 1 << (type))
#define get_iexcept() get_creg(IERR)
#define set_iexcept(mask) set_creg(IERR, (mask))
/*
* Misc. functions
*/
#define nop() asm("NOP\n");
#define mb() barrier()
#define rmb() barrier()
#define wmb() barrier()
#define set_mb(var, value) do { var = value; mb(); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while (0)
#define xchg(ptr, x) \
((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
sizeof(*(ptr))))
#define tas(ptr) xchg((ptr), 1)
unsigned int _lmbd(unsigned int, unsigned int);
unsigned int _bitr(unsigned int);
struct __xchg_dummy { unsigned int a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
{
unsigned int tmp;
unsigned long flags;
local_irq_save(flags);
switch (size) {
case 1:
tmp = 0;
tmp = *((unsigned char *) ptr);
*((unsigned char *) ptr) = (unsigned char) x;
break;
case 2:
tmp = 0;
tmp = *((unsigned short *) ptr);
*((unsigned short *) ptr) = x;
break;
case 4:
tmp = 0;
tmp = *((unsigned int *) ptr);
*((unsigned int *) ptr) = x;
break;
}
local_irq_restore(flags);
return tmp;
}
#include <asm-generic/cmpxchg-local.h>
/*
* cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
* them available.
*/
#define cmpxchg_local(ptr, o, n) \
((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
(unsigned long)(o), \
(unsigned long)(n), \
sizeof(*(ptr))))
#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
#include <asm-generic/cmpxchg.h>
#define _extu(x, s, e) \
({ unsigned int __x; \
asm volatile ("extu .S2 %3,%1,%2,%0\n" : \
"=b"(__x) : "n"(s), "n"(e), "b"(x)); \
__x; })
extern unsigned int c6x_core_freq;
struct pt_regs;
extern void die(char *str, struct pt_regs *fp, int nr);
extern asmlinkage int process_exception(struct pt_regs *regs);
extern void time_init(void);
extern void free_initmem(void);
extern void (*c6x_restart)(void);
extern void (*c6x_halt)(void);
#endif /* _ASM_C6X_SYSTEM_H */

View File

@ -0,0 +1,121 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.3x: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_THREAD_INFO_H
#define _ASM_C6X_THREAD_INFO_H
#ifdef __KERNEL__
#include <asm/page.h>
#ifdef CONFIG_4KSTACKS
#define THREAD_SIZE 4096
#define THREAD_SHIFT 12
#define THREAD_ORDER 0
#else
#define THREAD_SIZE 8192
#define THREAD_SHIFT 13
#define THREAD_ORDER 1
#endif
#define THREAD_START_SP (THREAD_SIZE - 8)
#ifndef __ASSEMBLY__
typedef struct {
unsigned long seg;
} mm_segment_t;
/*
* low level task data.
*/
struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
int cpu; /* cpu we're on */
int preempt_count; /* 0 = preemptable, <0 = BUG */
mm_segment_t addr_limit; /* thread address space */
struct restart_block restart_block;
};
/*
* macros/functions for gaining access to the thread information structure
*
* preempt_count needs to be 1 initially, until the scheduler is functional.
*/
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
.exec_domain = &default_exec_domain, \
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
.restart_block = { \
.fn = do_no_restart_syscall, \
}, \
}
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
/* get the thread information struct of current task */
static inline __attribute__((const))
struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
asm volatile (" clr .s2 B15,0,%1,%0\n"
: "=b" (ti)
: "Iu5" (THREAD_SHIFT - 1));
return ti;
}
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
/* thread information allocation */
#ifdef CONFIG_DEBUG_STACK_USAGE
#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
#else
#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK)
#endif
#define alloc_thread_info_node(tsk, node) \
((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER))
#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER)
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
#endif /* __ASSEMBLY__ */
#define PREEMPT_ACTIVE 0x10000000
/*
* thread information flag bit numbers
* - pending work-to-be-done flags are in LSW
* - other flags in MSW
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
#define TIF_POLLING_NRFLAG 16 /* true if polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17 /* OOM killer killed process */
#define TIF_WORK_MASK 0x00007FFE /* work on irq/exception return */
#define TIF_ALLWORK_MASK 0x00007FFF /* work on any return to u-space */
#endif /* __KERNEL__ */
#endif /* _ASM_C6X_THREAD_INFO_H */

View File

@ -0,0 +1,6 @@
#ifndef _C6X_TIMER64_H
#define _C6X_TIMER64_H
extern void __init timer64_init(void);
#endif /* _C6X_TIMER64_H */

View File

@ -0,0 +1,33 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Modified for 2.6.34: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_TIMEX_H
#define _ASM_C6X_TIMEX_H
#define CLOCK_TICK_RATE ((1000 * 1000000UL) / 6)
/* 64-bit timestamp */
typedef unsigned long long cycles_t;
static inline cycles_t get_cycles(void)
{
unsigned l, h;
asm volatile (" dint\n"
" mvc .s2 TSCL,%0\n"
" mvc .s2 TSCH,%1\n"
" rint\n"
: "=b"(l), "=b"(h));
return ((cycles_t)h << 32) | l;
}
#endif /* _ASM_C6X_TIMEX_H */

View File

@ -0,0 +1,8 @@
#ifndef _ASM_C6X_TLB_H
#define _ASM_C6X_TLB_H
#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
#include <asm-generic/tlb.h>
#endif /* _ASM_C6X_TLB_H */

View File

@ -0,0 +1,36 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_TRAPS_H
#define _ASM_C6X_TRAPS_H
#define EXCEPT_TYPE_NXF 31 /* NMI */
#define EXCEPT_TYPE_EXC 30 /* external exception */
#define EXCEPT_TYPE_IXF 1 /* internal exception */
#define EXCEPT_TYPE_SXF 0 /* software exception */
#define EXCEPT_CAUSE_LBX (1 << 7) /* loop buffer exception */
#define EXCEPT_CAUSE_PRX (1 << 6) /* privilege exception */
#define EXCEPT_CAUSE_RAX (1 << 5) /* resource access exception */
#define EXCEPT_CAUSE_RCX (1 << 4) /* resource conflict exception */
#define EXCEPT_CAUSE_OPX (1 << 3) /* opcode exception */
#define EXCEPT_CAUSE_EPX (1 << 2) /* execute packet exception */
#define EXCEPT_CAUSE_FPX (1 << 1) /* fetch packet exception */
#define EXCEPT_CAUSE_IFX (1 << 0) /* instruction fetch exception */
struct exception_info {
char *kernel_str;
int signo;
int code;
};
extern int (*c6x_nmi_handler)(struct pt_regs *regs);
#endif /* _ASM_C6X_TRAPS_H */

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_UACCESS_H
#define _ASM_C6X_UACCESS_H
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/string.h>
#ifdef CONFIG_ACCESS_CHECK
#define __access_ok _access_ok
#endif
/*
* __copy_from_user/copy_to_user are based on ones in asm-generic/uaccess.h
*
* C6X supports unaligned 32 and 64 bit loads and stores.
*/
static inline __must_check long __copy_from_user(void *to,
const void __user *from, unsigned long n)
{
u32 tmp32;
u64 tmp64;
if (__builtin_constant_p(n)) {
switch (n) {
case 1:
*(u8 *)to = *(u8 __force *)from;
return 0;
case 4:
asm volatile ("ldnw .d1t1 *%2,%0\n"
"nop 4\n"
"stnw .d1t1 %0,*%1\n"
: "=&a"(tmp32)
: "A"(to), "a"(from)
: "memory");
return 0;
case 8:
asm volatile ("ldndw .d1t1 *%2,%0\n"
"nop 4\n"
"stndw .d1t1 %0,*%1\n"
: "=&a"(tmp64)
: "a"(to), "a"(from)
: "memory");
return 0;
default:
break;
}
}
memcpy(to, (const void __force *)from, n);
return 0;
}
static inline __must_check long __copy_to_user(void __user *to,
const void *from, unsigned long n)
{
u32 tmp32;
u64 tmp64;
if (__builtin_constant_p(n)) {
switch (n) {
case 1:
*(u8 __force *)to = *(u8 *)from;
return 0;
case 4:
asm volatile ("ldnw .d1t1 *%2,%0\n"
"nop 4\n"
"stnw .d1t1 %0,*%1\n"
: "=&a"(tmp32)
: "a"(to), "a"(from)
: "memory");
return 0;
case 8:
asm volatile ("ldndw .d1t1 *%2,%0\n"
"nop 4\n"
"stndw .d1t1 %0,*%1\n"
: "=&a"(tmp64)
: "a"(to), "a"(from)
: "memory");
return 0;
default:
break;
}
}
memcpy((void __force *)to, from, n);
return 0;
}
#define __copy_to_user __copy_to_user
#define __copy_from_user __copy_from_user
extern int _access_ok(unsigned long addr, unsigned long size);
#ifdef CONFIG_ACCESS_CHECK
#define __access_ok _access_ok
#endif
#include <asm-generic/uaccess.h>
#endif /* _ASM_C6X_UACCESS_H */

View File

@ -0,0 +1,170 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
* Rewritten for 2.6.3x: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_UNALIGNED_H
#define _ASM_C6X_UNALIGNED_H
#include <linux/swab.h>
/*
* The C64x+ can do unaligned word and dword accesses in hardware
* using special load/store instructions.
*/
static inline u16 get_unaligned_le16(const void *p)
{
const u8 *_p = p;
return _p[0] | _p[1] << 8;
}
static inline u16 get_unaligned_be16(const void *p)
{
const u8 *_p = p;
return _p[0] << 8 | _p[1];
}
static inline void put_unaligned_le16(u16 val, void *p)
{
u8 *_p = p;
_p[0] = val;
_p[1] = val >> 8;
}
static inline void put_unaligned_be16(u16 val, void *p)
{
u8 *_p = p;
_p[0] = val >> 8;
_p[1] = val;
}
static inline u32 get_unaligned32(const void *p)
{
u32 val = (u32) p;
asm (" ldnw .d1t1 *%0,%0\n"
" nop 4\n"
: "+a"(val));
return val;
}
static inline void put_unaligned32(u32 val, void *p)
{
asm volatile (" stnw .d2t1 %0,*%1\n"
: : "a"(val), "b"(p) : "memory");
}
static inline u64 get_unaligned64(const void *p)
{
u64 val;
asm volatile (" ldndw .d1t1 *%1,%0\n"
" nop 4\n"
: "=a"(val) : "a"(p));
return val;
}
static inline void put_unaligned64(u64 val, const void *p)
{
asm volatile (" stndw .d2t1 %0,*%1\n"
: : "a"(val), "b"(p) : "memory");
}
#ifdef CONFIG_CPU_BIG_ENDIAN
#define get_unaligned_le32(p) __swab32(get_unaligned32(p))
#define get_unaligned_le64(p) __swab64(get_unaligned64(p))
#define get_unaligned_be32(p) get_unaligned32(p)
#define get_unaligned_be64(p) get_unaligned64(p)
#define put_unaligned_le32(v, p) put_unaligned32(__swab32(v), (p))
#define put_unaligned_le64(v, p) put_unaligned64(__swab64(v), (p))
#define put_unaligned_be32(v, p) put_unaligned32((v), (p))
#define put_unaligned_be64(v, p) put_unaligned64((v), (p))
#define get_unaligned __get_unaligned_be
#define put_unaligned __put_unaligned_be
#else
#define get_unaligned_le32(p) get_unaligned32(p)
#define get_unaligned_le64(p) get_unaligned64(p)
#define get_unaligned_be32(p) __swab32(get_unaligned32(p))
#define get_unaligned_be64(p) __swab64(get_unaligned64(p))
#define put_unaligned_le32(v, p) put_unaligned32((v), (p))
#define put_unaligned_le64(v, p) put_unaligned64((v), (p))
#define put_unaligned_be32(v, p) put_unaligned32(__swab32(v), (p))
#define put_unaligned_be64(v, p) put_unaligned64(__swab64(v), (p))
#define get_unaligned __get_unaligned_le
#define put_unaligned __put_unaligned_le
#endif
/*
* Cause a link-time error if we try an unaligned access other than
* 1,2,4 or 8 bytes long
*/
extern int __bad_unaligned_access_size(void);
#define __get_unaligned_le(ptr) (typeof(*(ptr)))({ \
sizeof(*(ptr)) == 1 ? *(ptr) : \
(sizeof(*(ptr)) == 2 ? get_unaligned_le16((ptr)) : \
(sizeof(*(ptr)) == 4 ? get_unaligned_le32((ptr)) : \
(sizeof(*(ptr)) == 8 ? get_unaligned_le64((ptr)) : \
__bad_unaligned_access_size()))); \
})
#define __get_unaligned_be(ptr) (__force typeof(*(ptr)))({ \
sizeof(*(ptr)) == 1 ? *(ptr) : \
(sizeof(*(ptr)) == 2 ? get_unaligned_be16((ptr)) : \
(sizeof(*(ptr)) == 4 ? get_unaligned_be32((ptr)) : \
(sizeof(*(ptr)) == 8 ? get_unaligned_be64((ptr)) : \
__bad_unaligned_access_size()))); \
})
#define __put_unaligned_le(val, ptr) ({ \
void *__gu_p = (ptr); \
switch (sizeof(*(ptr))) { \
case 1: \
*(u8 *)__gu_p = (__force u8)(val); \
break; \
case 2: \
put_unaligned_le16((__force u16)(val), __gu_p); \
break; \
case 4: \
put_unaligned_le32((__force u32)(val), __gu_p); \
break; \
case 8: \
put_unaligned_le64((__force u64)(val), __gu_p); \
break; \
default: \
__bad_unaligned_access_size(); \
break; \
} \
(void)0; })
#define __put_unaligned_be(val, ptr) ({ \
void *__gu_p = (ptr); \
switch (sizeof(*(ptr))) { \
case 1: \
*(u8 *)__gu_p = (__force u8)(val); \
break; \
case 2: \
put_unaligned_be16((__force u16)(val), __gu_p); \
break; \
case 4: \
put_unaligned_be32((__force u32)(val), __gu_p); \
break; \
case 8: \
put_unaligned_be64((__force u64)(val), __gu_p); \
break; \
default: \
__bad_unaligned_access_size(); \
break; \
} \
(void)0; })
#endif /* _ASM_C6X_UNALIGNED_H */

View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* Based on arch/tile version.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
#if !defined(_ASM_C6X_UNISTD_H) || defined(__SYSCALL)
#define _ASM_C6X_UNISTD_H
/* Use the standard ABI for syscalls. */
#include <asm-generic/unistd.h>
/* C6X-specific syscalls. */
#define __NR_cache_sync (__NR_arch_specific_syscall + 0)
__SYSCALL(__NR_cache_sync, sys_cache_sync)
#endif /* _ASM_C6X_UNISTD_H */

12
arch/c6x/kernel/Makefile Normal file
View File

@ -0,0 +1,12 @@
#
# Makefile for arch/c6x/kernel/
#
extra-y := head.o vmlinux.lds
obj-y := process.o traps.o irq.o signal.o ptrace.o
obj-y += setup.o sys_c6x.o time.o devicetree.o
obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o
obj-y += soc.o dma.o
obj-$(CONFIG_MODULES) += module.o

View File

@ -0,0 +1,123 @@
/*
* Generate definitions needed by assembly language modules.
* This code generates raw asm output which is post-processed
* to extract and format the required data.
*/
#include <linux/sched.h>
#include <linux/thread_info.h>
#include <asm/procinfo.h>
#include <linux/kbuild.h>
#include <linux/unistd.h>
void foo(void)
{
OFFSET(REGS_A16, pt_regs, a16);
OFFSET(REGS_A17, pt_regs, a17);
OFFSET(REGS_A18, pt_regs, a18);
OFFSET(REGS_A19, pt_regs, a19);
OFFSET(REGS_A20, pt_regs, a20);
OFFSET(REGS_A21, pt_regs, a21);
OFFSET(REGS_A22, pt_regs, a22);
OFFSET(REGS_A23, pt_regs, a23);
OFFSET(REGS_A24, pt_regs, a24);
OFFSET(REGS_A25, pt_regs, a25);
OFFSET(REGS_A26, pt_regs, a26);
OFFSET(REGS_A27, pt_regs, a27);
OFFSET(REGS_A28, pt_regs, a28);
OFFSET(REGS_A29, pt_regs, a29);
OFFSET(REGS_A30, pt_regs, a30);
OFFSET(REGS_A31, pt_regs, a31);
OFFSET(REGS_B16, pt_regs, b16);
OFFSET(REGS_B17, pt_regs, b17);
OFFSET(REGS_B18, pt_regs, b18);
OFFSET(REGS_B19, pt_regs, b19);
OFFSET(REGS_B20, pt_regs, b20);
OFFSET(REGS_B21, pt_regs, b21);
OFFSET(REGS_B22, pt_regs, b22);
OFFSET(REGS_B23, pt_regs, b23);
OFFSET(REGS_B24, pt_regs, b24);
OFFSET(REGS_B25, pt_regs, b25);
OFFSET(REGS_B26, pt_regs, b26);
OFFSET(REGS_B27, pt_regs, b27);
OFFSET(REGS_B28, pt_regs, b28);
OFFSET(REGS_B29, pt_regs, b29);
OFFSET(REGS_B30, pt_regs, b30);
OFFSET(REGS_B31, pt_regs, b31);
OFFSET(REGS_A0, pt_regs, a0);
OFFSET(REGS_A1, pt_regs, a1);
OFFSET(REGS_A2, pt_regs, a2);
OFFSET(REGS_A3, pt_regs, a3);
OFFSET(REGS_A4, pt_regs, a4);
OFFSET(REGS_A5, pt_regs, a5);
OFFSET(REGS_A6, pt_regs, a6);
OFFSET(REGS_A7, pt_regs, a7);
OFFSET(REGS_A8, pt_regs, a8);
OFFSET(REGS_A9, pt_regs, a9);
OFFSET(REGS_A10, pt_regs, a10);
OFFSET(REGS_A11, pt_regs, a11);
OFFSET(REGS_A12, pt_regs, a12);
OFFSET(REGS_A13, pt_regs, a13);
OFFSET(REGS_A14, pt_regs, a14);
OFFSET(REGS_A15, pt_regs, a15);
OFFSET(REGS_B0, pt_regs, b0);
OFFSET(REGS_B1, pt_regs, b1);
OFFSET(REGS_B2, pt_regs, b2);
OFFSET(REGS_B3, pt_regs, b3);
OFFSET(REGS_B4, pt_regs, b4);
OFFSET(REGS_B5, pt_regs, b5);
OFFSET(REGS_B6, pt_regs, b6);
OFFSET(REGS_B7, pt_regs, b7);
OFFSET(REGS_B8, pt_regs, b8);
OFFSET(REGS_B9, pt_regs, b9);
OFFSET(REGS_B10, pt_regs, b10);
OFFSET(REGS_B11, pt_regs, b11);
OFFSET(REGS_B12, pt_regs, b12);
OFFSET(REGS_B13, pt_regs, b13);
OFFSET(REGS_DP, pt_regs, dp);
OFFSET(REGS_SP, pt_regs, sp);
OFFSET(REGS_TSR, pt_regs, tsr);
OFFSET(REGS_ORIG_A4, pt_regs, orig_a4);
DEFINE(REGS__END, sizeof(struct pt_regs));
BLANK();
OFFSET(THREAD_PC, thread_struct, pc);
OFFSET(THREAD_B15_14, thread_struct, b15_14);
OFFSET(THREAD_A15_14, thread_struct, a15_14);
OFFSET(THREAD_B13_12, thread_struct, b13_12);
OFFSET(THREAD_A13_12, thread_struct, a13_12);
OFFSET(THREAD_B11_10, thread_struct, b11_10);
OFFSET(THREAD_A11_10, thread_struct, a11_10);
OFFSET(THREAD_RICL_ICL, thread_struct, ricl_icl);
BLANK();
OFFSET(TASK_STATE, task_struct, state);
BLANK();
OFFSET(THREAD_INFO_FLAGS, thread_info, flags);
OFFSET(THREAD_INFO_PREEMPT_COUNT, thread_info, preempt_count);
BLANK();
/* These would be unneccessary if we ran asm files
* through the preprocessor.
*/
DEFINE(KTHREAD_SIZE, THREAD_SIZE);
DEFINE(KTHREAD_SHIFT, THREAD_SHIFT);
DEFINE(KTHREAD_START_SP, THREAD_START_SP);
DEFINE(ENOSYS_, ENOSYS);
DEFINE(NR_SYSCALLS_, __NR_syscalls);
DEFINE(_TIF_SYSCALL_TRACE, (1<<TIF_SYSCALL_TRACE));
DEFINE(_TIF_NOTIFY_RESUME, (1<<TIF_NOTIFY_RESUME));
DEFINE(_TIF_SIGPENDING, (1<<TIF_SIGPENDING));
DEFINE(_TIF_NEED_RESCHED, (1<<TIF_NEED_RESCHED));
DEFINE(_TIF_POLLING_NRFLAG, (1<<TIF_POLLING_NRFLAG));
DEFINE(_TIF_ALLWORK_MASK, TIF_ALLWORK_MASK);
DEFINE(_TIF_WORK_MASK, TIF_WORK_MASK);
}

View File

@ -0,0 +1,66 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <asm/checksum.h>
#include <linux/io.h>
/*
* libgcc functions - used internally by the compiler...
*/
extern int __c6xabi_divi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_divi);
extern unsigned __c6xabi_divu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_divu);
extern int __c6xabi_remi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_remi);
extern unsigned __c6xabi_remu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_remu);
extern int __c6xabi_divremi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_divremi);
extern unsigned __c6xabi_divremu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_divremu);
extern unsigned long long __c6xabi_mpyll(unsigned long long src1,
unsigned long long src2);
EXPORT_SYMBOL(__c6xabi_mpyll);
extern long long __c6xabi_negll(long long src);
EXPORT_SYMBOL(__c6xabi_negll);
extern unsigned long long __c6xabi_llshl(unsigned long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshl);
extern long long __c6xabi_llshr(long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshr);
extern unsigned long long __c6xabi_llshru(unsigned long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshru);
extern void __c6xabi_strasgi(int *dst, const int *src, unsigned cnt);
EXPORT_SYMBOL(__c6xabi_strasgi);
extern void __c6xabi_push_rts(void);
EXPORT_SYMBOL(__c6xabi_push_rts);
extern void __c6xabi_pop_rts(void);
EXPORT_SYMBOL(__c6xabi_pop_rts);
extern void __c6xabi_strasgi_64plus(int *dst, const int *src, unsigned cnt);
EXPORT_SYMBOL(__c6xabi_strasgi_64plus);
/* lib functions */
EXPORT_SYMBOL(memcpy);

View File

@ -0,0 +1,53 @@
/*
* Architecture specific OF callbacks.
*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
void __init early_init_devtree(void *params)
{
/* Setup flat device-tree pointer */
initial_boot_params = params;
/* Retrieve various informations from the /chosen node of the
* device-tree, including the platform type, initrd location and
* size and more ...
*/
of_scan_flat_dt(early_init_dt_scan_chosen, c6x_command_line);
/* Scan memory nodes and rebuild MEMBLOCKs */
of_scan_flat_dt(early_init_dt_scan_root, NULL);
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init early_init_dt_setup_initrd_arch(unsigned long start,
unsigned long end)
{
initrd_start = (unsigned long)__va(start);
initrd_end = (unsigned long)__va(end);
initrd_below_start_ok = 1;
}
#endif
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
c6x_add_memory(base, size);
}
void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
return __va(memblock_alloc(size, align));
}

153
arch/c6x/kernel/dma.c Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/scatterlist.h>
#include <asm/cacheflush.h>
static void c6x_dma_sync(dma_addr_t handle, size_t size,
enum dma_data_direction dir)
{
unsigned long paddr = handle;
BUG_ON(!valid_dma_direction(dir));
switch (dir) {
case DMA_FROM_DEVICE:
L2_cache_block_invalidate(paddr, paddr + size);
break;
case DMA_TO_DEVICE:
L2_cache_block_writeback(paddr, paddr + size);
break;
case DMA_BIDIRECTIONAL:
L2_cache_block_writeback_invalidate(paddr, paddr + size);
break;
default:
break;
}
}
dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction dir)
{
dma_addr_t addr = virt_to_phys(ptr);
c6x_dma_sync(addr, size, dir);
debug_dma_map_page(dev, virt_to_page(ptr),
(unsigned long)ptr & ~PAGE_MASK, size,
dir, addr, true);
return addr;
}
EXPORT_SYMBOL(dma_map_single);
void dma_unmap_single(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
c6x_dma_sync(handle, size, dir);
debug_dma_unmap_page(dev, handle, size, dir, true);
}
EXPORT_SYMBOL(dma_unmap_single);
int dma_map_sg(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
for_each_sg(sglist, sg, nents, i)
sg->dma_address = dma_map_single(dev, sg_virt(sg), sg->length,
dir);
debug_dma_map_sg(dev, sglist, nents, nents, dir);
return nents;
}
EXPORT_SYMBOL(dma_map_sg);
void dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
for_each_sg(sglist, sg, nents, i)
dma_unmap_single(dev, sg_dma_address(sg), sg->length, dir);
debug_dma_unmap_sg(dev, sglist, nents, dir);
}
EXPORT_SYMBOL(dma_unmap_sg);
void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
c6x_dma_sync(handle, size, dir);
debug_dma_sync_single_for_cpu(dev, handle, size, dir);
}
EXPORT_SYMBOL(dma_sync_single_for_cpu);
void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
c6x_dma_sync(handle, size, dir);
debug_dma_sync_single_for_device(dev, handle, size, dir);
}
EXPORT_SYMBOL(dma_sync_single_for_device);
void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
for_each_sg(sglist, sg, nents, i)
dma_sync_single_for_cpu(dev, sg_dma_address(sg),
sg->length, dir);
debug_dma_sync_sg_for_cpu(dev, sglist, nents, dir);
}
EXPORT_SYMBOL(dma_sync_sg_for_cpu);
void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
int nents, enum dma_data_direction dir)
{
struct scatterlist *sg;
int i;
for_each_sg(sglist, sg, nents, i)
dma_sync_single_for_device(dev, sg_dma_address(sg),
sg->length, dir);
debug_dma_sync_sg_for_device(dev, sglist, nents, dir);
}
EXPORT_SYMBOL(dma_sync_sg_for_device);
/* Number of entries preallocated for DMA-API debugging */
#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
static int __init dma_init(void)
{
dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
return 0;
}
fs_initcall(dma_init);

803
arch/c6x/kernel/entry.S Normal file
View File

@ -0,0 +1,803 @@
;
; Port on Texas Instruments TMS320C6x architecture
;
; Copyright (C) 2004-2011 Texas Instruments Incorporated
; Author: Aurelien Jacquiot (aurelien.jacquiot@virtuallogix.com)
; Updated for 2.6.34: Mark Salter <msalter@redhat.com>
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as
; published by the Free Software Foundation.
;
#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
#include <asm/unistd.h>
#include <asm/errno.h>
; Registers naming
#define DP B14
#define SP B15
#ifndef CONFIG_PREEMPT
#define resume_kernel restore_all
#endif
.altmacro
.macro MASK_INT reg
MVC .S2 CSR,reg
CLR .S2 reg,0,0,reg
MVC .S2 reg,CSR
.endm
.macro UNMASK_INT reg
MVC .S2 CSR,reg
SET .S2 reg,0,0,reg
MVC .S2 reg,CSR
.endm
.macro GET_THREAD_INFO reg
SHR .S1X SP,THREAD_SHIFT,reg
SHL .S1 reg,THREAD_SHIFT,reg
.endm
;;
;; This defines the normal kernel pt_regs layout.
;;
.macro SAVE_ALL __rp __tsr
STW .D2T2 B0,*SP--[2] ; save original B0
MVKL .S2 current_ksp,B0
MVKH .S2 current_ksp,B0
LDW .D2T2 *B0,B1 ; KSP
NOP 3
STW .D2T2 B1,*+SP[1] ; save original B1
XOR .D2 SP,B1,B0 ; (SP ^ KSP)
LDW .D2T2 *+SP[1],B1 ; restore B0/B1
LDW .D2T2 *++SP[2],B0
SHR .S2 B0,THREAD_SHIFT,B0 ; 0 if already using kstack
[B0] STDW .D2T2 SP:DP,*--B1[1] ; user: save user sp/dp kstack
[B0] MV .S2 B1,SP ; and switch to kstack
||[!B0] STDW .D2T2 SP:DP,*--SP[1] ; kernel: save on current stack
SUBAW .D2 SP,2,SP
ADD .D1X SP,-8,A15
|| STDW .D2T1 A15:A14,*SP--[16] ; save A15:A14
STDW .D2T2 B13:B12,*SP--[1]
|| STDW .D1T1 A13:A12,*A15--[1]
|| MVC .S2 __rp,B13
STDW .D2T2 B11:B10,*SP--[1]
|| STDW .D1T1 A11:A10,*A15--[1]
|| MVC .S2 CSR,B12
STDW .D2T2 B9:B8,*SP--[1]
|| STDW .D1T1 A9:A8,*A15--[1]
|| MVC .S2 RILC,B11
STDW .D2T2 B7:B6,*SP--[1]
|| STDW .D1T1 A7:A6,*A15--[1]
|| MVC .S2 ILC,B10
STDW .D2T2 B5:B4,*SP--[1]
|| STDW .D1T1 A5:A4,*A15--[1]
STDW .D2T2 B3:B2,*SP--[1]
|| STDW .D1T1 A3:A2,*A15--[1]
|| MVC .S2 __tsr,B5
STDW .D2T2 B1:B0,*SP--[1]
|| STDW .D1T1 A1:A0,*A15--[1]
|| MV .S1X B5,A5
STDW .D2T2 B31:B30,*SP--[1]
|| STDW .D1T1 A31:A30,*A15--[1]
STDW .D2T2 B29:B28,*SP--[1]
|| STDW .D1T1 A29:A28,*A15--[1]
STDW .D2T2 B27:B26,*SP--[1]
|| STDW .D1T1 A27:A26,*A15--[1]
STDW .D2T2 B25:B24,*SP--[1]
|| STDW .D1T1 A25:A24,*A15--[1]
STDW .D2T2 B23:B22,*SP--[1]
|| STDW .D1T1 A23:A22,*A15--[1]
STDW .D2T2 B21:B20,*SP--[1]
|| STDW .D1T1 A21:A20,*A15--[1]
STDW .D2T2 B19:B18,*SP--[1]
|| STDW .D1T1 A19:A18,*A15--[1]
STDW .D2T2 B17:B16,*SP--[1]
|| STDW .D1T1 A17:A16,*A15--[1]
STDW .D2T2 B13:B12,*SP--[1] ; save PC and CSR
STDW .D2T2 B11:B10,*SP--[1] ; save RILC and ILC
STDW .D2T1 A5:A4,*SP--[1] ; save TSR and orig A4
;; We left an unused word on the stack just above pt_regs.
;; It is used to save whether or not this frame is due to
;; a syscall. It is cleared here, but the syscall handler
;; sets it to a non-zero value.
MVK .L2 0,B1
STW .D2T2 B1,*+SP(REGS__END+8) ; clear syscall flag
.endm
.macro RESTORE_ALL __rp __tsr
LDDW .D2T2 *++SP[1],B9:B8 ; get TSR (B9)
LDDW .D2T2 *++SP[1],B11:B10 ; get RILC (B11) and ILC (B10)
LDDW .D2T2 *++SP[1],B13:B12 ; get PC (B13) and CSR (B12)
ADDAW .D1X SP,30,A15
LDDW .D1T1 *++A15[1],A17:A16
|| LDDW .D2T2 *++SP[1],B17:B16
LDDW .D1T1 *++A15[1],A19:A18
|| LDDW .D2T2 *++SP[1],B19:B18
LDDW .D1T1 *++A15[1],A21:A20
|| LDDW .D2T2 *++SP[1],B21:B20
LDDW .D1T1 *++A15[1],A23:A22
|| LDDW .D2T2 *++SP[1],B23:B22
LDDW .D1T1 *++A15[1],A25:A24
|| LDDW .D2T2 *++SP[1],B25:B24
LDDW .D1T1 *++A15[1],A27:A26
|| LDDW .D2T2 *++SP[1],B27:B26
LDDW .D1T1 *++A15[1],A29:A28
|| LDDW .D2T2 *++SP[1],B29:B28
LDDW .D1T1 *++A15[1],A31:A30
|| LDDW .D2T2 *++SP[1],B31:B30
LDDW .D1T1 *++A15[1],A1:A0
|| LDDW .D2T2 *++SP[1],B1:B0
LDDW .D1T1 *++A15[1],A3:A2
|| LDDW .D2T2 *++SP[1],B3:B2
|| MVC .S2 B9,__tsr
LDDW .D1T1 *++A15[1],A5:A4
|| LDDW .D2T2 *++SP[1],B5:B4
|| MVC .S2 B11,RILC
LDDW .D1T1 *++A15[1],A7:A6
|| LDDW .D2T2 *++SP[1],B7:B6
|| MVC .S2 B10,ILC
LDDW .D1T1 *++A15[1],A9:A8
|| LDDW .D2T2 *++SP[1],B9:B8
|| MVC .S2 B13,__rp
LDDW .D1T1 *++A15[1],A11:A10
|| LDDW .D2T2 *++SP[1],B11:B10
|| MVC .S2 B12,CSR
LDDW .D1T1 *++A15[1],A13:A12
|| LDDW .D2T2 *++SP[1],B13:B12
MV .D2X A15,SP
|| MVKL .S1 current_ksp,A15
MVKH .S1 current_ksp,A15
|| ADDAW .D1X SP,6,A14
STW .D1T1 A14,*A15 ; save kernel stack pointer
LDDW .D2T1 *++SP[1],A15:A14
B .S2 __rp ; return from interruption
LDDW .D2T2 *+SP[1],SP:DP
NOP 4
.endm
.section .text
;;
;; Jump to schedule() then return to ret_from_exception
;;
_reschedule:
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 schedule,A0
MVKH .S1 schedule,A0
B .S2X A0
#else
B .S1 schedule
#endif
ADDKPC .S2 ret_from_exception,B3,4
;;
;; Called before syscall handler when process is being debugged
;;
tracesys_on:
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 syscall_trace_entry,A0
MVKH .S1 syscall_trace_entry,A0
B .S2X A0
#else
B .S1 syscall_trace_entry
#endif
ADDKPC .S2 ret_from_syscall_trace,B3,3
ADD .S1X 8,SP,A4
ret_from_syscall_trace:
;; tracing returns (possibly new) syscall number
MV .D2X A4,B0
|| MVK .S2 __NR_syscalls,B1
CMPLTU .L2 B0,B1,B1
[!B1] BNOP .S2 ret_from_syscall_function,5
|| MVK .S1 -ENOSYS,A4
;; reload syscall args from (possibly modified) stack frame
;; and get syscall handler addr from sys_call_table:
LDW .D2T2 *+SP(REGS_B4+8),B4
|| MVKL .S2 sys_call_table,B1
LDW .D2T1 *+SP(REGS_A6+8),A6
|| MVKH .S2 sys_call_table,B1
LDW .D2T2 *+B1[B0],B0
|| MVKL .S2 ret_from_syscall_function,B3
LDW .D2T2 *+SP(REGS_B6+8),B6
|| MVKH .S2 ret_from_syscall_function,B3
LDW .D2T1 *+SP(REGS_A8+8),A8
LDW .D2T2 *+SP(REGS_B8+8),B8
NOP
; B0 = sys_call_table[__NR_*]
BNOP .S2 B0,5 ; branch to syscall handler
|| LDW .D2T1 *+SP(REGS_ORIG_A4+8),A4
syscall_exit_work:
AND .D1 _TIF_SYSCALL_TRACE,A2,A0
[!A0] BNOP .S1 work_pending,5
[A0] B .S2 syscall_trace_exit
ADDKPC .S2 resume_userspace,B3,1
MVC .S2 CSR,B1
SET .S2 B1,0,0,B1
MVC .S2 B1,CSR ; enable ints
work_pending:
AND .D1 _TIF_NEED_RESCHED,A2,A0
[!A0] BNOP .S1 work_notifysig,5
work_resched:
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 schedule,A1
MVKH .S1 schedule,A1
B .S2X A1
#else
B .S2 schedule
#endif
ADDKPC .S2 work_rescheduled,B3,4
work_rescheduled:
;; make sure we don't miss an interrupt setting need_resched or
;; sigpending between sampling and the rti
MASK_INT B2
GET_THREAD_INFO A12
LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
MVK .S1 _TIF_WORK_MASK,A1
MVK .S1 _TIF_NEED_RESCHED,A3
NOP 2
AND .D1 A1,A2,A0
|| AND .S1 A3,A2,A1
[!A0] BNOP .S1 restore_all,5
[A1] BNOP .S1 work_resched,5
work_notifysig:
B .S2 do_notify_resume
LDW .D2T1 *+SP(REGS__END+8),A6 ; syscall flag
ADDKPC .S2 resume_userspace,B3,1
ADD .S1X 8,SP,A4 ; pt_regs pointer is first arg
MV .D2X A2,B4 ; thread_info flags is second arg
;;
;; On C64x+, the return way from exception and interrupt
;; is a little bit different
;;
ENTRY(ret_from_exception)
#ifdef CONFIG_PREEMPT
MASK_INT B2
#endif
ENTRY(ret_from_interrupt)
;;
;; Check if we are comming from user mode.
;;
LDW .D2T2 *+SP(REGS_TSR+8),B0
MVK .S2 0x40,B1
NOP 3
AND .D2 B0,B1,B0
[!B0] BNOP .S2 resume_kernel,5
resume_userspace:
;; make sure we don't miss an interrupt setting need_resched or
;; sigpending between sampling and the rti
MASK_INT B2
GET_THREAD_INFO A12
LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
MVK .S1 _TIF_WORK_MASK,A1
MVK .S1 _TIF_NEED_RESCHED,A3
NOP 2
AND .D1 A1,A2,A0
[A0] BNOP .S1 work_pending,5
BNOP .S1 restore_all,5
;;
;; System call handling
;; B0 = syscall number (in sys_call_table)
;; A4,B4,A6,B6,A8,B8 = arguments of the syscall function
;; A4 is the return value register
;;
system_call_saved:
MVK .L2 1,B2
STW .D2T2 B2,*+SP(REGS__END+8) ; set syscall flag
MVC .S2 B2,ECR ; ack the software exception
UNMASK_INT B2 ; re-enable global IT
system_call_saved_noack:
;; Check system call number
MVK .S2 __NR_syscalls,B1
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_ni_syscall,A0
#endif
CMPLTU .L2 B0,B1,B1
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKH .S1 sys_ni_syscall,A0
#endif
;; Check for ptrace
GET_THREAD_INFO A12
#ifdef CONFIG_C6X_BIG_KERNEL
[!B1] B .S2X A0
#else
[!B1] B .S2 sys_ni_syscall
#endif
[!B1] ADDKPC .S2 ret_from_syscall_function,B3,4
;; Get syscall handler addr from sys_call_table
;; call tracesys_on or call syscall handler
LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
|| MVKL .S2 sys_call_table,B1
MVKH .S2 sys_call_table,B1
LDW .D2T2 *+B1[B0],B0
NOP 2
; A2 = thread_info flags
AND .D1 _TIF_SYSCALL_TRACE,A2,A2
[A2] BNOP .S1 tracesys_on,5
;; B0 = _sys_call_table[__NR_*]
B .S2 B0
ADDKPC .S2 ret_from_syscall_function,B3,4
ret_from_syscall_function:
STW .D2T1 A4,*+SP(REGS_A4+8) ; save return value in A4
; original A4 is in orig_A4
syscall_exit:
;; make sure we don't miss an interrupt setting need_resched or
;; sigpending between sampling and the rti
MASK_INT B2
LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2
MVK .S1 _TIF_ALLWORK_MASK,A1
NOP 3
AND .D1 A1,A2,A2 ; check for work to do
[A2] BNOP .S1 syscall_exit_work,5
restore_all:
RESTORE_ALL NRP,NTSR
;;
;; After a fork we jump here directly from resume,
;; so that A4 contains the previous task structure.
;;
ENTRY(ret_from_fork)
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 schedule_tail,A0
MVKH .S1 schedule_tail,A0
B .S2X A0
#else
B .S2 schedule_tail
#endif
ADDKPC .S2 ret_from_fork_2,B3,4
ret_from_fork_2:
;; return 0 in A4 for child process
GET_THREAD_INFO A12
BNOP .S2 syscall_exit,3
MVK .L2 0,B0
STW .D2T2 B0,*+SP(REGS_A4+8)
ENDPROC(ret_from_fork)
;;
;; These are the interrupt handlers, responsible for calling __do_IRQ()
;; int6 is used for syscalls (see _system_call entry)
;;
.macro SAVE_ALL_INT
SAVE_ALL IRP,ITSR
.endm
.macro CALL_INT int
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 c6x_do_IRQ,A0
MVKH .S1 c6x_do_IRQ,A0
BNOP .S2X A0,1
MVK .S1 int,A4
ADDAW .D2 SP,2,B4
MVKL .S2 ret_from_interrupt,B3
MVKH .S2 ret_from_interrupt,B3
#else
CALLP .S2 c6x_do_IRQ,B3
|| MVK .S1 int,A4
|| ADDAW .D2 SP,2,B4
B .S1 ret_from_interrupt
NOP 5
#endif
.endm
ENTRY(_int4_handler)
SAVE_ALL_INT
CALL_INT 4
ENDPROC(_int4_handler)
ENTRY(_int5_handler)
SAVE_ALL_INT
CALL_INT 5
ENDPROC(_int5_handler)
ENTRY(_int6_handler)
SAVE_ALL_INT
CALL_INT 6
ENDPROC(_int6_handler)
ENTRY(_int7_handler)
SAVE_ALL_INT
CALL_INT 7
ENDPROC(_int7_handler)
ENTRY(_int8_handler)
SAVE_ALL_INT
CALL_INT 8
ENDPROC(_int8_handler)
ENTRY(_int9_handler)
SAVE_ALL_INT
CALL_INT 9
ENDPROC(_int9_handler)
ENTRY(_int10_handler)
SAVE_ALL_INT
CALL_INT 10
ENDPROC(_int10_handler)
ENTRY(_int11_handler)
SAVE_ALL_INT
CALL_INT 11
ENDPROC(_int11_handler)
ENTRY(_int12_handler)
SAVE_ALL_INT
CALL_INT 12
ENDPROC(_int12_handler)
ENTRY(_int13_handler)
SAVE_ALL_INT
CALL_INT 13
ENDPROC(_int13_handler)
ENTRY(_int14_handler)
SAVE_ALL_INT
CALL_INT 14
ENDPROC(_int14_handler)
ENTRY(_int15_handler)
SAVE_ALL_INT
CALL_INT 15
ENDPROC(_int15_handler)
;;
;; Handler for uninitialized and spurious interrupts
;;
ENTRY(_bad_interrupt)
B .S2 IRP
NOP 5
ENDPROC(_bad_interrupt)
;;
;; Entry for NMI/exceptions/syscall
;;
ENTRY(_nmi_handler)
SAVE_ALL NRP,NTSR
MVC .S2 EFR,B2
CMPEQ .L2 1,B2,B2
|| MVC .S2 TSR,B1
CLR .S2 B1,10,10,B1
MVC .S2 B1,TSR
#ifdef CONFIG_C6X_BIG_KERNEL
[!B2] MVKL .S1 process_exception,A0
[!B2] MVKH .S1 process_exception,A0
[!B2] B .S2X A0
#else
[!B2] B .S2 process_exception
#endif
[B2] B .S2 system_call_saved
[!B2] ADDAW .D2 SP,2,B1
[!B2] MV .D1X B1,A4
ADDKPC .S2 ret_from_trap,B3,2
ret_from_trap:
MV .D2X A4,B0
[!B0] BNOP .S2 ret_from_exception,5
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S2 system_call_saved_noack,B3
MVKH .S2 system_call_saved_noack,B3
#endif
LDW .D2T2 *+SP(REGS_B0+8),B0
LDW .D2T1 *+SP(REGS_A4+8),A4
LDW .D2T2 *+SP(REGS_B4+8),B4
LDW .D2T1 *+SP(REGS_A6+8),A6
LDW .D2T2 *+SP(REGS_B6+8),B6
LDW .D2T1 *+SP(REGS_A8+8),A8
#ifdef CONFIG_C6X_BIG_KERNEL
|| B .S2 B3
#else
|| B .S2 system_call_saved_noack
#endif
LDW .D2T2 *+SP(REGS_B8+8),B8
NOP 4
ENDPROC(_nmi_handler)
;;
;; Jump to schedule() then return to ret_from_isr
;;
#ifdef CONFIG_PREEMPT
resume_kernel:
GET_THREAD_INFO A12
LDW .D1T1 *+A12(THREAD_INFO_PREEMPT_COUNT),A1
NOP 4
[A1] BNOP .S2 restore_all,5
preempt_schedule:
GET_THREAD_INFO A2
LDW .D1T1 *+A2(THREAD_INFO_FLAGS),A1
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S2 preempt_schedule_irq,B0
MVKH .S2 preempt_schedule_irq,B0
NOP 2
#else
NOP 4
#endif
AND .D1 _TIF_NEED_RESCHED,A1,A1
[!A1] BNOP .S2 restore_all,5
#ifdef CONFIG_C6X_BIG_KERNEL
B .S2 B0
#else
B .S2 preempt_schedule_irq
#endif
ADDKPC .S2 preempt_schedule,B3,4
#endif /* CONFIG_PREEMPT */
ENTRY(enable_exception)
DINT
MVC .S2 TSR,B0
MVC .S2 B3,NRP
MVK .L2 0xc,B1
OR .D2 B0,B1,B0
MVC .S2 B0,TSR ; Set GEE and XEN in TSR
B .S2 NRP
NOP 5
ENDPROC(enable_exception)
ENTRY(sys_sigaltstack)
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 do_sigaltstack,A0 ; branch to do_sigaltstack
MVKH .S1 do_sigaltstack,A0
B .S2X A0
#else
B .S2 do_sigaltstack
#endif
LDW .D2T1 *+SP(REGS_SP+8),A6
NOP 4
ENDPROC(sys_sigaltstack)
;; kernel_execve
ENTRY(kernel_execve)
MVK .S2 __NR_execve,B0
SWE
BNOP .S2 B3,5
ENDPROC(kernel_execve)
;;
;; Special system calls
;; return address is in B3
;;
ENTRY(sys_clone)
ADD .D1X SP,8,A4
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_c6x_clone,A0
MVKH .S1 sys_c6x_clone,A0
BNOP .S2X A0,5
#else
|| B .S2 sys_c6x_clone
NOP 5
#endif
ENDPROC(sys_clone)
ENTRY(sys_rt_sigreturn)
ADD .D1X SP,8,A4
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 do_rt_sigreturn,A0
MVKH .S1 do_rt_sigreturn,A0
BNOP .S2X A0,5
#else
|| B .S2 do_rt_sigreturn
NOP 5
#endif
ENDPROC(sys_rt_sigreturn)
ENTRY(sys_execve)
ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter
; & adjust regs stack addr
LDW .D2T2 *+SP(REGS_B4+8),B4
;; c6x_execve(char *name, char **argv,
;; char **envp, struct pt_regs *regs)
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_c6x_execve,A0
MVKH .S1 sys_c6x_execve,A0
B .S2X A0
#else
|| B .S2 sys_c6x_execve
#endif
STW .D2T2 B3,*SP--[2]
ADDKPC .S2 ret_from_c6x_execve,B3,3
ret_from_c6x_execve:
LDW .D2T2 *++SP[2],B3
NOP 4
BNOP .S2 B3,5
ENDPROC(sys_execve)
ENTRY(sys_pread_c6x)
MV .D2X A8,B7
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_pread64,A0
MVKH .S1 sys_pread64,A0
BNOP .S2X A0,5
#else
|| B .S2 sys_pread64
NOP 5
#endif
ENDPROC(sys_pread_c6x)
ENTRY(sys_pwrite_c6x)
MV .D2X A8,B7
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_pwrite64,A0
MVKH .S1 sys_pwrite64,A0
BNOP .S2X A0,5
#else
|| B .S2 sys_pwrite64
NOP 5
#endif
ENDPROC(sys_pwrite_c6x)
;; On Entry
;; A4 - path
;; B4 - offset_lo (LE), offset_hi (BE)
;; A6 - offset_lo (BE), offset_hi (LE)
ENTRY(sys_truncate64_c6x)
#ifdef CONFIG_CPU_BIG_ENDIAN
MV .S2 B4,B5
MV .D2X A6,B4
#else
MV .D2X A6,B5
#endif
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_truncate64,A0
MVKH .S1 sys_truncate64,A0
BNOP .S2X A0,5
#else
|| B .S2 sys_truncate64
NOP 5
#endif
ENDPROC(sys_truncate64_c6x)
;; On Entry
;; A4 - fd
;; B4 - offset_lo (LE), offset_hi (BE)
;; A6 - offset_lo (BE), offset_hi (LE)
ENTRY(sys_ftruncate64_c6x)
#ifdef CONFIG_CPU_BIG_ENDIAN
MV .S2 B4,B5
MV .D2X A6,B4
#else
MV .D2X A6,B5
#endif
#ifdef CONFIG_C6X_BIG_KERNEL
|| MVKL .S1 sys_ftruncate64,A0
MVKH .S1 sys_ftruncate64,A0
BNOP .S2X A0,5
#else
|| B .S2 sys_ftruncate64
NOP 5
#endif
ENDPROC(sys_ftruncate64_c6x)
#ifdef __ARCH_WANT_SYSCALL_OFF_T
;; On Entry
;; A4 - fd
;; B4 - offset_lo (LE), offset_hi (BE)
;; A6 - offset_lo (BE), offset_hi (LE)
;; B6 - len
;; A8 - advice
ENTRY(sys_fadvise64_c6x)
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 sys_fadvise64,A0
MVKH .S1 sys_fadvise64,A0
BNOP .S2X A0,2
#else
B .S2 sys_fadvise64
NOP 2
#endif
#ifdef CONFIG_CPU_BIG_ENDIAN
MV .L2 B4,B5
|| MV .D2X A6,B4
#else
MV .D2X A6,B5
#endif
MV .D1X B6,A6
MV .D2X A8,B6
#endif
ENDPROC(sys_fadvise64_c6x)
;; On Entry
;; A4 - fd
;; B4 - offset_lo (LE), offset_hi (BE)
;; A6 - offset_lo (BE), offset_hi (LE)
;; B6 - len_lo (LE), len_hi (BE)
;; A8 - len_lo (BE), len_hi (LE)
;; B8 - advice
ENTRY(sys_fadvise64_64_c6x)
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 sys_fadvise64_64,A0
MVKH .S1 sys_fadvise64_64,A0
BNOP .S2X A0,2
#else
B .S2 sys_fadvise64_64
NOP 2
#endif
#ifdef CONFIG_CPU_BIG_ENDIAN
MV .L2 B4,B5
|| MV .D2X A6,B4
MV .L1 A8,A6
|| MV .D1X B6,A7
#else
MV .D2X A6,B5
MV .L1 A8,A7
|| MV .D1X B6,A6
#endif
MV .L2 B8,B6
ENDPROC(sys_fadvise64_64_c6x)
;; On Entry
;; A4 - fd
;; B4 - mode
;; A6 - offset_hi
;; B6 - offset_lo
;; A8 - len_hi
;; B8 - len_lo
ENTRY(sys_fallocate_c6x)
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 sys_fallocate,A0
MVKH .S1 sys_fallocate,A0
BNOP .S2X A0,1
#else
B .S2 sys_fallocate
NOP
#endif
MV .D1 A6,A7
MV .D1X B6,A6
MV .D2X A8,B7
MV .D2 B8,B6
ENDPROC(sys_fallocate_c6x)
;; put this in .neardata for faster access when using DSBT mode
.section .neardata,"aw",@progbits
.global current_ksp
.hidden current_ksp
current_ksp:
.word init_thread_union + THREAD_START_SP

84
arch/c6x/kernel/head.S Normal file
View File

@ -0,0 +1,84 @@
;
; Port on Texas Instruments TMS320C6x architecture
;
; Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as
; published by the Free Software Foundation.
;
#include <linux/linkage.h>
#include <linux/of_fdt.h>
#include <asm/asm-offsets.h>
__HEAD
ENTRY(_c_int00)
;; Save magic and pointer
MV .S1 A4,A10
MV .S2 B4,B10
MVKL .S2 __bss_start,B5
MVKH .S2 __bss_start,B5
MVKL .S2 __bss_stop,B6
MVKH .S2 __bss_stop,B6
SUB .L2 B6,B5,B6 ; bss size
;; Set the stack pointer
MVKL .S2 current_ksp,B0
MVKH .S2 current_ksp,B0
LDW .D2T2 *B0,B15
;; clear bss
SHR .S2 B6,3,B0 ; number of dwords to clear
ZERO .L2 B13
ZERO .L2 B12
bss_loop:
BDEC .S2 bss_loop,B0
NOP 3
CMPLT .L2 B0,0,B1
[!B1] STDW .D2T2 B13:B12,*B5++[1]
NOP 4
AND .D2 ~7,B15,B15
;; Clear GIE and PGIE
MVC .S2 CSR,B2
CLR .S2 B2,0,1,B2
MVC .S2 B2,CSR
MVC .S2 TSR,B2
CLR .S2 B2,0,1,B2
MVC .S2 B2,TSR
MVC .S2 ITSR,B2
CLR .S2 B2,0,1,B2
MVC .S2 B2,ITSR
MVC .S2 NTSR,B2
CLR .S2 B2,0,1,B2
MVC .S2 B2,NTSR
;; pass DTB pointer to machine_init (or zero if none)
MVKL .S1 OF_DT_HEADER,A0
MVKH .S1 OF_DT_HEADER,A0
CMPEQ .L1 A10,A0,A0
[A0] MV .S1X B10,A4
[!A0] MVK .S1 0,A4
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 machine_init,A0
MVKH .S1 machine_init,A0
B .S2X A0
ADDKPC .S2 0f,B3,4
0:
#else
CALLP .S2 machine_init,B3
#endif
;; Jump to Linux init
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 start_kernel,A0
MVKH .S1 start_kernel,A0
B .S2X A0
#else
B .S2 start_kernel
#endif
NOP 5
L1: BNOP .S2 L1,5

728
arch/c6x/kernel/irq.c Normal file
View File

@ -0,0 +1,728 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
*
* This borrows heavily from powerpc version, which is:
*
* Derived from arch/i386/kernel/irq.c
* Copyright (C) 1992 Linus Torvalds
* Adapted from arch/i386 by Gary Thomas
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
* Updated and modified by Cort Dougan <cort@fsmlabs.com>
* Copyright (C) 1996-2001 Cort Dougan
* Adapted for Power Macintosh by Paul Mackerras
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/radix-tree.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <asm/megamod-pic.h>
unsigned long irq_err_count;
static DEFINE_RAW_SPINLOCK(core_irq_lock);
static void mask_core_irq(struct irq_data *data)
{
unsigned int prio = data->irq;
BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
raw_spin_lock(&core_irq_lock);
and_creg(IER, ~(1 << prio));
raw_spin_unlock(&core_irq_lock);
}
static void unmask_core_irq(struct irq_data *data)
{
unsigned int prio = data->irq;
raw_spin_lock(&core_irq_lock);
or_creg(IER, 1 << prio);
raw_spin_unlock(&core_irq_lock);
}
static struct irq_chip core_chip = {
.name = "core",
.irq_mask = mask_core_irq,
.irq_unmask = unmask_core_irq,
};
asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
irq_enter();
BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS);
generic_handle_irq(prio);
irq_exit();
set_irq_regs(old_regs);
}
static struct irq_host *core_host;
static int core_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
if (hw < 4 || hw >= NR_PRIORITY_IRQS)
return -EINVAL;
irq_set_status_flags(virq, IRQ_LEVEL);
irq_set_chip_and_handler(virq, &core_chip, handle_level_irq);
return 0;
}
static struct irq_host_ops core_host_ops = {
.map = core_host_map,
};
void __init init_IRQ(void)
{
struct device_node *np;
/* Mask all priority IRQs */
and_creg(IER, ~0xfff0);
np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic");
if (np != NULL) {
/* create the core host */
core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0,
&core_host_ops, 0);
if (core_host)
irq_set_default_host(core_host);
of_node_put(np);
}
printk(KERN_INFO "Core interrupt controller initialized\n");
/* now we're ready for other SoC controllers */
megamod_pic_init();
/* Clear all general IRQ flags */
set_creg(ICR, 0xfff0);
}
void ack_bad_irq(int irq)
{
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
irq_err_count++;
}
int arch_show_interrupts(struct seq_file *p, int prec)
{
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
return 0;
}
/*
* IRQ controller and virtual interrupts
*/
/* The main irq map itself is an array of NR_IRQ entries containing the
* associate host and irq number. An entry with a host of NULL is free.
* An entry can be allocated if it's free, the allocator always then sets
* hwirq first to the host's invalid irq number and then fills ops.
*/
struct irq_map_entry {
irq_hw_number_t hwirq;
struct irq_host *host;
};
static LIST_HEAD(irq_hosts);
static DEFINE_RAW_SPINLOCK(irq_big_lock);
static DEFINE_MUTEX(revmap_trees_mutex);
static struct irq_map_entry irq_map[NR_IRQS];
static unsigned int irq_virq_count = NR_IRQS;
static struct irq_host *irq_default_host;
irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
{
return irq_map[d->irq].hwirq;
}
EXPORT_SYMBOL_GPL(irqd_to_hwirq);
irq_hw_number_t virq_to_hw(unsigned int virq)
{
return irq_map[virq].hwirq;
}
EXPORT_SYMBOL_GPL(virq_to_hw);
bool virq_is_host(unsigned int virq, struct irq_host *host)
{
return irq_map[virq].host == host;
}
EXPORT_SYMBOL_GPL(virq_is_host);
static int default_irq_host_match(struct irq_host *h, struct device_node *np)
{
return h->of_node != NULL && h->of_node == np;
}
struct irq_host *irq_alloc_host(struct device_node *of_node,
unsigned int revmap_type,
unsigned int revmap_arg,
struct irq_host_ops *ops,
irq_hw_number_t inval_irq)
{
struct irq_host *host;
unsigned int size = sizeof(struct irq_host);
unsigned int i;
unsigned int *rmap;
unsigned long flags;
/* Allocate structure and revmap table if using linear mapping */
if (revmap_type == IRQ_HOST_MAP_LINEAR)
size += revmap_arg * sizeof(unsigned int);
host = kzalloc(size, GFP_KERNEL);
if (host == NULL)
return NULL;
/* Fill structure */
host->revmap_type = revmap_type;
host->inval_irq = inval_irq;
host->ops = ops;
host->of_node = of_node_get(of_node);
if (host->ops->match == NULL)
host->ops->match = default_irq_host_match;
raw_spin_lock_irqsave(&irq_big_lock, flags);
/* Check for the priority controller. */
if (revmap_type == IRQ_HOST_MAP_PRIORITY) {
if (irq_map[0].host != NULL) {
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
of_node_put(host->of_node);
kfree(host);
return NULL;
}
irq_map[0].host = host;
}
list_add(&host->link, &irq_hosts);
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
/* Additional setups per revmap type */
switch (revmap_type) {
case IRQ_HOST_MAP_PRIORITY:
/* 0 is always the invalid number for priority */
host->inval_irq = 0;
/* setup us as the host for all priority interrupts */
for (i = 1; i < NR_PRIORITY_IRQS; i++) {
irq_map[i].hwirq = i;
smp_wmb();
irq_map[i].host = host;
smp_wmb();
ops->map(host, i, i);
}
break;
case IRQ_HOST_MAP_LINEAR:
rmap = (unsigned int *)(host + 1);
for (i = 0; i < revmap_arg; i++)
rmap[i] = NO_IRQ;
host->revmap_data.linear.size = revmap_arg;
smp_wmb();
host->revmap_data.linear.revmap = rmap;
break;
case IRQ_HOST_MAP_TREE:
INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
break;
default:
break;
}
pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host);
return host;
}
struct irq_host *irq_find_host(struct device_node *node)
{
struct irq_host *h, *found = NULL;
unsigned long flags;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*/
raw_spin_lock_irqsave(&irq_big_lock, flags);
list_for_each_entry(h, &irq_hosts, link)
if (h->ops->match(h, node)) {
found = h;
break;
}
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
return found;
}
EXPORT_SYMBOL_GPL(irq_find_host);
void irq_set_default_host(struct irq_host *host)
{
pr_debug("irq: Default host set to @0x%p\n", host);
irq_default_host = host;
}
void irq_set_virq_count(unsigned int count)
{
pr_debug("irq: Trying to set virq count to %d\n", count);
BUG_ON(count < NR_PRIORITY_IRQS);
if (count < NR_IRQS)
irq_virq_count = count;
}
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
int res;
res = irq_alloc_desc_at(virq, 0);
if (res != virq) {
pr_debug("irq: -> allocating desc failed\n");
goto error;
}
/* map it */
smp_wmb();
irq_map[virq].hwirq = hwirq;
smp_mb();
if (host->ops->map(host, virq, hwirq)) {
pr_debug("irq: -> mapping failed, freeing\n");
goto errdesc;
}
irq_clear_status_flags(virq, IRQ_NOREQUEST);
return 0;
errdesc:
irq_free_descs(virq, 1);
error:
irq_free_virt(virq, 1);
return -1;
}
unsigned int irq_create_direct_mapping(struct irq_host *host)
{
unsigned int virq;
if (host == NULL)
host = irq_default_host;
BUG_ON(host == NULL);
WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
virq = irq_alloc_virt(host, 1, 0);
if (virq == NO_IRQ) {
pr_debug("irq: create_direct virq allocation failed\n");
return NO_IRQ;
}
pr_debug("irq: create_direct obtained virq %d\n", virq);
if (irq_setup_virq(host, virq, virq))
return NO_IRQ;
return virq;
}
unsigned int irq_create_mapping(struct irq_host *host,
irq_hw_number_t hwirq)
{
unsigned int virq, hint;
pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);
/* Look for default host if nececssary */
if (host == NULL)
host = irq_default_host;
if (host == NULL) {
printk(KERN_WARNING "irq_create_mapping called for"
" NULL host, hwirq=%lx\n", hwirq);
WARN_ON(1);
return NO_IRQ;
}
pr_debug("irq: -> using host @%p\n", host);
/* Check if mapping already exists */
virq = irq_find_mapping(host, hwirq);
if (virq != NO_IRQ) {
pr_debug("irq: -> existing mapping on virq %d\n", virq);
return virq;
}
/* Allocate a virtual interrupt number */
hint = hwirq % irq_virq_count;
virq = irq_alloc_virt(host, 1, hint);
if (virq == NO_IRQ) {
pr_debug("irq: -> virq allocation failed\n");
return NO_IRQ;
}
if (irq_setup_virq(host, virq, hwirq))
return NO_IRQ;
pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n",
hwirq, host->of_node ? host->of_node->full_name : "null", virq);
return virq;
}
EXPORT_SYMBOL_GPL(irq_create_mapping);
unsigned int irq_create_of_mapping(struct device_node *controller,
const u32 *intspec, unsigned int intsize)
{
struct irq_host *host;
irq_hw_number_t hwirq;
unsigned int type = IRQ_TYPE_NONE;
unsigned int virq;
if (controller == NULL)
host = irq_default_host;
else
host = irq_find_host(controller);
if (host == NULL) {
printk(KERN_WARNING "irq: no irq host found for %s !\n",
controller->full_name);
return NO_IRQ;
}
/* If host has no translation, then we assume interrupt line */
if (host->ops->xlate == NULL)
hwirq = intspec[0];
else {
if (host->ops->xlate(host, controller, intspec, intsize,
&hwirq, &type))
return NO_IRQ;
}
/* Create mapping */
virq = irq_create_mapping(host, hwirq);
if (virq == NO_IRQ)
return virq;
/* Set type if specified and different than the current one */
if (type != IRQ_TYPE_NONE &&
type != (irqd_get_trigger_type(irq_get_irq_data(virq))))
irq_set_irq_type(virq, type);
return virq;
}
EXPORT_SYMBOL_GPL(irq_create_of_mapping);
void irq_dispose_mapping(unsigned int virq)
{
struct irq_host *host;
irq_hw_number_t hwirq;
if (virq == NO_IRQ)
return;
/* Never unmap priority interrupts */
if (virq < NR_PRIORITY_IRQS)
return;
host = irq_map[virq].host;
if (WARN_ON(host == NULL))
return;
irq_set_status_flags(virq, IRQ_NOREQUEST);
/* remove chip and handler */
irq_set_chip_and_handler(virq, NULL, NULL);
/* Make sure it's completed */
synchronize_irq(virq);
/* Tell the PIC about it */
if (host->ops->unmap)
host->ops->unmap(host, virq);
smp_mb();
/* Clear reverse map */
hwirq = irq_map[virq].hwirq;
switch (host->revmap_type) {
case IRQ_HOST_MAP_LINEAR:
if (hwirq < host->revmap_data.linear.size)
host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
break;
case IRQ_HOST_MAP_TREE:
mutex_lock(&revmap_trees_mutex);
radix_tree_delete(&host->revmap_data.tree, hwirq);
mutex_unlock(&revmap_trees_mutex);
break;
}
/* Destroy map */
smp_mb();
irq_map[virq].hwirq = host->inval_irq;
irq_free_descs(virq, 1);
/* Free it */
irq_free_virt(virq, 1);
}
EXPORT_SYMBOL_GPL(irq_dispose_mapping);
unsigned int irq_find_mapping(struct irq_host *host,
irq_hw_number_t hwirq)
{
unsigned int i;
unsigned int hint = hwirq % irq_virq_count;
/* Look for default host if nececssary */
if (host == NULL)
host = irq_default_host;
if (host == NULL)
return NO_IRQ;
/* Slow path does a linear search of the map */
i = hint;
do {
if (irq_map[i].host == host &&
irq_map[i].hwirq == hwirq)
return i;
i++;
if (i >= irq_virq_count)
i = 4;
} while (i != hint);
return NO_IRQ;
}
EXPORT_SYMBOL_GPL(irq_find_mapping);
unsigned int irq_radix_revmap_lookup(struct irq_host *host,
irq_hw_number_t hwirq)
{
struct irq_map_entry *ptr;
unsigned int virq;
if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
return irq_find_mapping(host, hwirq);
/*
* The ptr returned references the static global irq_map.
* but freeing an irq can delete nodes along the path to
* do the lookup via call_rcu.
*/
rcu_read_lock();
ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
rcu_read_unlock();
/*
* If found in radix tree, then fine.
* Else fallback to linear lookup - this should not happen in practice
* as it means that we failed to insert the node in the radix tree.
*/
if (ptr)
virq = ptr - irq_map;
else
virq = irq_find_mapping(host, hwirq);
return virq;
}
void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
return;
if (virq != NO_IRQ) {
mutex_lock(&revmap_trees_mutex);
radix_tree_insert(&host->revmap_data.tree, hwirq,
&irq_map[virq]);
mutex_unlock(&revmap_trees_mutex);
}
}
unsigned int irq_linear_revmap(struct irq_host *host,
irq_hw_number_t hwirq)
{
unsigned int *revmap;
if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
return irq_find_mapping(host, hwirq);
/* Check revmap bounds */
if (unlikely(hwirq >= host->revmap_data.linear.size))
return irq_find_mapping(host, hwirq);
/* Check if revmap was allocated */
revmap = host->revmap_data.linear.revmap;
if (unlikely(revmap == NULL))
return irq_find_mapping(host, hwirq);
/* Fill up revmap with slow path if no mapping found */
if (unlikely(revmap[hwirq] == NO_IRQ))
revmap[hwirq] = irq_find_mapping(host, hwirq);
return revmap[hwirq];
}
unsigned int irq_alloc_virt(struct irq_host *host,
unsigned int count,
unsigned int hint)
{
unsigned long flags;
unsigned int i, j, found = NO_IRQ;
if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS))
return NO_IRQ;
raw_spin_lock_irqsave(&irq_big_lock, flags);
/* Use hint for 1 interrupt if any */
if (count == 1 && hint >= NR_PRIORITY_IRQS &&
hint < irq_virq_count && irq_map[hint].host == NULL) {
found = hint;
goto hint_found;
}
/* Look for count consecutive numbers in the allocatable
* (non-legacy) space
*/
for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) {
if (irq_map[i].host != NULL)
j = 0;
else
j++;
if (j == count) {
found = i - count + 1;
break;
}
}
if (found == NO_IRQ) {
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
return NO_IRQ;
}
hint_found:
for (i = found; i < (found + count); i++) {
irq_map[i].hwirq = host->inval_irq;
smp_wmb();
irq_map[i].host = host;
}
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
return found;
}
void irq_free_virt(unsigned int virq, unsigned int count)
{
unsigned long flags;
unsigned int i;
WARN_ON(virq < NR_PRIORITY_IRQS);
WARN_ON(count == 0 || (virq + count) > irq_virq_count);
if (virq < NR_PRIORITY_IRQS) {
if (virq + count < NR_PRIORITY_IRQS)
return;
count -= NR_PRIORITY_IRQS - virq;
virq = NR_PRIORITY_IRQS;
}
if (count > irq_virq_count || virq > irq_virq_count - count) {
if (virq > irq_virq_count)
return;
count = irq_virq_count - virq;
}
raw_spin_lock_irqsave(&irq_big_lock, flags);
for (i = virq; i < (virq + count); i++) {
struct irq_host *host;
host = irq_map[i].host;
irq_map[i].hwirq = host->inval_irq;
smp_wmb();
irq_map[i].host = NULL;
}
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
}
#ifdef CONFIG_VIRQ_DEBUG
static int virq_debug_show(struct seq_file *m, void *private)
{
unsigned long flags;
struct irq_desc *desc;
const char *p;
static const char none[] = "none";
void *data;
int i;
seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
"chip name", "chip data", "host name");
for (i = 1; i < nr_irqs; i++) {
desc = irq_to_desc(i);
if (!desc)
continue;
raw_spin_lock_irqsave(&desc->lock, flags);
if (desc->action && desc->action->handler) {
struct irq_chip *chip;
seq_printf(m, "%5d ", i);
seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
chip = irq_desc_get_chip(desc);
if (chip && chip->name)
p = chip->name;
else
p = none;
seq_printf(m, "%-15s ", p);
data = irq_desc_get_chip_data(desc);
seq_printf(m, "0x%16p ", data);
if (irq_map[i].host && irq_map[i].host->of_node)
p = irq_map[i].host->of_node->full_name;
else
p = none;
seq_printf(m, "%s\n", p);
}
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
return 0;
}
static int virq_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, virq_debug_show, inode->i_private);
}
static const struct file_operations virq_debug_fops = {
.open = virq_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init irq_debugfs_init(void)
{
if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,
NULL, &virq_debug_fops) == NULL)
return -ENOMEM;
return 0;
}
device_initcall(irq_debugfs_init);
#endif /* CONFIG_VIRQ_DEBUG */

123
arch/c6x/kernel/module.c Normal file
View File

@ -0,0 +1,123 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Thomas Charleux (thomas.charleux@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>
static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift)
{
u32 opcode;
long ep = (long)ip & ~31;
long delta = ((long)dest - ep) >> 2;
long mask = (1 << maskbits) - 1;
if ((delta >> (maskbits - 1)) == 0 ||
(delta >> (maskbits - 1)) == -1) {
opcode = *ip;
opcode &= ~(mask << shift);
opcode |= ((delta & mask) << shift);
*ip = opcode;
pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n",
maskbits, ip, (void *)dest, opcode);
return 0;
}
pr_err("PCR_S%d reloc %p -> %p out of range!\n",
maskbits, ip, (void *)dest);
return -1;
}
/*
* apply a RELA relocation
*/
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr;
Elf_Sym *sym;
u32 *location, opcode;
unsigned int i;
Elf32_Addr v;
Elf_Addr offset = 0;
pr_debug("Applying relocate section %u to %u with offset 0x%x\n",
relsec, sechdrs[relsec].sh_info, offset);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset - offset;
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info);
/* this is the adjustment to be made */
v = sym->st_value + rel[i].r_addend;
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_C6000_ABS32:
pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v);
*location = v;
break;
case R_C6000_ABS16:
pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v);
*(u16 *)location = v;
break;
case R_C6000_ABS8:
pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v);
*(u8 *)location = v;
break;
case R_C6000_ABS_L16:
opcode = *location;
opcode &= ~0x7fff80;
opcode |= ((v & 0xffff) << 7);
pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n",
location, v, opcode);
*location = opcode;
break;
case R_C6000_ABS_H16:
opcode = *location;
opcode &= ~0x7fff80;
opcode |= ((v >> 9) & 0x7fff80);
pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n",
location, v, opcode);
*location = opcode;
break;
case R_C6000_PCR_S21:
if (fixup_pcr(location, v, 21, 7))
return -ENOEXEC;
break;
case R_C6000_PCR_S12:
if (fixup_pcr(location, v, 12, 16))
return -ENOEXEC;
break;
case R_C6000_PCR_S10:
if (fixup_pcr(location, v, 10, 13))
return -ENOEXEC;
break;
default:
pr_err("module %s: Unknown RELA relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}
return 0;
}

265
arch/c6x/kernel/process.c Normal file
View File

@ -0,0 +1,265 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/init_task.h>
#include <linux/tick.h>
#include <linux/mqueue.h>
#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <asm/syscalls.h>
/* hooks for board specific support */
void (*c6x_restart)(void);
void (*c6x_halt)(void);
extern asmlinkage void ret_from_fork(void);
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
/*
* Initial thread structure.
*/
union thread_union init_thread_union __init_task_data = {
INIT_THREAD_INFO(init_task)
};
/*
* Initial task structure.
*/
struct task_struct init_task = INIT_TASK(init_task);
EXPORT_SYMBOL(init_task);
/*
* power off function, if any
*/
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
static void c6x_idle(void)
{
unsigned long tmp;
/*
* Put local_irq_enable and idle in same execute packet
* to make them atomic and avoid race to idle with
* interrupts enabled.
*/
asm volatile (" mvc .s2 CSR,%0\n"
" or .d2 1,%0,%0\n"
" mvc .s2 %0,CSR\n"
"|| idle\n"
: "=b"(tmp));
}
/*
* The idle loop for C64x
*/
void cpu_idle(void)
{
/* endless idle loop with no priority at all */
while (1) {
tick_nohz_idle_enter();
rcu_idle_enter();
while (1) {
local_irq_disable();
if (need_resched()) {
local_irq_enable();
break;
}
c6x_idle(); /* enables local irqs */
}
rcu_idle_exit();
tick_nohz_idle_exit();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}
static void halt_loop(void)
{
printk(KERN_EMERG "System Halted, OK to turn off power\n");
local_irq_disable();
while (1)
asm volatile("idle\n");
}
void machine_restart(char *__unused)
{
if (c6x_restart)
c6x_restart();
halt_loop();
}
void machine_halt(void)
{
if (c6x_halt)
c6x_halt();
halt_loop();
}
void machine_power_off(void)
{
if (pm_power_off)
pm_power_off();
halt_loop();
}
static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *))
{
do_exit(fn(arg));
}
/*
* Create a kernel thread
*/
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
struct pt_regs regs;
/*
* copy_thread sets a4 to zero (child return from fork)
* so we can't just set things up to directly return to
* fn.
*/
memset(&regs, 0, sizeof(regs));
regs.b4 = (unsigned long) arg;
regs.a6 = (unsigned long) fn;
regs.pc = (unsigned long) kernel_thread_helper;
local_save_flags(regs.csr);
regs.csr |= 1;
regs.tsr = 5; /* Set GEE and GIE in TSR */
/* Ok, create the new process.. */
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, &regs,
0, NULL, NULL);
}
EXPORT_SYMBOL(kernel_thread);
void flush_thread(void)
{
}
void exit_thread(void)
{
}
SYSCALL_DEFINE1(c6x_clone, struct pt_regs *, regs)
{
unsigned long clone_flags;
unsigned long newsp;
/* syscall puts clone_flags in A4 and usp in B4 */
clone_flags = regs->orig_a4;
if (regs->b4)
newsp = regs->b4;
else
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0, (int __user *)regs->a6,
(int __user *)regs->b6);
}
/*
* Do necessary setup to start up a newly executed thread.
*/
void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp)
{
/*
* The binfmt loader will setup a "full" stack, but the C6X
* operates an "empty" stack. So we adjust the usp so that
* argc doesn't get destroyed if an interrupt is taken before
* it is read from the stack.
*
* NB: Library startup code needs to match this.
*/
usp -= 8;
set_fs(USER_DS);
regs->pc = pc;
regs->sp = usp;
regs->tsr |= 0x40; /* set user mode */
current->thread.usp = usp;
}
/*
* Copy a new thread context in its stack.
*/
int copy_thread(unsigned long clone_flags, unsigned long usp,
unsigned long ustk_size,
struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs;
childregs = task_pt_regs(p);
*childregs = *regs;
childregs->a4 = 0;
if (usp == -1)
/* case of __kernel_thread: we return to supervisor space */
childregs->sp = (unsigned long)(childregs + 1);
else
/* Otherwise use the given stack */
childregs->sp = usp;
/* Set usp/ksp */
p->thread.usp = childregs->sp;
/* switch_to uses stack to save/restore 14 callee-saved regs */
thread_saved_ksp(p) = (unsigned long)childregs - 8;
p->thread.pc = (unsigned int) ret_from_fork;
p->thread.wchan = (unsigned long) ret_from_fork;
#ifdef __DSBT__
{
unsigned long dp;
asm volatile ("mv .S2 b14,%0\n" : "=b"(dp));
thread_saved_dp(p) = dp;
if (usp == -1)
childregs->dp = dp;
}
#endif
return 0;
}
/*
* c6x_execve() executes a new program.
*/
SYSCALL_DEFINE4(c6x_execve, const char __user *, name,
const char __user *const __user *, argv,
const char __user *const __user *, envp,
struct pt_regs *, regs)
{
int error;
char *filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
out:
return error;
}
unsigned long get_wchan(struct task_struct *p)
{
return p->thread.wchan;
}

187
arch/c6x/kernel/ptrace.c Normal file
View File

@ -0,0 +1,187 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.34: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/ptrace.h>
#include <linux/tracehook.h>
#include <linux/regset.h>
#include <linux/elf.h>
#include <asm/cacheflush.h>
#define PT_REG_SIZE (sizeof(struct pt_regs))
/*
* Called by kernel/ptrace.c when detaching.
*/
void ptrace_disable(struct task_struct *child)
{
/* nothing to do */
}
/*
* Get a register number from live pt_regs for the specified task.
*/
static inline long get_reg(struct task_struct *task, int regno)
{
long *addr = (long *)task_pt_regs(task);
if (regno == PT_TSR || regno == PT_CSR)
return 0;
return addr[regno];
}
/*
* Write contents of register REGNO in task TASK.
*/
static inline int put_reg(struct task_struct *task,
int regno,
unsigned long data)
{
unsigned long *addr = (unsigned long *)task_pt_regs(task);
if (regno != PT_TSR && regno != PT_CSR)
addr[regno] = data;
return 0;
}
/* regset get/set implementations */
static int gpr_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
struct pt_regs *regs = task_pt_regs(target);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
regs,
0, sizeof(*regs));
}
static int gpr_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
int ret;
struct pt_regs *regs = task_pt_regs(target);
/* Don't copyin TSR or CSR */
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs,
0, PT_TSR * sizeof(long));
if (ret)
return ret;
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
PT_TSR * sizeof(long),
(PT_TSR + 1) * sizeof(long));
if (ret)
return ret;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs,
(PT_TSR + 1) * sizeof(long),
PT_CSR * sizeof(long));
if (ret)
return ret;
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
PT_CSR * sizeof(long),
(PT_CSR + 1) * sizeof(long));
if (ret)
return ret;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs,
(PT_CSR + 1) * sizeof(long), -1);
return ret;
}
enum c6x_regset {
REGSET_GPR,
};
static const struct user_regset c6x_regsets[] = {
[REGSET_GPR] = {
.core_note_type = NT_PRSTATUS,
.n = ELF_NGREG,
.size = sizeof(u32),
.align = sizeof(u32),
.get = gpr_get,
.set = gpr_set
},
};
static const struct user_regset_view user_c6x_native_view = {
.name = "tic6x",
.e_machine = EM_TI_C6000,
.regsets = c6x_regsets,
.n = ARRAY_SIZE(c6x_regsets),
};
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
return &user_c6x_native_view;
}
/*
* Perform ptrace request
*/
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
int ret = 0;
switch (request) {
/*
* write the word at location addr.
*/
case PTRACE_POKETEXT:
ret = generic_ptrace_pokedata(child, addr, data);
if (ret == 0 && request == PTRACE_POKETEXT)
flush_icache_range(addr, addr + 4);
break;
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
/*
* handle tracing of system call entry
* - return the revised system call number or ULONG_MAX to cause ENOSYS
*/
asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs)
{
if (tracehook_report_syscall_entry(regs))
/* tracing decided this syscall should not happen, so
* We'll return a bogus call number to get an ENOSYS
* error, but leave the original number in
* regs->orig_a4
*/
return ULONG_MAX;
return regs->b0;
}
/*
* handle tracing of system call exit
*/
asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{
tracehook_report_syscall_exit(regs, 0);
}

510
arch/c6x/kernel/setup.c Normal file
View File

@ -0,0 +1,510 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/dma-mapping.h>
#include <linux/memblock.h>
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/clkdev.h>
#include <linux/initrd.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_fdt.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/cache.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <asm/sections.h>
#include <asm/div64.h>
#include <asm/setup.h>
#include <asm/dscr.h>
#include <asm/clock.h>
#include <asm/soc.h>
static const char *c6x_soc_name;
int c6x_num_cores;
EXPORT_SYMBOL_GPL(c6x_num_cores);
unsigned int c6x_silicon_rev;
EXPORT_SYMBOL_GPL(c6x_silicon_rev);
/*
* Device status register. This holds information
* about device configuration needed by some drivers.
*/
unsigned int c6x_devstat;
EXPORT_SYMBOL_GPL(c6x_devstat);
/*
* Some SoCs have fuse registers holding a unique MAC
* address. This is parsed out of the device tree with
* the resulting MAC being held here.
*/
unsigned char c6x_fuse_mac[6];
unsigned long memory_start;
unsigned long memory_end;
unsigned long ram_start;
unsigned long ram_end;
/* Uncached memory for DMA consistent use (memdma=) */
static unsigned long dma_start __initdata;
static unsigned long dma_size __initdata;
char c6x_command_line[COMMAND_LINE_SIZE];
#if defined(CONFIG_CMDLINE_BOOL)
static const char default_command_line[COMMAND_LINE_SIZE] __section(.cmdline) =
CONFIG_CMDLINE;
#endif
struct cpuinfo_c6x {
const char *cpu_name;
const char *cpu_voltage;
const char *mmu;
const char *fpu;
char *cpu_rev;
unsigned int core_id;
char __cpu_rev[5];
};
static DEFINE_PER_CPU(struct cpuinfo_c6x, cpu_data);
unsigned int ticks_per_ns_scaled;
EXPORT_SYMBOL(ticks_per_ns_scaled);
unsigned int c6x_core_freq;
static void __init get_cpuinfo(void)
{
unsigned cpu_id, rev_id, csr;
struct clk *coreclk = clk_get_sys(NULL, "core");
unsigned long core_khz;
u64 tmp;
struct cpuinfo_c6x *p;
struct device_node *node, *np;
p = &per_cpu(cpu_data, smp_processor_id());
if (!IS_ERR(coreclk))
c6x_core_freq = clk_get_rate(coreclk);
else {
printk(KERN_WARNING
"Cannot find core clock frequency. Using 700MHz\n");
c6x_core_freq = 700000000;
}
core_khz = c6x_core_freq / 1000;
tmp = (uint64_t)core_khz << C6X_NDELAY_SCALE;
do_div(tmp, 1000000);
ticks_per_ns_scaled = tmp;
csr = get_creg(CSR);
cpu_id = csr >> 24;
rev_id = (csr >> 16) & 0xff;
p->mmu = "none";
p->fpu = "none";
p->cpu_voltage = "unknown";
switch (cpu_id) {
case 0:
p->cpu_name = "C67x";
p->fpu = "yes";
break;
case 2:
p->cpu_name = "C62x";
break;
case 8:
p->cpu_name = "C64x";
break;
case 12:
p->cpu_name = "C64x";
break;
case 16:
p->cpu_name = "C64x+";
p->cpu_voltage = "1.2";
break;
default:
p->cpu_name = "unknown";
break;
}
if (cpu_id < 16) {
switch (rev_id) {
case 0x1:
if (cpu_id > 8) {
p->cpu_rev = "DM640/DM641/DM642/DM643";
p->cpu_voltage = "1.2 - 1.4";
} else {
p->cpu_rev = "C6201";
p->cpu_voltage = "2.5";
}
break;
case 0x2:
p->cpu_rev = "C6201B/C6202/C6211";
p->cpu_voltage = "1.8";
break;
case 0x3:
p->cpu_rev = "C6202B/C6203/C6204/C6205";
p->cpu_voltage = "1.5";
break;
case 0x201:
p->cpu_rev = "C6701 revision 0 (early CPU)";
p->cpu_voltage = "1.8";
break;
case 0x202:
p->cpu_rev = "C6701/C6711/C6712";
p->cpu_voltage = "1.8";
break;
case 0x801:
p->cpu_rev = "C64x";
p->cpu_voltage = "1.5";
break;
default:
p->cpu_rev = "unknown";
}
} else {
p->cpu_rev = p->__cpu_rev;
snprintf(p->__cpu_rev, sizeof(p->__cpu_rev), "0x%x", cpu_id);
}
p->core_id = get_coreid();
node = of_find_node_by_name(NULL, "cpus");
if (node) {
for_each_child_of_node(node, np)
if (!strcmp("cpu", np->name))
++c6x_num_cores;
of_node_put(node);
}
node = of_find_node_by_name(NULL, "soc");
if (node) {
if (of_property_read_string(node, "model", &c6x_soc_name))
c6x_soc_name = "unknown";
of_node_put(node);
} else
c6x_soc_name = "unknown";
printk(KERN_INFO "CPU%d: %s rev %s, %s volts, %uMHz\n",
p->core_id, p->cpu_name, p->cpu_rev,
p->cpu_voltage, c6x_core_freq / 1000000);
}
/*
* Early parsing of the command line
*/
static u32 mem_size __initdata;
/* "mem=" parsing. */
static int __init early_mem(char *p)
{
if (!p)
return -EINVAL;
mem_size = memparse(p, &p);
/* don't remove all of memory when handling "mem={invalid}" */
if (mem_size == 0)
return -EINVAL;
return 0;
}
early_param("mem", early_mem);
/* "memdma=<size>[@<address>]" parsing. */
static int __init early_memdma(char *p)
{
if (!p)
return -EINVAL;
dma_size = memparse(p, &p);
if (*p == '@')
dma_start = memparse(p, &p);
return 0;
}
early_param("memdma", early_memdma);
int __init c6x_add_memory(phys_addr_t start, unsigned long size)
{
static int ram_found __initdata;
/* We only handle one bank (the one with PAGE_OFFSET) for now */
if (ram_found)
return -EINVAL;
if (start > PAGE_OFFSET || PAGE_OFFSET >= (start + size))
return 0;
ram_start = start;
ram_end = start + size;
ram_found = 1;
return 0;
}
/*
* Do early machine setup and device tree parsing. This is called very
* early on the boot process.
*/
notrace void __init machine_init(unsigned long dt_ptr)
{
struct boot_param_header *dtb = __va(dt_ptr);
struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start;
/* interrupts must be masked */
set_creg(IER, 2);
/*
* Set the Interrupt Service Table (IST) to the beginning of the
* vector table.
*/
set_ist(_vectors_start);
lockdep_init();
/*
* dtb is passed in from bootloader.
* fdt is linked in blob.
*/
if (dtb && dtb != fdt)
fdt = dtb;
/* Do some early initialization based on the flat device tree */
early_init_devtree(fdt);
/* parse_early_param needs a boot_command_line */
strlcpy(boot_command_line, c6x_command_line, COMMAND_LINE_SIZE);
parse_early_param();
}
void __init setup_arch(char **cmdline_p)
{
int bootmap_size;
struct memblock_region *reg;
printk(KERN_INFO "Initializing kernel\n");
/* Initialize command line */
*cmdline_p = c6x_command_line;
memory_end = ram_end;
memory_end &= ~(PAGE_SIZE - 1);
if (mem_size && (PAGE_OFFSET + PAGE_ALIGN(mem_size)) < memory_end)
memory_end = PAGE_OFFSET + PAGE_ALIGN(mem_size);
/* add block that this kernel can use */
memblock_add(PAGE_OFFSET, memory_end - PAGE_OFFSET);
/* reserve kernel text/data/bss */
memblock_reserve(PAGE_OFFSET,
PAGE_ALIGN((unsigned long)&_end - PAGE_OFFSET));
if (dma_size) {
/* align to cacheability granularity */
dma_size = CACHE_REGION_END(dma_size);
if (!dma_start)
dma_start = memory_end - dma_size;
/* align to cacheability granularity */
dma_start = CACHE_REGION_START(dma_start);
/* reserve DMA memory taken from kernel memory */
if (memblock_is_region_memory(dma_start, dma_size))
memblock_reserve(dma_start, dma_size);
}
memory_start = PAGE_ALIGN((unsigned int) &_end);
printk(KERN_INFO "Memory Start=%08lx, Memory End=%08lx\n",
memory_start, memory_end);
#ifdef CONFIG_BLK_DEV_INITRD
/*
* Reserve initrd memory if in kernel memory.
*/
if (initrd_start < initrd_end)
if (memblock_is_region_memory(initrd_start,
initrd_end - initrd_start))
memblock_reserve(initrd_start,
initrd_end - initrd_start);
#endif
init_mm.start_code = (unsigned long) &_stext;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = memory_start;
init_mm.brk = memory_start;
/*
* Give all the memory to the bootmap allocator, tell it to put the
* boot mem_map at the start of memory
*/
bootmap_size = init_bootmem_node(NODE_DATA(0),
memory_start >> PAGE_SHIFT,
PAGE_OFFSET >> PAGE_SHIFT,
memory_end >> PAGE_SHIFT);
memblock_reserve(memory_start, bootmap_size);
unflatten_device_tree();
c6x_cache_init();
/* Set the whole external memory as non-cacheable */
disable_caching(ram_start, ram_end - 1);
/* Set caching of external RAM used by Linux */
for_each_memblock(memory, reg)
enable_caching(CACHE_REGION_START(reg->base),
CACHE_REGION_START(reg->base + reg->size - 1));
#ifdef CONFIG_BLK_DEV_INITRD
/*
* Enable caching for initrd which falls outside kernel memory.
*/
if (initrd_start < initrd_end) {
if (!memblock_is_region_memory(initrd_start,
initrd_end - initrd_start))
enable_caching(CACHE_REGION_START(initrd_start),
CACHE_REGION_START(initrd_end - 1));
}
#endif
/*
* Disable caching for dma coherent memory taken from kernel memory.
*/
if (dma_size && memblock_is_region_memory(dma_start, dma_size))
disable_caching(dma_start,
CACHE_REGION_START(dma_start + dma_size - 1));
/* Initialize the coherent memory allocator */
coherent_mem_init(dma_start, dma_size);
/*
* Free all memory as a starting point.
*/
free_bootmem(PAGE_OFFSET, memory_end - PAGE_OFFSET);
/*
* Then reserve memory which is already being used.
*/
for_each_memblock(reserved, reg) {
pr_debug("reserved - 0x%08x-0x%08x\n",
(u32) reg->base, (u32) reg->size);
reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
}
max_low_pfn = PFN_DOWN(memory_end);
min_low_pfn = PFN_UP(memory_start);
max_mapnr = max_low_pfn - min_low_pfn;
/* Get kmalloc into gear */
paging_init();
/*
* Probe for Device State Configuration Registers.
* We have to do this early in case timer needs to be enabled
* through DSCR.
*/
dscr_probe();
/* We do this early for timer and core clock frequency */
c64x_setup_clocks();
/* Get CPU info */
get_cpuinfo();
#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
}
#define cpu_to_ptr(n) ((void *)((long)(n)+1))
#define ptr_to_cpu(p) ((long)(p) - 1)
static int show_cpuinfo(struct seq_file *m, void *v)
{
int n = ptr_to_cpu(v);
struct cpuinfo_c6x *p = &per_cpu(cpu_data, n);
if (n == 0) {
seq_printf(m,
"soc\t\t: %s\n"
"soc revision\t: 0x%x\n"
"soc cores\t: %d\n",
c6x_soc_name, c6x_silicon_rev, c6x_num_cores);
}
seq_printf(m,
"\n"
"processor\t: %d\n"
"cpu\t\t: %s\n"
"core revision\t: %s\n"
"core voltage\t: %s\n"
"core id\t\t: %d\n"
"mmu\t\t: %s\n"
"fpu\t\t: %s\n"
"cpu MHz\t\t: %u\n"
"bogomips\t: %lu.%02lu\n\n",
n,
p->cpu_name, p->cpu_rev, p->cpu_voltage,
p->core_id, p->mmu, p->fpu,
(c6x_core_freq + 500000) / 1000000,
(loops_per_jiffy/(500000/HZ)),
(loops_per_jiffy/(5000/HZ))%100);
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return NULL;
}
static void c_stop(struct seq_file *m, void *v)
{
}
const struct seq_operations cpuinfo_op = {
c_start,
c_stop,
c_next,
show_cpuinfo
};
static struct cpu cpu_devices[NR_CPUS];
static int __init topology_init(void)
{
int i;
for_each_present_cpu(i)
register_cpu(&cpu_devices[i], i);
return 0;
}
subsys_initcall(topology_init);

377
arch/c6x/kernel/signal.c Normal file
View File

@ -0,0 +1,377 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* Updated for 2.6.34: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/cacheflush.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/*
* Do a signal return, undo the signal stack.
*/
#define RETCODE_SIZE (9 << 2) /* 9 instructions = 36 bytes */
struct rt_sigframe {
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
unsigned long retcode[RETCODE_SIZE >> 2];
};
static int restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *sc)
{
int err = 0;
/* The access_ok check was done by caller, so use __get_user here */
#define COPY(x) (err |= __get_user(regs->x, &sc->sc_##x))
COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
COPY(a16); COPY(a17); COPY(a18); COPY(a19);
COPY(a20); COPY(a21); COPY(a22); COPY(a23);
COPY(a24); COPY(a25); COPY(a26); COPY(a27);
COPY(a28); COPY(a29); COPY(a30); COPY(a31);
COPY(b16); COPY(b17); COPY(b18); COPY(b19);
COPY(b20); COPY(b21); COPY(b22); COPY(b23);
COPY(b24); COPY(b25); COPY(b26); COPY(b27);
COPY(b28); COPY(b29); COPY(b30); COPY(b31);
COPY(csr); COPY(pc);
#undef COPY
return err;
}
asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
/*
* Since we stacked the signal on a dword boundary,
* 'sp' should be dword aligned here. If it's
* not, then the user is trying to mess with us.
*/
if (regs->sp & 7)
goto badframe;
frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8);
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
return regs->a4;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
unsigned long mask)
{
int err = 0;
err |= __put_user(mask, &sc->sc_mask);
/* The access_ok check was done by caller, so use __put_user here */
#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x))
COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8);
COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9);
COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9);
COPY(a16); COPY(a17); COPY(a18); COPY(a19);
COPY(a20); COPY(a21); COPY(a22); COPY(a23);
COPY(a24); COPY(a25); COPY(a26); COPY(a27);
COPY(a28); COPY(a29); COPY(a30); COPY(a31);
COPY(b16); COPY(b17); COPY(b18); COPY(b19);
COPY(b20); COPY(b21); COPY(b22); COPY(b23);
COPY(b24); COPY(b25); COPY(b26); COPY(b27);
COPY(b28); COPY(b29); COPY(b30); COPY(b31);
COPY(csr); COPY(pc);
#undef COPY
return err;
}
static inline void __user *get_sigframe(struct k_sigaction *ka,
struct pt_regs *regs,
unsigned long framesize)
{
unsigned long sp = regs->sp;
/*
* This is the X/Open sanctioned signal stack switching.
*/
if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp) == 0)
sp = current->sas_ss_sp + current->sas_ss_size;
/*
* No matter what happens, 'sp' must be dword
* aligned. Otherwise, nasty things will happen
*/
return (void __user *)((sp - framesize) & ~7);
}
static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
unsigned long __user *retcode;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto segv_and_exit;
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
/* Clear all the bits of the ucontext we don't use. */
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace */
retcode = (unsigned long __user *) &frame->retcode;
/* The access_ok check was done above, so use __put_user here */
#define COPY(x) (err |= __put_user(x, retcode++))
COPY(0x0000002AUL | (__NR_rt_sigreturn << 7));
/* MVK __NR_rt_sigreturn,B0 */
COPY(0x10000000UL); /* SWE */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
COPY(0x00006000UL); /* NOP 4 */
#undef COPY
if (err)
goto segv_and_exit;
flush_icache_range((unsigned long) &frame->retcode,
(unsigned long) &frame->retcode + RETCODE_SIZE);
retcode = (unsigned long __user *) &frame->retcode;
/* Change user context to branch to signal handler */
regs->sp = (unsigned long) frame - 8;
regs->b3 = (unsigned long) retcode;
regs->pc = (unsigned long) ka->sa.sa_handler;
/* Give the signal number to the handler */
regs->a4 = signr;
/*
* For realtime signals we must also set the second and third
* arguments for the signal handler.
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
regs->b4 = (unsigned long)&frame->info;
regs->a6 = (unsigned long)&frame->uc;
return 0;
segv_and_exit:
force_sigsegv(signr, current);
return -EFAULT;
}
static inline void
handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
{
switch (regs->a4) {
case -ERESTARTNOHAND:
if (!has_handler)
goto do_restart;
regs->a4 = -EINTR;
break;
case -ERESTARTSYS:
if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
regs->a4 = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
do_restart:
regs->a4 = regs->orig_a4;
regs->pc -= 4;
break;
}
}
/*
* handle the actual delivery of a signal to userspace
*/
static int handle_signal(int sig,
siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs,
int syscall)
{
int ret;
/* Are we from a system call? */
if (syscall) {
/* If so, check system call restarting.. */
switch (regs->a4) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->a4 = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->a4 = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->a4 = regs->orig_a4;
regs->pc -= 4;
}
}
/* Set up the stack frame */
ret = setup_rt_frame(sig, ka, info, oldset, regs);
if (ret == 0) {
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked,
&ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
sigaddset(&current->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
return ret;
}
/*
* handle a potential signal
*/
static void do_signal(struct pt_regs *regs, int syscall)
{
struct k_sigaction ka;
siginfo_t info;
sigset_t *oldset;
int signr;
/* we want the common case to go fast, which is why we may in certain
* cases get here from kernel mode */
if (!user_mode(regs))
return;
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
if (handle_signal(signr, &info, &ka, oldset,
regs, syscall) == 0) {
/* a signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
* clear the TIF_RESTORE_SIGMASK flag */
if (test_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK);
tracehook_signal_handler(signr, &info, &ka, regs, 0);
}
return;
}
/* did we come from a system call? */
if (syscall) {
/* restart the system call - no handlers present */
switch (regs->a4) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
regs->a4 = regs->orig_a4;
regs->pc -= 4;
break;
case -ERESTART_RESTARTBLOCK:
regs->a4 = regs->orig_a4;
regs->b0 = __NR_restart_syscall;
regs->pc -= 4;
break;
}
}
/* if there's no signal to deliver, we just put the saved sigmask
* back */
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
clear_thread_flag(TIF_RESTORE_SIGMASK);
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
/*
* notification of userspace execution resumption
* - triggered by current->work.notify_resume
*/
asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags,
int syscall)
{
/* deal with pending signal delivery */
if (thread_info_flags & ((1 << TIF_SIGPENDING) |
(1 << TIF_RESTORE_SIGMASK)))
do_signal(regs, syscall);
if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
}

91
arch/c6x/kernel/soc.c Normal file
View File

@ -0,0 +1,91 @@
/*
* Miscellaneous SoC-specific hooks.
*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter <msalter@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/etherdevice.h>
#include <asm/system.h>
#include <asm/setup.h>
#include <asm/soc.h>
struct soc_ops soc_ops;
int soc_get_exception(void)
{
if (!soc_ops.get_exception)
return -1;
return soc_ops.get_exception();
}
void soc_assert_event(unsigned int evt)
{
if (soc_ops.assert_event)
soc_ops.assert_event(evt);
}
static u8 cmdline_mac[6];
static int __init get_mac_addr_from_cmdline(char *str)
{
int count, i, val;
for (count = 0; count < 6 && *str; count++, str += 3) {
if (!isxdigit(str[0]) || !isxdigit(str[1]))
return 0;
if (str[2] != ((count < 5) ? ':' : '\0'))
return 0;
for (i = 0, val = 0; i < 2; i++) {
val = val << 4;
val |= isdigit(str[i]) ?
str[i] - '0' : toupper(str[i]) - 'A' + 10;
}
cmdline_mac[count] = val;
}
return 1;
}
__setup("emac_addr=", get_mac_addr_from_cmdline);
/*
* Setup the MAC address for SoC ethernet devices.
*
* Before calling this function, the ethernet driver will have
* initialized the addr with local-mac-address from the device
* tree (if found). Allow command line to override, but not
* the fused address.
*/
int soc_mac_addr(unsigned int index, u8 *addr)
{
int i, have_dt_mac = 0, have_cmdline_mac = 0, have_fuse_mac = 0;
for (i = 0; i < 6; i++) {
if (cmdline_mac[i])
have_cmdline_mac = 1;
if (c6x_fuse_mac[i])
have_fuse_mac = 1;
if (addr[i])
have_dt_mac = 1;
}
/* cmdline overrides all */
if (have_cmdline_mac)
memcpy(addr, cmdline_mac, 6);
else if (!have_dt_mac) {
if (have_fuse_mac)
memcpy(addr, c6x_fuse_mac, 6);
else
random_ether_addr(addr);
}
/* adjust for specific EMAC device */
addr[5] += index * c6x_num_cores;
return 1;
}
EXPORT_SYMBOL_GPL(soc_mac_addr);

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2011 Texas Instruments Incorporated
* Author: Mark Salter (msalter@redhat.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#define SP B15
/*
* void __switch_to(struct thread_info *prev,
* struct thread_info *next,
* struct task_struct *tsk) ;
*/
ENTRY(__switch_to)
LDDW .D2T2 *+B4(THREAD_B15_14),B7:B6
|| MV .L2X A4,B5 ; prev
|| MV .L1X B4,A5 ; next
|| MVC .S2 RILC,B1
STW .D2T2 B3,*+B5(THREAD_PC)
|| STDW .D1T1 A13:A12,*+A4(THREAD_A13_12)
|| MVC .S2 ILC,B0
LDW .D2T2 *+B4(THREAD_PC),B3
|| LDDW .D1T1 *+A5(THREAD_A13_12),A13:A12
STDW .D1T1 A11:A10,*+A4(THREAD_A11_10)
|| STDW .D2T2 B1:B0,*+B5(THREAD_RICL_ICL)
#ifndef __DSBT__
|| MVKL .S2 current_ksp,B1
#endif
STDW .D2T2 B15:B14,*+B5(THREAD_B15_14)
|| STDW .D1T1 A15:A14,*+A4(THREAD_A15_14)
#ifndef __DSBT__
|| MVKH .S2 current_ksp,B1
#endif
;; Switch to next SP
MV .S2 B7,SP
#ifdef __DSBT__
|| STW .D2T2 B7,*+B14(current_ksp)
#else
|| STW .D2T2 B7,*B1
|| MV .L2 B6,B14
#endif
|| LDDW .D1T1 *+A5(THREAD_RICL_ICL),A1:A0
STDW .D2T2 B11:B10,*+B5(THREAD_B11_10)
|| LDDW .D1T1 *+A5(THREAD_A15_14),A15:A14
STDW .D2T2 B13:B12,*+B5(THREAD_B13_12)
|| LDDW .D1T1 *+A5(THREAD_A11_10),A11:A10
B .S2 B3 ; return in next E1
|| LDDW .D2T2 *+B4(THREAD_B13_12),B13:B12
LDDW .D2T2 *+B4(THREAD_B11_10),B11:B10
NOP
MV .L2X A0,B0
|| MV .S1 A6,A4
MVC .S2 B0,ILC
|| MV .L2X A1,B1
MVC .S2 B1,RILC
ENDPROC(__switch_to)

74
arch/c6x/kernel/sys_c6x.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <asm/syscalls.h>
#ifdef CONFIG_ACCESS_CHECK
int _access_ok(unsigned long addr, unsigned long size)
{
if (!size)
return 1;
if (!addr || addr > (0xffffffffUL - (size - 1)))
goto _bad_access;
if (segment_eq(get_fs(), KERNEL_DS))
return 1;
if (memory_start <= addr && (addr + size - 1) < memory_end)
return 1;
_bad_access:
pr_debug("Bad access attempt: pid[%d] addr[%08lx] size[0x%lx]\n",
current->pid, addr, size);
return 0;
}
EXPORT_SYMBOL(_access_ok);
#endif
/* sys_cache_sync -- sync caches over given range */
asmlinkage int sys_cache_sync(unsigned long s, unsigned long e)
{
L1D_cache_block_writeback_invalidate(s, e);
L1P_cache_block_invalidate(s, e);
return 0;
}
/* Provide the actual syscall number to call mapping. */
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
/*
* Use trampolines
*/
#define sys_pread64 sys_pread_c6x
#define sys_pwrite64 sys_pwrite_c6x
#define sys_truncate64 sys_truncate64_c6x
#define sys_ftruncate64 sys_ftruncate64_c6x
#define sys_fadvise64 sys_fadvise64_c6x
#define sys_fadvise64_64 sys_fadvise64_64_c6x
#define sys_fallocate sys_fallocate_c6x
/* Use sys_mmap_pgoff directly */
#define sys_mmap2 sys_mmap_pgoff
/*
* Note that we can't include <linux/unistd.h> here since the header
* guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
*/
void *sys_call_table[__NR_syscalls] = {
[0 ... __NR_syscalls-1] = sys_ni_syscall,
#include <asm/unistd.h>
};

65
arch/c6x/kernel/time.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/clocksource.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/profile.h>
#include <asm/timer64.h>
static u32 sched_clock_multiplier;
#define SCHED_CLOCK_SHIFT 16
static cycle_t tsc_read(struct clocksource *cs)
{
return get_cycles();
}
static struct clocksource clocksource_tsc = {
.name = "timestamp",
.rating = 300,
.read = tsc_read,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
/*
* scheduler clock - returns current time in nanoseconds.
*/
u64 sched_clock(void)
{
u64 tsc = get_cycles();
return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT;
}
void time_init(void)
{
u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT;
do_div(tmp, c6x_core_freq);
sched_clock_multiplier = tmp;
clocksource_register_hz(&clocksource_tsc, c6x_core_freq);
/* write anything into TSCL to enable counting */
set_creg(TSCL, 0);
/* probe for timer64 event timer */
timer64_init();
}

423
arch/c6x/kernel/traps.c Normal file
View File

@ -0,0 +1,423 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/ptrace.h>
#include <linux/kallsyms.h>
#include <linux/bug.h>
#include <asm/soc.h>
#include <asm/traps.h>
int (*c6x_nmi_handler)(struct pt_regs *regs);
void __init trap_init(void)
{
ack_exception(EXCEPT_TYPE_NXF);
ack_exception(EXCEPT_TYPE_EXC);
ack_exception(EXCEPT_TYPE_IXF);
ack_exception(EXCEPT_TYPE_SXF);
enable_exception();
}
void show_regs(struct pt_regs *regs)
{
pr_err("\n");
pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp);
pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4);
pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0);
pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1);
pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2);
pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3);
pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4);
pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5);
pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6);
pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7);
pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8);
pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9);
pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10);
pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11);
pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12);
pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13);
pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp);
pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp);
pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16);
pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17);
pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18);
pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19);
pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20);
pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21);
pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22);
pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23);
pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24);
pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25);
pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26);
pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27);
pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28);
pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29);
pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30);
pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31);
}
void dump_stack(void)
{
unsigned long stack;
show_stack(current, &stack);
}
EXPORT_SYMBOL(dump_stack);
void die(char *str, struct pt_regs *fp, int nr)
{
console_verbose();
pr_err("%s: %08x\n", str, nr);
show_regs(fp);
pr_err("Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, (PAGE_SIZE +
(unsigned long) current));
dump_stack();
while (1)
;
}
static void die_if_kernel(char *str, struct pt_regs *fp, int nr)
{
if (user_mode(fp))
return;
die(str, fp, nr);
}
/* Internal exceptions */
static struct exception_info iexcept_table[10] = {
{ "Oops - instruction fetch", SIGBUS, BUS_ADRERR },
{ "Oops - fetch packet", SIGBUS, BUS_ADRERR },
{ "Oops - execute packet", SIGILL, ILL_ILLOPC },
{ "Oops - undefined instruction", SIGILL, ILL_ILLOPC },
{ "Oops - resource conflict", SIGILL, ILL_ILLOPC },
{ "Oops - resource access", SIGILL, ILL_PRVREG },
{ "Oops - privilege", SIGILL, ILL_PRVOPC },
{ "Oops - loops buffer", SIGILL, ILL_ILLOPC },
{ "Oops - software exception", SIGILL, ILL_ILLTRP },
{ "Oops - unknown exception", SIGILL, ILL_ILLOPC }
};
/* External exceptions */
static struct exception_info eexcept_table[128] = {
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - external exception", SIGBUS, BUS_ADRERR },
{ "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
{ "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
{ "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR },
{ "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
{ "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR },
{ "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
{ "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR },
{ "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR },
{ "Oops - EMC bus error", SIGBUS, BUS_ADRERR }
};
static void do_trap(struct exception_info *except_info, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
siginfo_t info;
if (except_info->code != TRAP_BRKPT)
pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n",
except_info->kernel_str, regs->pc,
except_info->signo, except_info->code);
die_if_kernel(except_info->kernel_str, regs, addr);
info.si_signo = except_info->signo;
info.si_errno = 0;
info.si_code = except_info->code;
info.si_addr = (void __user *)addr;
force_sig_info(except_info->signo, &info, current);
}
/*
* Process an internal exception (non maskable)
*/
static int process_iexcept(struct pt_regs *regs)
{
unsigned int iexcept_report = get_iexcept();
unsigned int iexcept_num;
ack_exception(EXCEPT_TYPE_IXF);
pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc);
while (iexcept_report) {
iexcept_num = __ffs(iexcept_report);
iexcept_report &= ~(1 << iexcept_num);
set_iexcept(iexcept_report);
if (*(unsigned int *)regs->pc == BKPT_OPCODE) {
/* This is a breakpoint */
struct exception_info bkpt_exception = {
"Oops - undefined instruction",
SIGTRAP, TRAP_BRKPT
};
do_trap(&bkpt_exception, regs);
iexcept_report &= ~(0xFF);
set_iexcept(iexcept_report);
continue;
}
do_trap(&iexcept_table[iexcept_num], regs);
}
return 0;
}
/*
* Process an external exception (maskable)
*/
static void process_eexcept(struct pt_regs *regs)
{
int evt;
pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc);
while ((evt = soc_get_exception()) >= 0)
do_trap(&eexcept_table[evt], regs);
ack_exception(EXCEPT_TYPE_EXC);
}
/*
* Main exception processing
*/
asmlinkage int process_exception(struct pt_regs *regs)
{
unsigned int type;
unsigned int type_num;
unsigned int ie_num = 9; /* default is unknown exception */
while ((type = get_except_type()) != 0) {
type_num = fls(type) - 1;
switch (type_num) {
case EXCEPT_TYPE_NXF:
ack_exception(EXCEPT_TYPE_NXF);
if (c6x_nmi_handler)
(c6x_nmi_handler)(regs);
else
pr_alert("NMI interrupt!\n");
break;
case EXCEPT_TYPE_IXF:
if (process_iexcept(regs))
return 1;
break;
case EXCEPT_TYPE_EXC:
process_eexcept(regs);
break;
case EXCEPT_TYPE_SXF:
ie_num = 8;
default:
ack_exception(type_num);
do_trap(&iexcept_table[ie_num], regs);
break;
}
}
return 0;
}
static int kstack_depth_to_print = 48;
static void show_trace(unsigned long *stack, unsigned long *endstack)
{
unsigned long addr;
int i;
pr_debug("Call trace:");
i = 0;
while (stack + 1 <= endstack) {
addr = *stack++;
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* memory, it *may* be the address of a calling
* routine; if so, print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
if (__kernel_text_address(addr)) {
#ifndef CONFIG_KALLSYMS
if (i % 5 == 0)
pr_debug("\n ");
#endif
pr_debug(" [<%08lx>]", addr);
print_symbol(" %s\n", addr);
i++;
}
}
pr_debug("\n");
}
void show_stack(struct task_struct *task, unsigned long *stack)
{
unsigned long *p, *endstack;
int i;
if (!stack) {
if (task && task != current)
/* We know this is a kernel stack,
so this is the start/end */
stack = (unsigned long *)thread_saved_ksp(task);
else
stack = (unsigned long *)&stack;
}
endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1)
& -THREAD_SIZE);
pr_debug("Stack from %08lx:", (unsigned long)stack);
for (i = 0, p = stack; i < kstack_depth_to_print; i++) {
if (p + 1 > endstack)
break;
if (i % 8 == 0)
pr_cont("\n ");
pr_cont(" %08lx", *p++);
}
pr_cont("\n");
show_trace(stack, endstack);
}
int is_valid_bugaddr(unsigned long addr)
{
return __kernel_text_address(addr);
}

81
arch/c6x/kernel/vectors.S Normal file
View File

@ -0,0 +1,81 @@
;
; Port on Texas Instruments TMS320C6x architecture
;
; Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as
; published by the Free Software Foundation.
;
; This section handles all the interrupt vector routines.
; At RESET the processor sets up the DRAM timing parameters and
; branches to the label _c_int00 which handles initialization for the C code.
;
#define ALIGNMENT 5
.macro IRQVEC name, handler
.align ALIGNMENT
.hidden \name
.global \name
\name:
#ifdef CONFIG_C6X_BIG_KERNEL
STW .D2T1 A0,*B15--[2]
|| MVKL .S1 \handler,A0
MVKH .S1 \handler,A0
B .S2X A0
LDW .D2T1 *++B15[2],A0
NOP 4
NOP
NOP
.endm
#else /* CONFIG_C6X_BIG_KERNEL */
B .S2 \handler
NOP
NOP
NOP
NOP
NOP
NOP
NOP
.endm
#endif /* CONFIG_C6X_BIG_KERNEL */
.sect ".vectors","ax"
.align ALIGNMENT
.global RESET
.hidden RESET
RESET:
#ifdef CONFIG_C6X_BIG_KERNEL
MVKL .S1 _c_int00,A0 ; branch to _c_int00
MVKH .S1 _c_int00,A0
B .S2X A0
#else
B .S2 _c_int00
NOP
NOP
#endif
NOP
NOP
NOP
NOP
NOP
IRQVEC NMI,_nmi_handler ; NMI interrupt
IRQVEC AINT,_bad_interrupt ; reserved
IRQVEC MSGINT,_bad_interrupt ; reserved
IRQVEC INT4,_int4_handler
IRQVEC INT5,_int5_handler
IRQVEC INT6,_int6_handler
IRQVEC INT7,_int7_handler
IRQVEC INT8,_int8_handler
IRQVEC INT9,_int9_handler
IRQVEC INT10,_int10_handler
IRQVEC INT11,_int11_handler
IRQVEC INT12,_int12_handler
IRQVEC INT13,_int13_handler
IRQVEC INT14,_int14_handler
IRQVEC INT15,_int15_handler

View File

@ -0,0 +1,162 @@
/*
* ld script for the c6x kernel
*
* Copyright (C) 2010, 2011 Texas Instruments Incorporated
* Mark Salter <msalter@redhat.com>
*/
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
#include <asm/page.h>
ENTRY(_c_int00)
#if defined(CONFIG_CPU_BIG_ENDIAN)
jiffies = jiffies_64 + 4;
#else
jiffies = jiffies_64;
#endif
#define READONLY_SEGMENT_START \
. = PAGE_OFFSET;
#define READWRITE_SEGMENT_START \
. = ALIGN(128); \
_data_lma = .;
SECTIONS
{
/*
* Start kernel read only segment
*/
READONLY_SEGMENT_START
.vectors :
{
_vectors_start = .;
*(.vectors)
. = ALIGN(0x400);
_vectors_end = .;
}
. = ALIGN(0x1000);
.cmdline :
{
*(.cmdline)
}
/*
* This section contains data which may be shared with other
* cores. It needs to be a fixed offset from PAGE_OFFSET
* regardless of kernel configuration.
*/
.virtio_ipc_dev :
{
*(.virtio_ipc_dev)
}
. = ALIGN(PAGE_SIZE);
.init :
{
_stext = .;
_sinittext = .;
HEAD_TEXT
INIT_TEXT
_einittext = .;
}
__init_begin = _stext;
INIT_DATA_SECTION(16)
PERCPU_SECTION(128)
. = ALIGN(PAGE_SIZE);
__init_end = .;
.text :
{
_text = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
IRQENTRY_TEXT
KPROBES_TEXT
*(.fixup)
*(.gnu.warning)
}
EXCEPTION_TABLE(16)
NOTES
RO_DATA_SECTION(PAGE_SIZE)
.const :
{
*(.const .const.* .gnu.linkonce.r.*)
*(.switch)
}
. = ALIGN (8) ;
__fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET)
{
_fdt_start = . ; /* place for fdt blob */
*(__fdt_blob) ; /* Any link-placed DTB */
BYTE(0); /* section always has contents */
. = _fdt_start + 0x4000; /* Pad up to 16kbyte */
_fdt_end = . ;
}
_etext = .;
/*
* Start kernel read-write segment.
*/
READWRITE_SEGMENT_START
_sdata = .;
.fardata : AT(ADDR(.fardata) - LOAD_OFFSET)
{
INIT_TASK_DATA(THREAD_SIZE)
NOSAVE_DATA
PAGE_ALIGNED_DATA(PAGE_SIZE)
CACHELINE_ALIGNED_DATA(128)
READ_MOSTLY_DATA(128)
DATA_DATA
CONSTRUCTORS
*(.data1)
*(.fardata .fardata.*)
*(.data.debug_bpt)
}
.neardata ALIGN(8) : AT(ADDR(.neardata) - LOAD_OFFSET)
{
*(.neardata2 .neardata2.* .gnu.linkonce.s2.*)
*(.neardata .neardata.* .gnu.linkonce.s.*)
. = ALIGN(8);
}
_edata = .;
__bss_start = .;
SBSS(8)
BSS(8)
.far :
{
. = ALIGN(8);
*(.dynfar)
*(.far .far.* .gnu.linkonce.b.*)
. = ALIGN(8);
}
__bss_stop = .;
_end = .;
DWARF_DEBUG
/DISCARD/ :
{
EXIT_TEXT
EXIT_DATA
EXIT_CALL
*(.discard)
*(.discard.*)
*(.interp)
}
}

7
arch/c6x/lib/Makefile Normal file
View File

@ -0,0 +1,7 @@
#
# Makefile for arch/c6x/lib/
#
lib-y := divu.o divi.o pop_rts.o push_rts.o remi.o remu.o strasgi.o llshru.o
lib-y += llshr.o llshl.o negll.o mpyll.o divremi.o divremu.o
lib-y += checksum.o csum_64plus.o memcpy_64plus.o strasgi_64plus.o

36
arch/c6x/lib/checksum.c Normal file
View File

@ -0,0 +1,36 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <net/checksum.h>
#include <asm/byteorder.h>
/*
* copy from fs while checksumming, otherwise like csum_partial
*/
__wsum
csum_partial_copy_from_user(const void __user *src, void *dst, int len,
__wsum sum, int *csum_err)
{
int missing;
missing = __copy_from_user(dst, src, len);
if (missing) {
memset(dst + len - missing, 0, missing);
*csum_err = -EFAULT;
} else
*csum_err = 0;
return csum_partial(dst, len, sum);
}
EXPORT_SYMBOL(csum_partial_copy_from_user);
/* These are from csum_64plus.S */
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy);
EXPORT_SYMBOL(ip_compute_csum);
EXPORT_SYMBOL(ip_fast_csum);

419
arch/c6x/lib/csum_64plus.S Normal file
View File

@ -0,0 +1,419 @@
;
; linux/arch/c6x/lib/csum_64plus.s
;
; Port on Texas Instruments TMS320C6x architecture
;
; Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated
; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as
; published by the Free Software Foundation.
;
#include <linux/linkage.h>
;
;unsigned int csum_partial_copy(const char *src, char * dst,
; int len, int sum)
;
; A4: src
; B4: dst
; A6: len
; B6: sum
; return csum in A4
;
.text
ENTRY(csum_partial_copy)
MVC .S2 ILC,B30
MV .D1X B6,A31 ; given csum
ZERO .D1 A9 ; csum (a side)
|| ZERO .D2 B9 ; csum (b side)
|| SHRU .S2X A6,2,B5 ; len / 4
;; Check alignment and size
AND .S1 3,A4,A1
|| AND .S2 3,B4,B0
OR .L2X B0,A1,B0 ; non aligned condition
|| MVC .S2 B5,ILC
|| MVK .D2 1,B2
|| MV .D1X B5,A1 ; words condition
[!A1] B .S1 L8
[B0] BNOP .S1 L6,5
SPLOOP 1
;; Main loop for aligned words
LDW .D1T1 *A4++,A7
NOP 4
MV .S2X A7,B7
|| EXTU .S1 A7,0,16,A16
STW .D2T2 B7,*B4++
|| MPYU .M2 B7,B2,B8
|| ADD .L1 A16,A9,A9
NOP
SPKERNEL 8,0
|| ADD .L2 B8,B9,B9
ZERO .D1 A1
|| ADD .L1X A9,B9,A9 ; add csum from a and b sides
L6:
[!A1] BNOP .S1 L8,5
;; Main loop for non-aligned words
SPLOOP 2
|| MVK .L1 1,A2
LDNW .D1T1 *A4++,A7
NOP 3
NOP
MV .S2X A7,B7
|| EXTU .S1 A7,0,16,A16
|| MPYU .M1 A7,A2,A8
ADD .L1 A16,A9,A9
SPKERNEL 6,0
|| STNW .D2T2 B7,*B4++
|| ADD .L1 A8,A9,A9
L8: AND .S2X 2,A6,B5
CMPGT .L2 B5,0,B0
[!B0] BNOP .S1 L82,4
;; Manage half-word
ZERO .L1 A7
|| ZERO .D1 A8
#ifdef CONFIG_CPU_BIG_ENDIAN
LDBU .D1T1 *A4++,A7
LDBU .D1T1 *A4++,A8
NOP 3
SHL .S1 A7,8,A0
ADD .S1 A8,A9,A9
STB .D2T1 A7,*B4++
|| ADD .S1 A0,A9,A9
STB .D2T1 A8,*B4++
#else
LDBU .D1T1 *A4++,A7
LDBU .D1T1 *A4++,A8
NOP 3
ADD .S1 A7,A9,A9
SHL .S1 A8,8,A0
STB .D2T1 A7,*B4++
|| ADD .S1 A0,A9,A9
STB .D2T1 A8,*B4++
#endif
;; Manage eventually the last byte
L82: AND .S2X 1,A6,B0
[!B0] BNOP .S1 L9,5
|| ZERO .L1 A7
L83: LDBU .D1T1 *A4++,A7
NOP 4
MV .L2X A7,B7
#ifdef CONFIG_CPU_BIG_ENDIAN
STB .D2T2 B7,*B4++
|| SHL .S1 A7,8,A7
ADD .S1 A7,A9,A9
#else
STB .D2T2 B7,*B4++
|| ADD .S1 A7,A9,A9
#endif
;; Fold the csum
L9: SHRU .S2X A9,16,B0
[!B0] BNOP .S1 L10,5
L91: SHRU .S2X A9,16,B4
|| EXTU .S1 A9,16,16,A3
ADD .D1X A3,B4,A9
SHRU .S1 A9,16,A0
[A0] BNOP .S1 L91,5
L10: ADD .D1 A31,A9,A9
MV .D1 A9,A4
BNOP .S2 B3,4
MVC .S2 B30,ILC
ENDPROC(csum_partial_copy)
;
;unsigned short
;ip_fast_csum(unsigned char *iph, unsigned int ihl)
;{
; unsigned int checksum = 0;
; unsigned short *tosum = (unsigned short *) iph;
; int len;
;
; len = ihl*4;
;
; if (len <= 0)
; return 0;
;
; while(len) {
; len -= 2;
; checksum += *tosum++;
; }
; if (len & 1)
; checksum += *(unsigned char*) tosum;
;
; while(checksum >> 16)
; checksum = (checksum & 0xffff) + (checksum >> 16);
;
; return ~checksum;
;}
;
; A4: iph
; B4: ihl
; return checksum in A4
;
.text
ENTRY(ip_fast_csum)
ZERO .D1 A5
|| MVC .S2 ILC,B30
SHL .S2 B4,2,B0
CMPGT .L2 B0,0,B1
[!B1] BNOP .S1 L15,4
[!B1] ZERO .D1 A3
[!B0] B .S1 L12
SHRU .S2 B0,1,B0
MVC .S2 B0,ILC
NOP 3
SPLOOP 1
LDHU .D1T1 *A4++,A3
NOP 3
NOP
SPKERNEL 5,0
|| ADD .L1 A3,A5,A5
L12: SHRU .S1 A5,16,A0
[!A0] BNOP .S1 L14,5
L13: SHRU .S2X A5,16,B4
EXTU .S1 A5,16,16,A3
ADD .D1X A3,B4,A5
SHRU .S1 A5,16,A0
[A0] BNOP .S1 L13,5
L14: NOT .D1 A5,A3
EXTU .S1 A3,16,16,A3
L15: BNOP .S2 B3,3
MVC .S2 B30,ILC
MV .D1 A3,A4
ENDPROC(ip_fast_csum)
;
;unsigned short
;do_csum(unsigned char *buff, unsigned int len)
;{
; int odd, count;
; unsigned int result = 0;
;
; if (len <= 0)
; goto out;
; odd = 1 & (unsigned long) buff;
; if (odd) {
;#ifdef __LITTLE_ENDIAN
; result += (*buff << 8);
;#else
; result = *buff;
;#endif
; len--;
; buff++;
; }
; count = len >> 1; /* nr of 16-bit words.. */
; if (count) {
; if (2 & (unsigned long) buff) {
; result += *(unsigned short *) buff;
; count--;
; len -= 2;
; buff += 2;
; }
; count >>= 1; /* nr of 32-bit words.. */
; if (count) {
; unsigned int carry = 0;
; do {
; unsigned int w = *(unsigned int *) buff;
; count--;
; buff += 4;
; result += carry;
; result += w;
; carry = (w > result);
; } while (count);
; result += carry;
; result = (result & 0xffff) + (result >> 16);
; }
; if (len & 2) {
; result += *(unsigned short *) buff;
; buff += 2;
; }
; }
; if (len & 1)
;#ifdef __LITTLE_ENDIAN
; result += *buff;
;#else
; result += (*buff << 8);
;#endif
; result = (result & 0xffff) + (result >> 16);
; /* add up carry.. */
; result = (result & 0xffff) + (result >> 16);
; if (odd)
; result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
;out:
; return result;
;}
;
; A4: buff
; B4: len
; return checksum in A4
;
ENTRY(do_csum)
CMPGT .L2 B4,0,B0
[!B0] BNOP .S1 L26,3
EXTU .S1 A4,31,31,A0
MV .L1 A0,A3
|| MV .S1X B3,A5
|| MV .L2 B4,B3
|| ZERO .D1 A1
#ifdef CONFIG_CPU_BIG_ENDIAN
[A0] SUB .L2 B3,1,B3
|| [A0] LDBU .D1T1 *A4++,A1
#else
[!A0] BNOP .S1 L21,5
|| [A0] LDBU .D1T1 *A4++,A0
SUB .L2 B3,1,B3
|| SHL .S1 A0,8,A1
L21:
#endif
SHR .S2 B3,1,B0
[!B0] BNOP .S1 L24,3
MVK .L1 2,A0
AND .L1 A4,A0,A0
[!A0] BNOP .S1 L22,5
|| [A0] LDHU .D1T1 *A4++,A0
SUB .L2 B0,1,B0
|| SUB .S2 B3,2,B3
|| ADD .L1 A0,A1,A1
L22:
SHR .S2 B0,1,B0
|| ZERO .L1 A0
[!B0] BNOP .S1 L23,5
|| [B0] MVC .S2 B0,ILC
SPLOOP 3
SPMASK L1
|| MV .L1 A1,A2
|| LDW .D1T1 *A4++,A1
NOP 4
ADD .L1 A0,A1,A0
ADD .L1 A2,A0,A2
SPKERNEL 1,2
|| CMPGTU .L1 A1,A2,A0
ADD .L1 A0,A2,A6
EXTU .S1 A6,16,16,A7
SHRU .S2X A6,16,B0
NOP 1
ADD .L1X A7,B0,A1
L23:
MVK .L2 2,B0
AND .L2 B3,B0,B0
[B0] LDHU .D1T1 *A4++,A0
NOP 4
[B0] ADD .L1 A0,A1,A1
L24:
EXTU .S2 B3,31,31,B0
#ifdef CONFIG_CPU_BIG_ENDIAN
[!B0] BNOP .S1 L25,4
|| [B0] LDBU .D1T1 *A4,A0
SHL .S1 A0,8,A0
ADD .L1 A0,A1,A1
L25:
#else
[B0] LDBU .D1T1 *A4,A0
NOP 4
[B0] ADD .L1 A0,A1,A1
#endif
EXTU .S1 A1,16,16,A0
SHRU .S2X A1,16,B0
NOP 1
ADD .L1X A0,B0,A0
SHRU .S1 A0,16,A1
ADD .L1 A0,A1,A0
EXTU .S1 A0,16,16,A1
EXTU .S1 A1,16,24,A2
EXTU .S1 A1,24,16,A0
|| MV .L2X A3,B0
[B0] OR .L1 A0,A2,A1
L26:
NOP 1
BNOP .S2X A5,4
MV .L1 A1,A4
ENDPROC(do_csum)
;__wsum csum_partial(const void *buff, int len, __wsum wsum)
;{
; unsigned int sum = (__force unsigned int)wsum;
; unsigned int result = do_csum(buff, len);
;
; /* add in old sum, and carry.. */
; result += sum;
; if (sum > result)
; result += 1;
; return (__force __wsum)result;
;}
;
ENTRY(csum_partial)
MV .L1X B3,A9
|| CALLP .S2 do_csum,B3
|| MV .S1 A6,A8
BNOP .S2X A9,2
ADD .L1 A8,A4,A1
CMPGTU .L1 A8,A1,A0
ADD .L1 A1,A0,A4
ENDPROC(csum_partial)
;unsigned short
;ip_compute_csum(unsigned char *buff, unsigned int len)
;
; A4: buff
; B4: len
; return checksum in A4
ENTRY(ip_compute_csum)
MV .L1X B3,A9
|| CALLP .S2 do_csum,B3
BNOP .S2X A9,3
NOT .S1 A4,A4
CLR .S1 A4,16,31,A4
ENDPROC(ip_compute_csum)

53
arch/c6x/lib/divi.S Normal file
View File

@ -0,0 +1,53 @@
;; Copyright 2010 Free Software Foundation, Inc.
;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <linux/linkage.h>
;; ABI considerations for the divide functions
;; The following registers are call-used:
;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
;;
;; In our implementation, divu and remu are leaf functions,
;; while both divi and remi call into divu.
;; A0 is not clobbered by any of the functions.
;; divu does not clobber B2 either, which is taken advantage of
;; in remi.
;; divi uses B5 to hold the original return address during
;; the call to divu.
;; remi uses B2 and A5 to hold the input values during the
;; call to divu. It stores B3 in on the stack.
.text
ENTRY(__c6xabi_divi)
call .s2 __c6xabi_divu
|| mv .d2 B3, B5
|| cmpgt .l1 0, A4, A1
|| cmpgt .l2 0, B4, B1
[A1] neg .l1 A4, A4
|| [B1] neg .l2 B4, B4
|| xor .s1x A1, B1, A1
[A1] addkpc .s2 _divu_ret, B3, 4
_divu_ret:
neg .l1 A4, A4
|| mv .l2 B3,B5
|| ret .s2 B5
nop 5
ENDPROC(__c6xabi_divi)

46
arch/c6x/lib/divremi.S Normal file
View File

@ -0,0 +1,46 @@
;; Copyright 2010 Free Software Foundation, Inc.
;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <linux/linkage.h>
.text
ENTRY(__c6xabi_divremi)
stw .d2t2 B3, *B15--[2]
|| cmpgt .l1 0, A4, A1
|| cmpgt .l2 0, B4, B2
|| mv .s1 A4, A5
|| call .s2 __c6xabi_divu
[A1] neg .l1 A4, A4
|| [B2] neg .l2 B4, B4
|| xor .s2x B2, A1, B0
|| mv .d2 B4, B2
[B0] addkpc .s2 _divu_ret_1, B3, 1
[!B0] addkpc .s2 _divu_ret_2, B3, 1
nop 2
_divu_ret_1:
neg .l1 A4, A4
_divu_ret_2:
ldw .d2t2 *++B15[2], B3
mpy32 .m1x A4, B2, A6
nop 3
ret .s2 B3
sub .l1 A5, A6, A5
nop 4
ENDPROC(__c6xabi_divremi)

87
arch/c6x/lib/divremu.S Normal file
View File

@ -0,0 +1,87 @@
;; Copyright 2011 Free Software Foundation, Inc.
;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <linux/linkage.h>
.text
ENTRY(__c6xabi_divremu)
;; We use a series of up to 31 subc instructions. First, we find
;; out how many leading zero bits there are in the divisor. This
;; gives us both a shift count for aligning (shifting) the divisor
;; to the, and the number of times we have to execute subc.
;; At the end, we have both the remainder and most of the quotient
;; in A4. The top bit of the quotient is computed first and is
;; placed in A2.
;; Return immediately if the dividend is zero. Setting B4 to 1
;; is a trick to allow us to leave the following insns in the jump
;; delay slot without affecting the result.
mv .s2x A4, B1
[b1] lmbd .l2 1, B4, B1
||[!b1] b .s2 B3 ; RETURN A
||[!b1] mvk .d2 1, B4
||[!b1] zero .s1 A5
mv .l1x B1, A6
|| shl .s2 B4, B1, B4
;; The loop performs a maximum of 28 steps, so we do the
;; first 3 here.
cmpltu .l1x A4, B4, A2
[!A2] sub .l1x A4, B4, A4
|| shru .s2 B4, 1, B4
|| xor .s1 1, A2, A2
shl .s1 A2, 31, A2
|| [b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
;; RETURN A may happen here (note: must happen before the next branch)
__divremu0:
cmpgt .l2 B1, 7, B0
|| [b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
|| [b0] b .s1 __divremu0
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
[b1] subc .l1x A4,B4,A4
|| [b1] add .s2 -1, B1, B1
;; loop backwards branch happens here
ret .s2 B3
|| mvk .s1 32, A1
sub .l1 A1, A6, A6
|| extu .s1 A4, A6, A5
shl .s1 A4, A6, A4
shru .s1 A4, 1, A4
|| sub .l1 A6, 1, A6
or .l1 A2, A4, A4
shru .s1 A4, A6, A4
nop
ENDPROC(__c6xabi_divremu)

98
arch/c6x/lib/divu.S Normal file
View File

@ -0,0 +1,98 @@
;; Copyright 2010 Free Software Foundation, Inc.
;; Contributed by Bernd Schmidt <bernds@codesourcery.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <linux/linkage.h>
;; ABI considerations for the divide functions
;; The following registers are call-used:
;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5
;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4
;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4
;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4
;;
;; In our implementation, divu and remu are leaf functions,
;; while both divi and remi call into divu.
;; A0 is not clobbered by any of the functions.
;; divu does not clobber B2 either, which is taken advantage of
;; in remi.
;; divi uses B5 to hold the original return address during
;; the call to divu.
;; remi uses B2 and A5 to hold the input values during the
;; call to divu. It stores B3 in on the stack.
.text
ENTRY(__c6xabi_divu)
;; We use a series of up to 31 subc instructions. First, we find
;; out how many leading zero bits there are in the divisor. This
;; gives us both a shift count for aligning (shifting) the divisor
;; to the, and the number of times we have to execute subc.
;; At the end, we have both the remainder and most of the quotient
;; in A4. The top bit of the quotient is computed first and is
;; placed in A2.
;; Return immediately if the dividend is zero.
mv .s2x A4, B1
[B1] lmbd .l2 1, B4, B1
|| [!B1] b .s2 B3 ; RETURN A
|| [!B1] mvk .d2 1, B4
mv .l1x B1, A6
|| shl .s2 B4, B1, B4
;; The loop performs a maximum of 28 steps, so we do the
;; first 3 here.
cmpltu .l1x A4, B4, A2
[!A2] sub .l1x A4, B4, A4
|| shru .s2 B4, 1, B4
|| xor .s1 1, A2, A2
shl .s1 A2, 31, A2
|| [B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
;; RETURN A may happen here (note: must happen before the next branch)
_divu_loop:
cmpgt .l2 B1, 7, B0
|| [B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
|| [B0] b .s1 _divu_loop
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
[B1] subc .l1x A4,B4,A4
|| [B1] add .s2 -1, B1, B1
;; loop backwards branch happens here
ret .s2 B3
|| mvk .s1 32, A1
sub .l1 A1, A6, A6
shl .s1 A4, A6, A4
shru .s1 A4, 1, A4
|| sub .l1 A6, 1, A6
or .l1 A2, A4, A4
shru .s1 A4, A6, A4
nop
ENDPROC(__c6xabi_divu)

37
arch/c6x/lib/llshl.S Normal file
View File

@ -0,0 +1,37 @@
;; Copyright (C) 2010 Texas Instruments Incorporated
;; Contributed by Mark Salter <msalter@redhat.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;; uint64_t __c6xabi_llshl(uint64_t val, uint shift)
#include <linux/linkage.h>
.text
ENTRY(__c6xabi_llshl)
mv .l1x B4,A1
[!A1] b .s2 B3 ; just return if zero shift
mvk .s1 32,A0
sub .d1 A0,A1,A0
cmplt .l1 0,A0,A2
[A2] shru .s1 A4,A0,A0
[!A2] neg .l1 A0,A5
|| [A2] shl .s1 A5,A1,A5
[!A2] shl .s1 A4,A5,A5
|| [A2] or .d1 A5,A0,A5
|| [!A2] mvk .l1 0,A4
[A2] shl .s1 A4,A1,A4
bnop .s2 B3,5
ENDPROC(__c6xabi_llshl)

38
arch/c6x/lib/llshr.S Normal file
View File

@ -0,0 +1,38 @@
;; Copyright (C) 2010 Texas Instruments Incorporated
;; Contributed by Mark Salter <msalter@redhat.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;; uint64_t __c6xabi_llshr(uint64_t val, uint shift)
#include <linux/linkage.h>
.text
ENTRY(__c6xabi_llshr)
mv .l1x B4,A1
[!A1] b .s2 B3 ; return if zero shift count
mvk .s1 32,A0
sub .d1 A0,A1,A0
cmplt .l1 0,A0,A2
[A2] shl .s1 A5,A0,A0
nop
[!A2] neg .l1 A0,A4
|| [A2] shru .s1 A4,A1,A4
[!A2] shr .s1 A5,A4,A4
|| [A2] or .d1 A4,A0,A4
[!A2] shr .s1 A5,0x1f,A5
[A2] shr .s1 A5,A1,A5
bnop .s2 B3,5
ENDPROC(__c6xabi_llshr)

38
arch/c6x/lib/llshru.S Normal file
View File

@ -0,0 +1,38 @@
;; Copyright (C) 2010 Texas Instruments Incorporated
;; Contributed by Mark Salter <msalter@redhat.com>.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;; uint64_t __c6xabi_llshru(uint64_t val, uint shift)
#include <linux/linkage.h>
.text
ENTRY(__c6xabi_llshru)
mv .l1x B4,A1
[!A1] b .s2 B3 ; return if zero shift count
mvk .s1 32,A0
sub .d1 A0,A1,A0
cmplt .l1 0,A0,A2
[A2] shl .s1 A5,A0,A0
nop
[!A2] neg .l1 A0,A4
|| [A2] shru .s1 A4,A1,A4
[!A2] shru .s1 A5,A4,A4
|| [A2] or .d1 A4,A0,A4
|| [!A2] mvk .l1 0,A5
[A2] shru .s1 A5,A1,A5
bnop .s2 B3,5
ENDPROC(__c6xabi_llshru)

View File

@ -0,0 +1,46 @@
; Port on Texas Instruments TMS320C6x architecture
;
; Copyright (C) 2006, 2009, 2010 Texas Instruments Incorporated
; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License version 2 as
; published by the Free Software Foundation.
;
#include <linux/linkage.h>
.text
ENTRY(memcpy)
AND .L1 0x1,A6,A0
|| AND .S1 0x2,A6,A1
|| AND .L2X 0x4,A6,B0
|| MV .D1 A4,A3
|| MVC .S2 ILC,B2
[A0] LDB .D2T1 *B4++,A5
[A1] LDB .D2T1 *B4++,A7
[A1] LDB .D2T1 *B4++,A8
[B0] LDNW .D2T1 *B4++,A9
|| SHRU .S2X A6,0x3,B1
[!B1] BNOP .S2 B3,1
[A0] STB .D1T1 A5,*A3++
||[B1] MVC .S2 B1,ILC
[A1] STB .D1T1 A7,*A3++
[A1] STB .D1T1 A8,*A3++
[B0] STNW .D1T1 A9,*A3++ ; return when len < 8
SPLOOP 2
LDNDW .D2T1 *B4++,A9:A8
NOP 3
NOP
SPKERNEL 0,0
|| STNDW .D1T1 A9:A8,*A3++
BNOP .S2 B3,4
MVC .S2 B2,ILC
ENDPROC(memcpy)

Some files were not shown because too many files have changed in this diff Show More