blackfin architecture
This adds support for the Analog Devices Blackfin processor architecture, and currently supports the BF533, BF532, BF531, BF537, BF536, BF534, and BF561 (Dual Core) devices, with a variety of development platforms including those avaliable from Analog Devices (BF533-EZKit, BF533-STAMP, BF537-STAMP, BF561-EZKIT), and Bluetechnix! Tinyboards. The Blackfin architecture was jointly developed by Intel and Analog Devices Inc. (ADI) as the Micro Signal Architecture (MSA) core and introduced it in December of 2000. Since then ADI has put this core into its Blackfin processor family of devices. The Blackfin core has the advantages of a clean, orthogonal,RISC-like microprocessor instruction set. It combines a dual-MAC (Multiply/Accumulate), state-of-the-art signal processing engine and single-instruction, multiple-data (SIMD) multimedia capabilities into a single instruction-set architecture. The Blackfin architecture, including the instruction set, is described by the ADSP-BF53x/BF56x Blackfin Processor Programming Reference http://blackfin.uclinux.org/gf/download/frsrelease/29/2549/Blackfin_PRM.pdf The Blackfin processor is already supported by major releases of gcc, and there are binary and source rpms/tarballs for many architectures at: http://blackfin.uclinux.org/gf/project/toolchain/frs There is complete documentation, including "getting started" guides available at: http://docs.blackfin.uclinux.org/ which provides links to the sources and patches you will need in order to set up a cross-compiling environment for bfin-linux-uclibc This patch, as well as the other patches (toolchain, distribution, uClibc) are actively supported by Analog Devices Inc, at: http://blackfin.uclinux.org/ We have tested this on LTP, and our test plan (including pass/fails) can be found at: http://docs.blackfin.uclinux.org/doku.php?id=testing_the_linux_kernel [m.kozlowski@tuxland.pl: balance parenthesis in blackfin header files] Signed-off-by: Bryan Wu <bryan.wu@analog.com> Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl> Signed-off-by: Aubrey Li <aubrey.li@analog.com> Signed-off-by: Jie Zhang <jie.zhang@analog.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
7324328446
commit
1394f03221
257 changed files with 47285 additions and 6 deletions
11
Documentation/blackfin/00-INDEX
Normal file
11
Documentation/blackfin/00-INDEX
Normal file
|
@ -0,0 +1,11 @@
|
|||
00-INDEX
|
||||
- This file
|
||||
|
||||
cache-lock.txt
|
||||
- HOWTO for blackfin cache locking.
|
||||
|
||||
cachefeatures.txt
|
||||
- Supported cache features.
|
||||
|
||||
Filesystems
|
||||
- Requirements for mounting the root file system.
|
169
Documentation/blackfin/Filesystems
Normal file
169
Documentation/blackfin/Filesystems
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* File: Documentation/blackfin/Filesystems
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: Filesystems 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
How to mount the root file system in uClinux/Blackfin
|
||||
-----------------------------------------------------
|
||||
|
||||
1 Mounting EXT3 File system.
|
||||
------------------------
|
||||
|
||||
Creating an EXT3 File system for uClinux/Blackfin:
|
||||
|
||||
|
||||
Please follow the steps to form the EXT3 File system and mount the same as root
|
||||
file system.
|
||||
|
||||
a Make an ext3 file system as large as you want the final root file
|
||||
system.
|
||||
|
||||
mkfs.ext3 /dev/ram0 <your-rootfs-size-in-1k-blocks>
|
||||
|
||||
b Mount this Empty file system on a free directory as:
|
||||
|
||||
mount -t ext3 /dev/ram0 ./test
|
||||
where ./test is the empty directory.
|
||||
|
||||
c Copy your root fs directory that you have so carefully made over.
|
||||
|
||||
cp -af /tmp/my_final_rootfs_files/* ./test
|
||||
|
||||
(For ex: cp -af uClinux-dist/romfs/* ./test)
|
||||
|
||||
d If you have done everything right till now you should be able to see
|
||||
the required "root" dir's (that's etc, root, bin, lib, sbin...)
|
||||
|
||||
e Now unmount the file system
|
||||
|
||||
umount ./test
|
||||
|
||||
f Create the root file system image.
|
||||
|
||||
dd if=/dev/ram0 bs=1k count=<your-rootfs-size-in-1k-blocks> \
|
||||
> ext3fs.img
|
||||
|
||||
|
||||
Now you have to tell the kernel that will be mounting this file system as
|
||||
rootfs.
|
||||
So do a make menuconfig under kernel and select the Ext3 journaling file system
|
||||
support under File system --> submenu.
|
||||
|
||||
|
||||
2. Mounting EXT2 File system.
|
||||
-------------------------
|
||||
|
||||
By default the ext2 file system image will be created if you invoke make from
|
||||
the top uClinux-dist directory.
|
||||
|
||||
|
||||
3. Mounting CRAMFS File System
|
||||
----------------------------
|
||||
|
||||
To create a CRAMFS file system image execute the command
|
||||
|
||||
mkfs.cramfs ./test cramfs.img
|
||||
|
||||
where ./test is the target directory.
|
||||
|
||||
|
||||
4. Mounting ROMFS File System
|
||||
--------------------------
|
||||
|
||||
To create a ROMFS file system image execute the command
|
||||
|
||||
genromfs -v -V "ROMdisk" -f romfs.img -d ./test
|
||||
|
||||
where ./test is the target directory
|
||||
|
||||
|
||||
5. Mounting the JFFS2 Filesystem
|
||||
-----------------------------
|
||||
|
||||
To create a compressed JFFS filesystem (JFFS2), please execute the command
|
||||
|
||||
mkfs.jffs2 -d ./test -o jffs2.img
|
||||
|
||||
where ./test is the target directory.
|
||||
|
||||
However, please make sure the following is in your kernel config.
|
||||
|
||||
/*
|
||||
* RAM/ROM/Flash chip drivers
|
||||
*/
|
||||
#define CONFIG_MTD_CFI 1
|
||||
#define CONFIG_MTD_ROM 1
|
||||
/*
|
||||
* Mapping drivers for chip access
|
||||
*/
|
||||
#define CONFIG_MTD_COMPLEX_MAPPINGS 1
|
||||
#define CONFIG_MTD_BF533 1
|
||||
#undef CONFIG_MTD_UCLINUX
|
||||
|
||||
Through the u-boot boot loader, use the jffs2.img in the corresponding
|
||||
partition made in linux-2.6.x/drivers/mtd/maps/bf533_flash.c.
|
||||
|
||||
NOTE - Currently the Flash driver is available only for EZKIT. Watch out for a
|
||||
STAMP driver soon.
|
||||
|
||||
|
||||
6. Mounting the NFS File system
|
||||
-----------------------------
|
||||
|
||||
For mounting the NFS please do the following in the kernel config.
|
||||
|
||||
In Networking Support --> Networking options --> TCP/IP networking -->
|
||||
IP: kernel level autoconfiguration
|
||||
|
||||
Enable BOOTP Support.
|
||||
|
||||
In Kernel hacking --> Compiled-in kernel boot parameter add the following
|
||||
|
||||
root=/dev/nfs rw ip=bootp
|
||||
|
||||
In File system --> Network File system, Enable
|
||||
|
||||
NFS file system support --> NFSv3 client support
|
||||
Root File system on NFS
|
||||
|
||||
in uClibc menuconfig, do the following
|
||||
In Networking Support
|
||||
enable Remote Procedure Call (RPC) support
|
||||
Full RPC Support
|
||||
|
||||
On the Host side, ensure that /etc/dhcpd.conf looks something like this
|
||||
|
||||
ddns-update-style ad-hoc;
|
||||
allow bootp;
|
||||
subnet 10.100.4.0 netmask 255.255.255.0 {
|
||||
default-lease-time 122209600;
|
||||
max-lease-time 31557600;
|
||||
group {
|
||||
host bf533 {
|
||||
hardware ethernet 00:CF:52:49:C3:01;
|
||||
fixed-address 10.100.4.50;
|
||||
option root-path "/home/nfsmount";
|
||||
}
|
||||
}
|
||||
|
||||
ensure that /etc/exports looks something like this
|
||||
/home/nfsmount *(rw,no_root_squash,no_all_squash)
|
||||
|
||||
run the following commands as root (may differ depending on your
|
||||
distribution) :
|
||||
- service nfs start
|
||||
- service portmap start
|
||||
- service dhcpd start
|
||||
- /usr/sbin/exportfs
|
48
Documentation/blackfin/cache-lock.txt
Normal file
48
Documentation/blackfin/cache-lock.txt
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* File: Documentation/blackfin/cache-lock.txt
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: cache-lock.txt 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
How to lock your code in cache in uClinux/blackfin
|
||||
--------------------------------------------------
|
||||
|
||||
There are only a few steps required to lock your code into the cache.
|
||||
Currently you can lock the code by Way.
|
||||
|
||||
Below are the interface provided for locking the cache.
|
||||
|
||||
|
||||
1. cache_grab_lock(int Ways);
|
||||
|
||||
This function grab the lock for locking your code into the cache specified
|
||||
by Ways.
|
||||
|
||||
|
||||
2. cache_lock(int Ways);
|
||||
|
||||
This function should be called after your critical code has been executed.
|
||||
Once the critical code exits, the code is now loaded into the cache. This
|
||||
function locks the code into the cache.
|
||||
|
||||
|
||||
So, the example sequence will be:
|
||||
|
||||
cache_grab_lock(WAY0_L); /* Grab the lock */
|
||||
|
||||
critical_code(); /* Execute the code of interest */
|
||||
|
||||
cache_lock(WAY0_L); /* Lock the cache */
|
||||
|
||||
Where WAY0_L signifies WAY0 locking.
|
65
Documentation/blackfin/cachefeatures.txt
Normal file
65
Documentation/blackfin/cachefeatures.txt
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* File: Documentation/blackfin/cachefeatures.txt
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Rev: $Id: cachefeatures.txt 2384 2006-11-01 04:12:43Z magicyang $
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
*/
|
||||
|
||||
- Instruction and Data cache initialization.
|
||||
icache_init();
|
||||
dcache_init();
|
||||
|
||||
- Instruction and Data cache Invalidation Routines, when flushing the
|
||||
same is not required.
|
||||
_icache_invalidate();
|
||||
_dcache_invalidate();
|
||||
|
||||
Also, for invalidating the entire instruction and data cache, the below
|
||||
routines are provided (another method for invalidation, refer page no 267 and 287 of
|
||||
ADSP-BF533 Hardware Reference manual)
|
||||
|
||||
invalidate_entire_dcache();
|
||||
invalidate_entire_icache();
|
||||
|
||||
-External Flushing of Instruction and data cache routines.
|
||||
|
||||
flush_instruction_cache();
|
||||
flush_data_cache();
|
||||
|
||||
- Internal Flushing of Instruction and Data Cache.
|
||||
|
||||
icplb_flush();
|
||||
dcplb_flush();
|
||||
|
||||
- Locking the cache.
|
||||
|
||||
cache_grab_lock();
|
||||
cache_lock();
|
||||
|
||||
Please refer linux-2.6.x/Documentation/blackfin/cache-lock.txt for how to
|
||||
lock the cache.
|
||||
|
||||
Locking the cache is optional feature.
|
||||
|
||||
- Miscellaneous cache functions.
|
||||
|
||||
flush_cache_all();
|
||||
flush_cache_mm();
|
||||
invalidate_dcache_range();
|
||||
flush_dcache_range();
|
||||
flush_dcache_page();
|
||||
flush_cache_range();
|
||||
flush_cache_page();
|
||||
invalidate_dcache_range();
|
||||
flush_page_to_ram();
|
||||
|
38
MAINTAINERS
38
MAINTAINERS
|
@ -700,6 +700,44 @@ P: Richard Purdie
|
|||
M: rpurdie@rpsys.net
|
||||
S: Maintained
|
||||
|
||||
BLACKFIN ARCHITECTURE
|
||||
P: Aubrey Li
|
||||
M: aubrey.li@analog.com
|
||||
P: Bernd Schmidt
|
||||
M: bernd.schmidt@analog.com
|
||||
P: Bryan Wu
|
||||
M: bryan.wu@analog.com
|
||||
P: Grace Pan
|
||||
M: grace.pan@analog.com
|
||||
P: Michael Hennerich
|
||||
M: michael.hennerich@analog.com
|
||||
P: Mike Frysinger
|
||||
M: michael.frysinger@analog.com
|
||||
P: Jane Lv
|
||||
M: jane.lv@analog.com
|
||||
P: Jerry Zeng
|
||||
M: jerry.zeng@analog.com
|
||||
P: Jie Zhang
|
||||
M: jie.zhang@analog.com
|
||||
P: Robin Getz
|
||||
M: robin.getz@analog.com
|
||||
P: Roy Huang
|
||||
M: roy.huang@analog.com
|
||||
P: Sonic Zhang
|
||||
M: sonic.zhang@analog.com
|
||||
P: Yi Li
|
||||
M: yi.li@analog.com
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
|
||||
BLACKFIN SERIAL DRIVER
|
||||
P: Aubrey Li
|
||||
M: aubrey.li@analog.com
|
||||
L: uclinux-dist-devel@blackfin.uclinux.org
|
||||
W: http://blackfin.uclinux.org
|
||||
S: Supported
|
||||
|
||||
BAYCOM/HDLCDRV DRIVERS FOR AX.25
|
||||
P: Thomas Sailer
|
||||
M: t.sailer@alumni.ethz.ch
|
||||
|
|
989
arch/blackfin/Kconfig
Normal file
989
arch/blackfin/Kconfig
Normal file
|
@ -0,0 +1,989 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see Documentation/kbuild/kconfig-language.txt.
|
||||
#
|
||||
|
||||
mainmenu "uClinux/Blackfin (w/o MMU) Kernel Configuration"
|
||||
|
||||
config MMU
|
||||
bool
|
||||
default n
|
||||
|
||||
config FPU
|
||||
bool
|
||||
default n
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
default y
|
||||
|
||||
config RWSEM_XCHGADD_ALGORITHM
|
||||
bool
|
||||
default n
|
||||
|
||||
config BLACKFIN
|
||||
bool
|
||||
default y
|
||||
|
||||
config BFIN
|
||||
bool
|
||||
default y
|
||||
|
||||
config SEMAPHORE_SLEEPERS
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_FIND_NEXT_BIT
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_HWEIGHT
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_HARDIRQS
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_IRQ_PROBE
|
||||
bool
|
||||
default y
|
||||
|
||||
config GENERIC_TIME
|
||||
bool
|
||||
default n
|
||||
|
||||
config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int
|
||||
default "14"
|
||||
|
||||
config GENERIC_CALIBRATE_DELAY
|
||||
bool
|
||||
default y
|
||||
|
||||
config IRQCHIP_DEMUX_GPIO
|
||||
bool
|
||||
default y
|
||||
|
||||
source "init/Kconfig"
|
||||
source "kernel/Kconfig.preempt"
|
||||
|
||||
menu "Blackfin Processor Options"
|
||||
|
||||
comment "Processor and Board Settings"
|
||||
|
||||
choice
|
||||
prompt "CPU"
|
||||
default BF533
|
||||
|
||||
config BF531
|
||||
bool "BF531"
|
||||
help
|
||||
BF531 Processor Support.
|
||||
|
||||
config BF532
|
||||
bool "BF532"
|
||||
help
|
||||
BF532 Processor Support.
|
||||
|
||||
config BF533
|
||||
bool "BF533"
|
||||
help
|
||||
BF533 Processor Support.
|
||||
|
||||
config BF534
|
||||
bool "BF534"
|
||||
help
|
||||
BF534 Processor Support.
|
||||
|
||||
config BF536
|
||||
bool "BF536"
|
||||
help
|
||||
BF536 Processor Support.
|
||||
|
||||
config BF537
|
||||
bool "BF537"
|
||||
help
|
||||
BF537 Processor Support.
|
||||
|
||||
config BF561
|
||||
bool "BF561"
|
||||
help
|
||||
Not Supported Yet - Work in progress - BF561 Processor Support.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Silicon Rev"
|
||||
default BF_REV_0_2 if BF537
|
||||
default BF_REV_0_3 if BF533
|
||||
|
||||
config BF_REV_0_2
|
||||
bool "0.2"
|
||||
depends on (BF537 || BF536 || BF534)
|
||||
|
||||
config BF_REV_0_3
|
||||
bool "0.3"
|
||||
depends on (BF561 || BF537 || BF536 || BF534 || BF533 || BF532 || BF531)
|
||||
|
||||
config BF_REV_0_4
|
||||
bool "0.4"
|
||||
depends on (BF561 || BF533 || BF532 || BF531)
|
||||
|
||||
config BF_REV_0_5
|
||||
bool "0.5"
|
||||
depends on (BF561 || BF533 || BF532 || BF531)
|
||||
|
||||
endchoice
|
||||
|
||||
config BFIN_DUAL_CORE
|
||||
bool
|
||||
depends on (BF561)
|
||||
default y
|
||||
|
||||
config BFIN_SINGLE_CORE
|
||||
bool
|
||||
depends on !BFIN_DUAL_CORE
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "System type"
|
||||
default BFIN533_STAMP
|
||||
help
|
||||
Do NOT change the board here. Please use the top level
|
||||
configuration to ensure that all the other settings are
|
||||
correct.
|
||||
|
||||
config BFIN533_EZKIT
|
||||
bool "BF533-EZKIT"
|
||||
depends on (BF533 || BF532 || BF531)
|
||||
help
|
||||
BF533-EZKIT-LITE board Support.
|
||||
|
||||
config BFIN533_STAMP
|
||||
bool "BF533-STAMP"
|
||||
depends on (BF533 || BF532 || BF531)
|
||||
help
|
||||
BF533-STAMP board Support.
|
||||
|
||||
config BFIN537_STAMP
|
||||
bool "BF537-STAMP"
|
||||
depends on (BF537 || BF536 || BF534)
|
||||
help
|
||||
BF537-STAMP board Support.
|
||||
|
||||
config BFIN533_BLUETECHNIX_CM
|
||||
bool "Bluetechnix CM-BF533"
|
||||
depends on (BF533)
|
||||
help
|
||||
CM-BF533 support for EVAL- and DEV-Board.
|
||||
|
||||
config BFIN537_BLUETECHNIX_CM
|
||||
bool "Bluetechnix CM-BF537"
|
||||
depends on (BF537)
|
||||
help
|
||||
CM-BF537 support for EVAL- and DEV-Board.
|
||||
|
||||
config BFIN561_BLUETECHNIX_CM
|
||||
bool "BF561-CM"
|
||||
depends on (BF561)
|
||||
help
|
||||
CM-BF561 support for EVAL- and DEV-Board.
|
||||
|
||||
config BFIN561_EZKIT
|
||||
bool "BF561-EZKIT"
|
||||
depends on (BF561)
|
||||
help
|
||||
BF561-EZKIT-LITE board Support.
|
||||
|
||||
config PNAV10
|
||||
bool "PNAV 1.0 board"
|
||||
depends on (BF537)
|
||||
help
|
||||
PNAV 1.0 board Support.
|
||||
|
||||
config GENERIC_BOARD
|
||||
bool "Custom"
|
||||
depends on (BF537 || BF536 \
|
||||
|| BF534 || BF561 || BF535 || BF533 || BF532 || BF531)
|
||||
help
|
||||
GENERIC or Custom board Support.
|
||||
|
||||
endchoice
|
||||
|
||||
config MEM_GENERIC_BOARD
|
||||
bool
|
||||
depends on GENERIC_BOARD
|
||||
default y
|
||||
|
||||
config MEM_MT48LC64M4A2FB_7E
|
||||
bool
|
||||
depends on (BFIN533_STAMP)
|
||||
default y
|
||||
|
||||
config MEM_MT48LC16M16A2TG_75
|
||||
bool
|
||||
depends on (BFIN533_EZKIT || BFIN561_EZKIT \
|
||||
|| BFIN533_BLUETECHNIX_CM || BFIN537_BLUETECHNIX_CM)
|
||||
default y
|
||||
|
||||
config MEM_MT48LC32M8A2_75
|
||||
bool
|
||||
depends on (BFIN537_STAMP || PNAV10)
|
||||
default y
|
||||
|
||||
config MEM_MT48LC8M32B2B5_7
|
||||
bool
|
||||
depends on (BFIN561_BLUETECHNIX_CM)
|
||||
default y
|
||||
|
||||
config BFIN_SHARED_FLASH_ENET
|
||||
bool
|
||||
depends on (BFIN533_STAMP)
|
||||
default y
|
||||
|
||||
source "arch/blackfin/mach-bf533/Kconfig"
|
||||
source "arch/blackfin/mach-bf561/Kconfig"
|
||||
source "arch/blackfin/mach-bf537/Kconfig"
|
||||
|
||||
menu "Board customizations"
|
||||
|
||||
config CMDLINE_BOOL
|
||||
bool "Default bootloader kernel arguments"
|
||||
|
||||
config CMDLINE
|
||||
string "Initial kernel command string"
|
||||
depends on CMDLINE_BOOL
|
||||
default "console=ttyBF0,57600"
|
||||
help
|
||||
If you don't have a boot loader capable of passing a command line string
|
||||
to the kernel, you may specify one here. As a minimum, you should specify
|
||||
the memory size and the root device (e.g., mem=8M, root=/dev/nfs).
|
||||
|
||||
comment "Board Setup"
|
||||
|
||||
config CLKIN_HZ
|
||||
int "Crystal Frequency in Hz"
|
||||
default "11059200" if BFIN533_STAMP
|
||||
default "27000000" if BFIN533_EZKIT
|
||||
default "25000000" if BFIN537_STAMP
|
||||
default "30000000" if BFIN561_EZKIT
|
||||
default "24576000" if PNAV10
|
||||
help
|
||||
The frequency of CLKIN crystal oscillator on the board in Hz.
|
||||
|
||||
config MEM_SIZE
|
||||
int "SDRAM Memory Size in MBytes"
|
||||
default 32 if BFIN533_EZKIT
|
||||
default 64 if BFIN537_STAMP
|
||||
default 64 if BFIN561_EZKIT
|
||||
default 128 if BFIN533_STAMP
|
||||
default 64 if PNAV10
|
||||
|
||||
config MEM_ADD_WIDTH
|
||||
int "SDRAM Memory Address Width"
|
||||
default 9 if BFIN533_EZKIT
|
||||
default 9 if BFIN561_EZKIT
|
||||
default 10 if BFIN537_STAMP
|
||||
default 11 if BFIN533_STAMP
|
||||
default 10 if PNAV10
|
||||
|
||||
config ENET_FLASH_PIN
|
||||
int "PF port/pin used for flash and ethernet sharing"
|
||||
depends on (BFIN533_STAMP)
|
||||
default 0
|
||||
help
|
||||
PF port/pin used for flash and ethernet sharing to allow other PF
|
||||
pins to be used on other platforms without having to touch common
|
||||
code.
|
||||
For example: PF0 --> 0,PF1 --> 1,PF2 --> 2, etc.
|
||||
|
||||
config BOOT_LOAD
|
||||
hex "Kernel load address for booting"
|
||||
default "0x1000"
|
||||
help
|
||||
This option allows you to set the load address of the kernel.
|
||||
This can be useful if you are on a board which has a small amount
|
||||
of memory or you wish to reserve some memory at the beginning of
|
||||
the address space.
|
||||
|
||||
Note that you generally want to keep this value at or above 4k
|
||||
(0x1000) as this will allow the kernel to capture NULL pointer
|
||||
references.
|
||||
|
||||
comment "LED Status Indicators"
|
||||
depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
|
||||
|
||||
config BFIN_ALIVE_LED
|
||||
bool "Enable Board Alive"
|
||||
depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
|
||||
default n
|
||||
help
|
||||
Blink the LEDs you select when the kernel is running. Helps detect
|
||||
a hung kernel.
|
||||
|
||||
config BFIN_ALIVE_LED_NUM
|
||||
int "LED"
|
||||
depends on BFIN_ALIVE_LED
|
||||
range 1 3 if BFIN533_STAMP
|
||||
default "3" if BFIN533_STAMP
|
||||
help
|
||||
Select the LED (marked on the board) for you to blink.
|
||||
|
||||
config BFIN_IDLE_LED
|
||||
bool "Enable System Load/Idle LED"
|
||||
depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
|
||||
default n
|
||||
help
|
||||
Blinks the LED you select when to determine kernel load.
|
||||
|
||||
config BFIN_IDLE_LED_NUM
|
||||
int "LED"
|
||||
depends on BFIN_IDLE_LED
|
||||
range 1 3 if BFIN533_STAMP
|
||||
default "2" if BFIN533_STAMP
|
||||
help
|
||||
Select the LED (marked on the board) for you to blink.
|
||||
|
||||
#
|
||||
# Sorry - but you need to put the hex address here -
|
||||
#
|
||||
|
||||
# Flag Data register
|
||||
config BFIN_ALIVE_LED_PORT
|
||||
hex
|
||||
default 0xFFC00700 if (BFIN533_STAMP)
|
||||
|
||||
# Peripheral Flag Direction Register
|
||||
config BFIN_ALIVE_LED_DPORT
|
||||
hex
|
||||
default 0xFFC00730 if (BFIN533_STAMP)
|
||||
|
||||
config BFIN_ALIVE_LED_PIN
|
||||
hex
|
||||
default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
|
||||
default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
|
||||
default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
|
||||
|
||||
config BFIN_IDLE_LED_PORT
|
||||
hex
|
||||
default 0xFFC00700 if (BFIN533_STAMP)
|
||||
|
||||
# Peripheral Flag Direction Register
|
||||
config BFIN_IDLE_LED_DPORT
|
||||
hex
|
||||
default 0xFFC00730 if (BFIN533_STAMP)
|
||||
|
||||
config BFIN_IDLE_LED_PIN
|
||||
hex
|
||||
default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
|
||||
default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
|
||||
default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
|
||||
|
||||
comment "Console UART Setup"
|
||||
|
||||
choice
|
||||
prompt "Baud Rate"
|
||||
default BAUD_57600
|
||||
config BAUD_9600
|
||||
bool "9600"
|
||||
config BAUD_19200
|
||||
bool "19200"
|
||||
config BAUD_38400
|
||||
bool "38400"
|
||||
config BAUD_57600
|
||||
bool "57600"
|
||||
config BAUD_115200
|
||||
bool "115200"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Parity"
|
||||
default BAUD_NO_PARITY
|
||||
config BAUD_NO_PARITY
|
||||
bool "No Parity"
|
||||
config BAUD_PARITY
|
||||
bool "Parity"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Stop Bits"
|
||||
default BAUD_1_STOPBIT
|
||||
config BAUD_1_STOPBIT
|
||||
bool "1"
|
||||
config BAUD_2_STOPBIT
|
||||
bool "2"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
menu "Blackfin Kernel Optimizations"
|
||||
|
||||
comment "Timer Tick"
|
||||
|
||||
source kernel/Kconfig.hz
|
||||
|
||||
comment "Memory Optimizations"
|
||||
|
||||
config I_ENTRY_L1
|
||||
bool "Locate interrupt entry code in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled interrupt entry code (STORE/RESTORE CONTEXT) is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config EXCPT_IRQ_SYSC_L1
|
||||
bool "Locate entire ASM lowlevel excepetion / interrupt - Syscall and CPLB handler code in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled entire ASM lowlevel exception and interrupt entry code (STORE/RESTORE CONTEXT) is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config DO_IRQ_L1
|
||||
bool "Locate frequently called do_irq dispatcher function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled frequently called do_irq dispatcher function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config CORE_TIMER_IRQ_L1
|
||||
bool "Locate frequently called timer_interrupt() function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled frequently called timer_interrupt() function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config IDLE_L1
|
||||
bool "Locate frequently idle function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled frequently called idle function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config SCHEDULE_L1
|
||||
bool "Locate kernel schedule function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled frequently called kernel schedule is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config ARITHMETIC_OPS_L1
|
||||
bool "Locate kernel owned arithmetic functions in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled arithmetic functions are linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config ACCESS_OK_L1
|
||||
bool "Locate access_ok function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled access_ok function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config MEMSET_L1
|
||||
bool "Locate memset function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled memset function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config MEMCPY_L1
|
||||
bool "Locate memcpy function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled memcpy function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config SYS_BFIN_SPINLOCK_L1
|
||||
bool "Locate sys_bfin_spinlock function in L1 Memory"
|
||||
default y
|
||||
help
|
||||
If enabled sys_bfin_spinlock function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config IP_CHECKSUM_L1
|
||||
bool "Locate IP Checksum function in L1 Memory"
|
||||
default n
|
||||
help
|
||||
If enabled IP Checksum function is linked
|
||||
into L1 instruction memory.(less latency)
|
||||
|
||||
config CACHELINE_ALIGNED_L1
|
||||
bool "Locate cacheline_aligned data to L1 Data Memory"
|
||||
default y
|
||||
depends on !BF531
|
||||
help
|
||||
If enabled cacheline_anligned data is linked
|
||||
into L1 data memory.(less latency)
|
||||
|
||||
config SYSCALL_TAB_L1
|
||||
bool "Locate Syscall Table L1 Data Memory"
|
||||
default n
|
||||
depends on !BF531
|
||||
help
|
||||
If enabled the Syscall LUT is linked
|
||||
into L1 data memory.(less latency)
|
||||
|
||||
config CPLB_SWITCH_TAB_L1
|
||||
bool "Locate CPLB Switch Tables L1 Data Memory"
|
||||
default n
|
||||
depends on !BF531
|
||||
help
|
||||
If enabled the CPLB Switch Tables are linked
|
||||
into L1 data memory.(less latency)
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
choice
|
||||
prompt "Kernel executes from"
|
||||
help
|
||||
Choose the memory type that the kernel will be running in.
|
||||
|
||||
config RAMKERNEL
|
||||
bool "RAM"
|
||||
help
|
||||
The kernel will be resident in RAM when running.
|
||||
|
||||
config ROMKERNEL
|
||||
bool "ROM"
|
||||
help
|
||||
The kernel will be resident in FLASH/ROM when running.
|
||||
|
||||
endchoice
|
||||
|
||||
source "mm/Kconfig"
|
||||
|
||||
config LARGE_ALLOCS
|
||||
bool "Allow allocating large blocks (> 1MB) of memory"
|
||||
help
|
||||
Allow the slab memory allocator to keep chains for very large
|
||||
memory sizes - upto 32MB. You may need this if your system has
|
||||
a lot of RAM, and you need to able to allocate very large
|
||||
contiguous chunks. If unsure, say N.
|
||||
|
||||
config BFIN_DMA_5XX
|
||||
bool "Enable DMA Support"
|
||||
depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561)
|
||||
default y
|
||||
help
|
||||
DMA driver for BF5xx.
|
||||
|
||||
choice
|
||||
prompt "Uncached SDRAM region"
|
||||
default DMA_UNCACHED_1M
|
||||
depends BFIN_DMA_5XX
|
||||
config DMA_UNCACHED_2M
|
||||
bool "Enable 2M DMA region"
|
||||
config DMA_UNCACHED_1M
|
||||
bool "Enable 1M DMA region"
|
||||
config DMA_UNCACHED_NONE
|
||||
bool "Disable DMA region"
|
||||
endchoice
|
||||
|
||||
|
||||
comment "Cache Support"
|
||||
config BLKFIN_CACHE
|
||||
bool "Enable ICACHE"
|
||||
config BLKFIN_DCACHE
|
||||
bool "Enable DCACHE"
|
||||
config BLKFIN_DCACHE_BANKA
|
||||
bool "Enable only 16k BankA DCACHE - BankB is SRAM"
|
||||
depends on BLKFIN_DCACHE && !BF531
|
||||
default n
|
||||
config BLKFIN_CACHE_LOCK
|
||||
bool "Enable Cache Locking"
|
||||
|
||||
choice
|
||||
prompt "Policy"
|
||||
depends on BLKFIN_DCACHE
|
||||
default BLKFIN_WB
|
||||
config BLKFIN_WB
|
||||
bool "Write back"
|
||||
help
|
||||
Write Back Policy:
|
||||
Cached data will be written back to SDRAM only when needed.
|
||||
This can give a nice increase in performance, but beware of
|
||||
broken drivers that do not properly invalidate/flush their
|
||||
cache.
|
||||
|
||||
Write Through Policy:
|
||||
Cached data will always be written back to SDRAM when the
|
||||
cache is updated. This is a completely safe setting, but
|
||||
performance is worse than Write Back.
|
||||
|
||||
If you are unsure of the options and you want to be safe,
|
||||
then go with Write Through.
|
||||
|
||||
config BLKFIN_WT
|
||||
bool "Write through"
|
||||
help
|
||||
Write Back Policy:
|
||||
Cached data will be written back to SDRAM only when needed.
|
||||
This can give a nice increase in performance, but beware of
|
||||
broken drivers that do not properly invalidate/flush their
|
||||
cache.
|
||||
|
||||
Write Through Policy:
|
||||
Cached data will always be written back to SDRAM when the
|
||||
cache is updated. This is a completely safe setting, but
|
||||
performance is worse than Write Back.
|
||||
|
||||
If you are unsure of the options and you want to be safe,
|
||||
then go with Write Through.
|
||||
|
||||
endchoice
|
||||
|
||||
config L1_MAX_PIECE
|
||||
int "Set the max L1 SRAM pieces"
|
||||
default 16
|
||||
help
|
||||
Set the max memory pieces for the L1 SRAM allocation algorithm.
|
||||
Min value is 16. Max value is 1024.
|
||||
|
||||
menu "Clock Settings"
|
||||
|
||||
|
||||
config BFIN_KERNEL_CLOCK
|
||||
bool "Re-program Clocks while Kernel boots?"
|
||||
default n
|
||||
help
|
||||
This option decides if kernel clocks are re-programed from the
|
||||
bootloader settings. If the clocks are not set, the SDRAM settings
|
||||
are also not changed, and the Bootloader does 100% of the hardware
|
||||
configuration.
|
||||
|
||||
config VCO_MULT
|
||||
int "VCO Multiplier"
|
||||
depends on BFIN_KERNEL_CLOCK
|
||||
default "22" if BFIN533_EZKIT
|
||||
default "45" if BFIN533_STAMP
|
||||
default "20" if BFIN537_STAMP
|
||||
default "22" if BFIN533_BLUETECHNIX_CM
|
||||
default "20" if BFIN537_BLUETECHNIX_CM
|
||||
default "20" if BFIN561_BLUETECHNIX_CM
|
||||
default "20" if BFIN561_EZKIT
|
||||
|
||||
config CCLK_DIV
|
||||
int "Core Clock Divider"
|
||||
depends on BFIN_KERNEL_CLOCK
|
||||
default 1 if BFIN533_EZKIT
|
||||
default 1 if BFIN533_STAMP
|
||||
default 1 if BFIN537_STAMP
|
||||
default 1 if BFIN533_BLUETECHNIX_CM
|
||||
default 1 if BFIN537_BLUETECHNIX_CM
|
||||
default 1 if BFIN561_BLUETECHNIX_CM
|
||||
default 1 if BFIN561_EZKIT
|
||||
|
||||
config SCLK_DIV
|
||||
int "System Clock Divider"
|
||||
depends on BFIN_KERNEL_CLOCK
|
||||
default 5 if BFIN533_EZKIT
|
||||
default 5 if BFIN533_STAMP
|
||||
default 4 if BFIN537_STAMP
|
||||
default 5 if BFIN533_BLUETECHNIX_CM
|
||||
default 4 if BFIN537_BLUETECHNIX_CM
|
||||
default 4 if BFIN561_BLUETECHNIX_CM
|
||||
default 5 if BFIN561_EZKIT
|
||||
|
||||
config CLKIN_HALF
|
||||
bool "Half ClockIn"
|
||||
depends on BFIN_KERNEL_CLOCK
|
||||
default n
|
||||
|
||||
config PLL_BYPASS
|
||||
bool "Bypass PLL"
|
||||
depends on BFIN_KERNEL_CLOCK
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
||||
comment "Asynchonous Memory Configuration"
|
||||
|
||||
menu "EBIU_AMBCTL Global Control"
|
||||
config C_AMCKEN
|
||||
bool "Enable CLKOUT"
|
||||
default y
|
||||
|
||||
config C_CDPRIO
|
||||
bool "DMA has priority over core for ext. accesses"
|
||||
default n
|
||||
|
||||
config C_B0PEN
|
||||
depends on BF561
|
||||
bool "Bank 0 16 bit packing enable"
|
||||
default y
|
||||
|
||||
config C_B1PEN
|
||||
depends on BF561
|
||||
bool "Bank 1 16 bit packing enable"
|
||||
default y
|
||||
|
||||
config C_B2PEN
|
||||
depends on BF561
|
||||
bool "Bank 2 16 bit packing enable"
|
||||
default y
|
||||
|
||||
config C_B3PEN
|
||||
depends on BF561
|
||||
bool "Bank 3 16 bit packing enable"
|
||||
default n
|
||||
|
||||
choice
|
||||
prompt"Enable Asynchonous Memory Banks"
|
||||
default C_AMBEN_ALL
|
||||
|
||||
config C_AMBEN
|
||||
bool "Disable All Banks"
|
||||
|
||||
config C_AMBEN_B0
|
||||
bool "Enable Bank 0"
|
||||
|
||||
config C_AMBEN_B0_B1
|
||||
bool "Enable Bank 0 & 1"
|
||||
|
||||
config C_AMBEN_B0_B1_B2
|
||||
bool "Enable Bank 0 & 1 & 2"
|
||||
|
||||
config C_AMBEN_ALL
|
||||
bool "Enable All Banks"
|
||||
endchoice
|
||||
endmenu
|
||||
|
||||
menu "EBIU_AMBCTL Control"
|
||||
config BANK_0
|
||||
hex "Bank 0"
|
||||
default 0x7BB0
|
||||
|
||||
config BANK_1
|
||||
hex "Bank 1"
|
||||
default 0x7BB0
|
||||
|
||||
config BANK_2
|
||||
hex "Bank 2"
|
||||
default 0x7BB0
|
||||
|
||||
config BANK_3
|
||||
hex "Bank 3"
|
||||
default 0x99B3
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
#############################################################################
|
||||
menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
|
||||
|
||||
config PCI
|
||||
bool "PCI support"
|
||||
help
|
||||
Support for PCI bus.
|
||||
|
||||
source "drivers/pci/Kconfig"
|
||||
|
||||
config HOTPLUG
|
||||
bool "Support for hot-pluggable device"
|
||||
help
|
||||
Say Y here if you want to plug devices into your computer while
|
||||
the system is running, and be able to use them quickly. In many
|
||||
cases, the devices can likewise be unplugged at any time too.
|
||||
|
||||
One well known example of this is PCMCIA- or PC-cards, credit-card
|
||||
size devices such as network cards, modems or hard drives which are
|
||||
plugged into slots found on all modern laptop computers. Another
|
||||
example, used on modern desktops as well as laptops, is USB.
|
||||
|
||||
Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
|
||||
software (at <http://linux-hotplug.sourceforge.net/>) and install it.
|
||||
Then your kernel will automatically call out to a user mode "policy
|
||||
agent" (/sbin/hotplug) to load modules and set up software needed
|
||||
to use devices as you hotplug them.
|
||||
|
||||
source "drivers/pcmcia/Kconfig"
|
||||
|
||||
source "drivers/pci/hotplug/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Executable file formats"
|
||||
|
||||
source "fs/Kconfig.binfmt"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Power management options"
|
||||
source "kernel/power/Kconfig"
|
||||
|
||||
choice
|
||||
prompt "Select PM Wakeup Event Source"
|
||||
default PM_WAKEUP_GPIO_BY_SIC_IWR
|
||||
depends on PM
|
||||
help
|
||||
If you have a GPIO already configured as input with the corresponding PORTx_MASK
|
||||
bit set - "Specify Wakeup Event by SIC_IWR value"
|
||||
|
||||
config PM_WAKEUP_GPIO_BY_SIC_IWR
|
||||
bool "Specify Wakeup Event by SIC_IWR value"
|
||||
config PM_WAKEUP_BY_GPIO
|
||||
bool "Cause Wakeup Event by GPIO"
|
||||
config PM_WAKEUP_GPIO_API
|
||||
bool "Configure Wakeup Event by PM GPIO API"
|
||||
|
||||
endchoice
|
||||
|
||||
config PM_WAKEUP_SIC_IWR
|
||||
hex "Wakeup Events (SIC_IWR)"
|
||||
depends on PM_WAKEUP_GPIO_BY_SIC_IWR
|
||||
default 0x80000000 if (BF537 || BF536 || BF534)
|
||||
default 0x100000 if (BF533 || BF532 || BF531)
|
||||
|
||||
config PM_WAKEUP_GPIO_NUMBER
|
||||
int "Wakeup GPIO number"
|
||||
range 0 47
|
||||
depends on PM_WAKEUP_BY_GPIO
|
||||
default 2 if BFIN537_STAMP
|
||||
|
||||
choice
|
||||
prompt "GPIO Polarity"
|
||||
depends on PM_WAKEUP_BY_GPIO
|
||||
default PM_WAKEUP_GPIO_POLAR_H
|
||||
config PM_WAKEUP_GPIO_POLAR_H
|
||||
bool "Active High"
|
||||
config PM_WAKEUP_GPIO_POLAR_L
|
||||
bool "Active Low"
|
||||
config PM_WAKEUP_GPIO_POLAR_EDGE_F
|
||||
bool "Falling EDGE"
|
||||
config PM_WAKEUP_GPIO_POLAR_EDGE_R
|
||||
bool "Rising EDGE"
|
||||
config PM_WAKEUP_GPIO_POLAR_EDGE_B
|
||||
bool "Both EDGE"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
if (BF537 || BF533)
|
||||
|
||||
menu "CPU Frequency scaling"
|
||||
|
||||
source "drivers/cpufreq/Kconfig"
|
||||
|
||||
config CPU_FREQ
|
||||
bool
|
||||
default n
|
||||
help
|
||||
If you want to enable this option, you should select the
|
||||
DPMC driver from Character Devices.
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
||||
source "net/Kconfig"
|
||||
|
||||
source "drivers/Kconfig"
|
||||
|
||||
source "fs/Kconfig"
|
||||
|
||||
source "arch/blackfin/oprofile/Kconfig"
|
||||
|
||||
menu "Kernel hacking"
|
||||
|
||||
source "lib/Kconfig.debug"
|
||||
|
||||
config DEBUG_HWERR
|
||||
bool "Hardware error interrupt debugging"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
When enabled, the hardware error interrupt is never disabled, and
|
||||
will happen immediately when an error condition occurs. This comes
|
||||
at a slight cost in code size, but is necessary if you are getting
|
||||
hardware error interrupts and need to know where they are coming
|
||||
from.
|
||||
|
||||
config DEBUG_ICACHE_CHECK
|
||||
bool "Check Instruction cache coherancy"
|
||||
depends on DEBUG_KERNEL
|
||||
depends on DEBUG_HWERR
|
||||
help
|
||||
Say Y here if you are getting wierd unexplained errors. This will
|
||||
ensure that icache is what SDRAM says it should be, by doing a
|
||||
byte wise comparision between SDRAM and instruction cache. This
|
||||
also relocates the irq_panic() function to L1 memory, (which is
|
||||
un-cached).
|
||||
|
||||
config DEBUG_KERNEL_START
|
||||
bool "Debug Kernel Startup"
|
||||
depends on DEBUG_KERNEL
|
||||
help
|
||||
Say Y here to put in an mini-execption handler before the kernel
|
||||
replaces the bootloader exception handler. This will stop kernels
|
||||
from dieing at startup with no visible error messages.
|
||||
|
||||
config DEBUG_SERIAL_EARLY_INIT
|
||||
bool "Initialize serial driver early"
|
||||
default n
|
||||
depends on SERIAL_BFIN
|
||||
help
|
||||
Say Y here if you want to get kernel output early when kernel
|
||||
crashes before the normal console initialization. If this option
|
||||
is enable, console output will always go to the ttyBF0, no matter
|
||||
what kernel boot paramters you set.
|
||||
|
||||
config DEBUG_HUNT_FOR_ZERO
|
||||
bool "Catch NULL pointer reads/writes"
|
||||
default y
|
||||
help
|
||||
Say Y here to catch reads/writes to anywhere in the memory range
|
||||
from 0x0000 - 0x0FFF (the first 4k) of memory. This is useful in
|
||||
catching common programming errors such as NULL pointer dereferences.
|
||||
|
||||
Misbehaving applications will be killed (generate a SEGV) while the
|
||||
kernel will trigger a panic.
|
||||
|
||||
Enabling this option will take up an extra entry in CPLB table.
|
||||
Otherwise, there is no extra overhead.
|
||||
|
||||
config DEBUG_BFIN_NO_KERN_HWTRACE
|
||||
bool "Trace user apps (turn off hwtrace in kernel)"
|
||||
default n
|
||||
help
|
||||
Some pieces of the kernel contain a lot of flow changes which can
|
||||
quickly fill up the hardware trace buffer. When debugging crashes,
|
||||
the hardware trace may indicate that the problem lies in kernel
|
||||
space when in reality an application is buggy.
|
||||
|
||||
Say Y here to disable hardware tracing in some known "jumpy" pieces
|
||||
of code so that the trace buffer will extend further back.
|
||||
|
||||
config DUAL_CORE_TEST_MODULE
|
||||
tristate "Dual Core Test Module"
|
||||
depends on (BF561)
|
||||
default n
|
||||
help
|
||||
Say Y here to build-in dual core test module for dual core test.
|
||||
|
||||
config CPLB_INFO
|
||||
bool "Display the CPLB information"
|
||||
help
|
||||
Display the CPLB information.
|
||||
|
||||
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
|
||||
|
||||
source "security/Kconfig"
|
||||
|
||||
source "crypto/Kconfig"
|
||||
|
||||
source "lib/Kconfig"
|
80
arch/blackfin/Makefile
Normal file
80
arch/blackfin/Makefile
Normal file
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# arch/blackfin/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.
|
||||
#
|
||||
|
||||
|
||||
CROSS_COMPILE ?= bfin-uclinux-
|
||||
LDFLAGS_vmlinux := -X
|
||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
||||
GZFLAGS := -9
|
||||
|
||||
CFLAGS_MODULE += -mlong-calls
|
||||
KALLSYMS += --symbol-prefix=_
|
||||
|
||||
|
||||
# setup the machine name and the machine dependent settings
|
||||
machine-$(CONFIG_BF531) := bf533
|
||||
machine-$(CONFIG_BF532) := bf533
|
||||
machine-$(CONFIG_BF533) := bf533
|
||||
machine-$(CONFIG_BF534) := bf537
|
||||
machine-$(CONFIG_BF536) := bf537
|
||||
machine-$(CONFIG_BF537) := bf537
|
||||
machine-$(CONFIG_BF561) := bf561
|
||||
MACHINE := $(machine-y)
|
||||
export MACHINE
|
||||
|
||||
|
||||
head-y := arch/$(ARCH)/mach-$(MACHINE)/head.o arch/$(ARCH)/kernel/init_task.o
|
||||
|
||||
core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ arch/$(ARCH)/mach-common/
|
||||
|
||||
# If we have a machine-specific directory, then include it in the build.
|
||||
ifneq ($(machine-y),)
|
||||
core-y += arch/$(ARCH)/mach-$(MACHINE)/
|
||||
core-y += arch/$(ARCH)/mach-$(MACHINE)/boards/
|
||||
endif
|
||||
|
||||
libs-y += arch/$(ARCH)/lib/
|
||||
|
||||
drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
|
||||
|
||||
|
||||
|
||||
# Update machine arch symlinks if something which affects
|
||||
# them changed. We use .mach to indicate when they were updated
|
||||
# last, otherwise make uses the target directory mtime.
|
||||
|
||||
include/asm-blackfin/.mach: $(wildcard include/config/arch/*.h) include/config/auto.conf
|
||||
@echo ' SYMLINK include/asm-$(ARCH)/mach-$(MACHINE) -> include/asm-$(ARCH)/mach'
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
$(Q)mkdir -p include/asm-$(ARCH)
|
||||
$(Q)ln -fsn $(srctree)/include/asm-$(ARCH)/mach-$(MACHINE) include/asm-$(ARCH)/mach
|
||||
else
|
||||
$(Q)ln -fsn mach-$(MACHINE) include/asm-$(ARCH)/mach
|
||||
endif
|
||||
@touch $@
|
||||
|
||||
CLEAN_FILES += \
|
||||
include/asm-$(ARCH)/asm-offsets.h \
|
||||
arch/$(ARCH)/kernel/asm-offsets.s \
|
||||
include/asm-$(ARCH)/mach \
|
||||
include/asm-$(ARCH)/.mach
|
||||
|
||||
archprepare: include/asm-blackfin/.mach
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
||||
|
||||
all: vmImage
|
||||
boot := arch/$(ARCH)/boot
|
||||
BOOT_TARGETS = vmImage
|
||||
.PHONY: $(BOOT_TARGETS)
|
||||
$(BOOT_TARGETS): vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
define archhelp
|
||||
echo '* vmImage - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
|
||||
endef
|
27
arch/blackfin/boot/Makefile
Normal file
27
arch/blackfin/boot/Makefile
Normal file
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# arch/blackfin/boot/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.
|
||||
#
|
||||
|
||||
MKIMAGE := $(srctree)/scripts/mkuboot.sh
|
||||
|
||||
targets := vmImage
|
||||
extra-y += vmlinux.bin vmlinux.gz
|
||||
|
||||
quiet_cmd_uimage = UIMAGE $@
|
||||
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
|
||||
-C gzip -a $(CONFIG_BOOT_LOAD) -e $(CONFIG_BOOT_LOAD) -n 'Linux-$(KERNELRELEASE)' \
|
||||
-d $< $@
|
||||
|
||||
$(obj)/vmlinux.bin: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
$(obj)/vmImage: $(obj)/vmlinux.gz
|
||||
$(call if_changed,uimage)
|
||||
@echo 'Kernel: $@ is ready'
|
1314
arch/blackfin/defconfig
Normal file
1314
arch/blackfin/defconfig
Normal file
File diff suppressed because it is too large
Load diff
14
arch/blackfin/kernel/Makefile
Normal file
14
arch/blackfin/kernel/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# arch/blackfin/kernel/Makefile
|
||||
#
|
||||
|
||||
extra-y := init_task.o vmlinux.lds
|
||||
|
||||
obj-y := \
|
||||
entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
|
||||
sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
|
||||
flat.o
|
||||
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
|
||||
obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
|
136
arch/blackfin/kernel/asm-offsets.c
Normal file
136
arch/blackfin/kernel/asm-offsets.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/asm-offsets.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: generate definitions needed by assembly language modules.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
#define DEFINE(sym, val) \
|
||||
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
/* offsets into the task struct */
|
||||
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
|
||||
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
|
||||
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
|
||||
DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
|
||||
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
|
||||
DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
|
||||
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
|
||||
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
|
||||
DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
|
||||
|
||||
/* offsets into the irq_cpustat_t struct */
|
||||
DEFINE(CPUSTAT_SOFTIRQ_PENDING,
|
||||
offsetof(irq_cpustat_t, __softirq_pending));
|
||||
|
||||
/* offsets into the thread struct */
|
||||
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
|
||||
DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
|
||||
DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
|
||||
DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
|
||||
DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
|
||||
DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
|
||||
DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
|
||||
|
||||
/* offsets into the pt_regs */
|
||||
DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
|
||||
DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
|
||||
DEFINE(PT_R0, offsetof(struct pt_regs, r0));
|
||||
DEFINE(PT_R1, offsetof(struct pt_regs, r1));
|
||||
DEFINE(PT_R2, offsetof(struct pt_regs, r2));
|
||||
DEFINE(PT_R3, offsetof(struct pt_regs, r3));
|
||||
DEFINE(PT_R4, offsetof(struct pt_regs, r4));
|
||||
DEFINE(PT_R5, offsetof(struct pt_regs, r5));
|
||||
DEFINE(PT_R6, offsetof(struct pt_regs, r6));
|
||||
DEFINE(PT_R7, offsetof(struct pt_regs, r7));
|
||||
|
||||
DEFINE(PT_P0, offsetof(struct pt_regs, p0));
|
||||
DEFINE(PT_P1, offsetof(struct pt_regs, p1));
|
||||
DEFINE(PT_P2, offsetof(struct pt_regs, p2));
|
||||
DEFINE(PT_P3, offsetof(struct pt_regs, p3));
|
||||
DEFINE(PT_P4, offsetof(struct pt_regs, p4));
|
||||
DEFINE(PT_P5, offsetof(struct pt_regs, p5));
|
||||
|
||||
DEFINE(PT_FP, offsetof(struct pt_regs, fp));
|
||||
DEFINE(PT_USP, offsetof(struct pt_regs, usp));
|
||||
DEFINE(PT_I0, offsetof(struct pt_regs, i0));
|
||||
DEFINE(PT_I1, offsetof(struct pt_regs, i1));
|
||||
DEFINE(PT_I2, offsetof(struct pt_regs, i2));
|
||||
DEFINE(PT_I3, offsetof(struct pt_regs, i3));
|
||||
DEFINE(PT_M0, offsetof(struct pt_regs, m0));
|
||||
DEFINE(PT_M1, offsetof(struct pt_regs, m1));
|
||||
DEFINE(PT_M2, offsetof(struct pt_regs, m2));
|
||||
DEFINE(PT_M3, offsetof(struct pt_regs, m3));
|
||||
DEFINE(PT_L0, offsetof(struct pt_regs, l0));
|
||||
DEFINE(PT_L1, offsetof(struct pt_regs, l1));
|
||||
DEFINE(PT_L2, offsetof(struct pt_regs, l2));
|
||||
DEFINE(PT_L3, offsetof(struct pt_regs, l3));
|
||||
DEFINE(PT_B0, offsetof(struct pt_regs, b0));
|
||||
DEFINE(PT_B1, offsetof(struct pt_regs, b1));
|
||||
DEFINE(PT_B2, offsetof(struct pt_regs, b2));
|
||||
DEFINE(PT_B3, offsetof(struct pt_regs, b3));
|
||||
DEFINE(PT_A0X, offsetof(struct pt_regs, a0x));
|
||||
DEFINE(PT_A0W, offsetof(struct pt_regs, a0w));
|
||||
DEFINE(PT_A1X, offsetof(struct pt_regs, a1x));
|
||||
DEFINE(PT_A1W, offsetof(struct pt_regs, a1w));
|
||||
DEFINE(PT_LC0, offsetof(struct pt_regs, lc0));
|
||||
DEFINE(PT_LC1, offsetof(struct pt_regs, lc1));
|
||||
DEFINE(PT_LT0, offsetof(struct pt_regs, lt0));
|
||||
DEFINE(PT_LT1, offsetof(struct pt_regs, lt1));
|
||||
DEFINE(PT_LB0, offsetof(struct pt_regs, lb0));
|
||||
DEFINE(PT_LB1, offsetof(struct pt_regs, lb1));
|
||||
DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat));
|
||||
DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved));
|
||||
DEFINE(PT_RETS, offsetof(struct pt_regs, rets));
|
||||
DEFINE(PT_PC, offsetof(struct pt_regs, pc));
|
||||
DEFINE(PT_RETX, offsetof(struct pt_regs, retx));
|
||||
DEFINE(PT_RETN, offsetof(struct pt_regs, retn));
|
||||
DEFINE(PT_RETE, offsetof(struct pt_regs, rete));
|
||||
DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat));
|
||||
DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg));
|
||||
DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend));
|
||||
DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs));
|
||||
DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs)); /* Needed by gdb */
|
||||
DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */
|
||||
DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs)); /* Needed by gdb */
|
||||
DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs)); /* Needed by gdb */
|
||||
DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */
|
||||
|
||||
/* signal defines */
|
||||
DEFINE(SIGSEGV, SIGSEGV);
|
||||
DEFINE(SIGTRAP, SIGTRAP);
|
||||
|
||||
return 0;
|
||||
}
|
742
arch/blackfin/kernel/bfin_dma_5xx.c
Normal file
742
arch/blackfin/kernel/bfin_dma_5xx.c
Normal file
|
@ -0,0 +1,742 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/bfin_dma_5xx.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
|
||||
#include <asm/dma.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/* Remove unused code not exported by symbol or internally called */
|
||||
#define REMOVE_DEAD_CODE
|
||||
|
||||
/**************************************************************************
|
||||
* Global Variables
|
||||
***************************************************************************/
|
||||
|
||||
static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
|
||||
#if defined (CONFIG_BF561)
|
||||
static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
|
||||
(struct dma_register *) DMA1_0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_2_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_3_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_4_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_5_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_6_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_7_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_8_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_9_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_10_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_11_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_2_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_3_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_4_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_5_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_6_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_7_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_8_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_9_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_10_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_11_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
|
||||
};
|
||||
#else
|
||||
static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
|
||||
(struct dma_register *) DMA0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA2_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA3_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA4_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA5_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA6_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA7_NEXT_DESC_PTR,
|
||||
#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
|
||||
(struct dma_register *) DMA8_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA9_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA10_NEXT_DESC_PTR,
|
||||
(struct dma_register *) DMA11_NEXT_DESC_PTR,
|
||||
#endif
|
||||
(struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
|
||||
(struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Set the Buffer Clear bit in the Configuration register of specific DMA
|
||||
* channel. This will stop the descriptor based DMA operation.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
static void clear_dma_buffer(unsigned int channel)
|
||||
{
|
||||
dma_ch[channel].regs->cfg |= RESTART;
|
||||
SSYNC();
|
||||
dma_ch[channel].regs->cfg &= ~RESTART;
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
int __init blackfin_dma_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "Blackfin DMA Controller\n");
|
||||
|
||||
for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
|
||||
dma_ch[i].chan_status = DMA_CHANNEL_FREE;
|
||||
dma_ch[i].regs = base_addr[i];
|
||||
mutex_init(&(dma_ch[i].dmalock));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(blackfin_dma_init);
|
||||
|
||||
/*
|
||||
* Form the channel find the irq number for that channel.
|
||||
*/
|
||||
#if !defined(CONFIG_BF561)
|
||||
|
||||
static int bf533_channel2irq(unsigned int channel)
|
||||
{
|
||||
int ret_irq = -1;
|
||||
|
||||
switch (channel) {
|
||||
case CH_PPI:
|
||||
ret_irq = IRQ_PPI;
|
||||
break;
|
||||
|
||||
#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
|
||||
case CH_EMAC_RX:
|
||||
ret_irq = IRQ_MAC_RX;
|
||||
break;
|
||||
|
||||
case CH_EMAC_TX:
|
||||
ret_irq = IRQ_MAC_TX;
|
||||
break;
|
||||
|
||||
case CH_UART1_RX:
|
||||
ret_irq = IRQ_UART1_RX;
|
||||
break;
|
||||
|
||||
case CH_UART1_TX:
|
||||
ret_irq = IRQ_UART1_TX;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case CH_SPORT0_RX:
|
||||
ret_irq = IRQ_SPORT0_RX;
|
||||
break;
|
||||
|
||||
case CH_SPORT0_TX:
|
||||
ret_irq = IRQ_SPORT0_TX;
|
||||
break;
|
||||
|
||||
case CH_SPORT1_RX:
|
||||
ret_irq = IRQ_SPORT1_RX;
|
||||
break;
|
||||
|
||||
case CH_SPORT1_TX:
|
||||
ret_irq = IRQ_SPORT1_TX;
|
||||
break;
|
||||
|
||||
case CH_SPI:
|
||||
ret_irq = IRQ_SPI;
|
||||
break;
|
||||
|
||||
case CH_UART_RX:
|
||||
ret_irq = IRQ_UART_RX;
|
||||
break;
|
||||
|
||||
case CH_UART_TX:
|
||||
ret_irq = IRQ_UART_TX;
|
||||
break;
|
||||
|
||||
case CH_MEM_STREAM0_SRC:
|
||||
case CH_MEM_STREAM0_DEST:
|
||||
ret_irq = IRQ_MEM_DMA0;
|
||||
break;
|
||||
|
||||
case CH_MEM_STREAM1_SRC:
|
||||
case CH_MEM_STREAM1_DEST:
|
||||
ret_irq = IRQ_MEM_DMA1;
|
||||
break;
|
||||
}
|
||||
return ret_irq;
|
||||
}
|
||||
|
||||
# define channel2irq(channel) bf533_channel2irq(channel)
|
||||
|
||||
#else
|
||||
|
||||
static int bf561_channel2irq(unsigned int channel)
|
||||
{
|
||||
int ret_irq = -1;
|
||||
|
||||
switch (channel) {
|
||||
case CH_PPI0:
|
||||
ret_irq = IRQ_PPI0;
|
||||
break;
|
||||
case CH_PPI1:
|
||||
ret_irq = IRQ_PPI1;
|
||||
break;
|
||||
case CH_SPORT0_RX:
|
||||
ret_irq = IRQ_SPORT0_RX;
|
||||
break;
|
||||
case CH_SPORT0_TX:
|
||||
ret_irq = IRQ_SPORT0_TX;
|
||||
break;
|
||||
case CH_SPORT1_RX:
|
||||
ret_irq = IRQ_SPORT1_RX;
|
||||
break;
|
||||
case CH_SPORT1_TX:
|
||||
ret_irq = IRQ_SPORT1_TX;
|
||||
break;
|
||||
case CH_SPI:
|
||||
ret_irq = IRQ_SPI;
|
||||
break;
|
||||
case CH_UART_RX:
|
||||
ret_irq = IRQ_UART_RX;
|
||||
break;
|
||||
case CH_UART_TX:
|
||||
ret_irq = IRQ_UART_TX;
|
||||
break;
|
||||
|
||||
case CH_MEM_STREAM0_SRC:
|
||||
case CH_MEM_STREAM0_DEST:
|
||||
ret_irq = IRQ_MEM_DMA0;
|
||||
break;
|
||||
case CH_MEM_STREAM1_SRC:
|
||||
case CH_MEM_STREAM1_DEST:
|
||||
ret_irq = IRQ_MEM_DMA1;
|
||||
break;
|
||||
case CH_MEM_STREAM2_SRC:
|
||||
case CH_MEM_STREAM2_DEST:
|
||||
ret_irq = IRQ_MEM_DMA2;
|
||||
break;
|
||||
case CH_MEM_STREAM3_SRC:
|
||||
case CH_MEM_STREAM3_DEST:
|
||||
ret_irq = IRQ_MEM_DMA3;
|
||||
break;
|
||||
|
||||
case CH_IMEM_STREAM0_SRC:
|
||||
case CH_IMEM_STREAM0_DEST:
|
||||
ret_irq = IRQ_IMEM_DMA0;
|
||||
break;
|
||||
case CH_IMEM_STREAM1_SRC:
|
||||
case CH_IMEM_STREAM1_DEST:
|
||||
ret_irq = IRQ_IMEM_DMA1;
|
||||
break;
|
||||
}
|
||||
return ret_irq;
|
||||
}
|
||||
|
||||
# define channel2irq(channel) bf561_channel2irq(channel)
|
||||
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Request the specific DMA channel from the system.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
int request_dma(unsigned int channel, char *device_id)
|
||||
{
|
||||
|
||||
pr_debug("request_dma() : BEGIN \n");
|
||||
mutex_lock(&(dma_ch[channel].dmalock));
|
||||
|
||||
if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
|
||||
|| (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
|
||||
mutex_unlock(&(dma_ch[channel].dmalock));
|
||||
pr_debug("DMA CHANNEL IN USE \n");
|
||||
return -EBUSY;
|
||||
} else {
|
||||
dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
|
||||
pr_debug("DMA CHANNEL IS ALLOCATED \n");
|
||||
}
|
||||
|
||||
mutex_unlock(&(dma_ch[channel].dmalock));
|
||||
|
||||
dma_ch[channel].device_id = device_id;
|
||||
dma_ch[channel].irq_callback = NULL;
|
||||
|
||||
/* This is to be enabled by putting a restriction -
|
||||
* you have to request DMA, before doing any operations on
|
||||
* descriptor/channel
|
||||
*/
|
||||
pr_debug("request_dma() : END \n");
|
||||
return channel;
|
||||
}
|
||||
EXPORT_SYMBOL(request_dma);
|
||||
|
||||
int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data)
|
||||
{
|
||||
int ret_irq = 0;
|
||||
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
if (callback != NULL) {
|
||||
int ret_val;
|
||||
ret_irq = channel2irq(channel);
|
||||
|
||||
dma_ch[channel].data = data;
|
||||
|
||||
ret_val =
|
||||
request_irq(ret_irq, (void *)callback, IRQF_DISABLED,
|
||||
dma_ch[channel].device_id, data);
|
||||
if (ret_val) {
|
||||
printk(KERN_NOTICE
|
||||
"Request irq in DMA engine failed.\n");
|
||||
return -EPERM;
|
||||
}
|
||||
dma_ch[channel].irq_callback = callback;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_callback);
|
||||
|
||||
void free_dma(unsigned int channel)
|
||||
{
|
||||
int ret_irq;
|
||||
|
||||
pr_debug("freedma() : BEGIN \n");
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
/* Halt the DMA */
|
||||
disable_dma(channel);
|
||||
clear_dma_buffer(channel);
|
||||
|
||||
if (dma_ch[channel].irq_callback != NULL) {
|
||||
ret_irq = channel2irq(channel);
|
||||
free_irq(ret_irq, dma_ch[channel].data);
|
||||
}
|
||||
|
||||
/* Clear the DMA Variable in the Channel */
|
||||
mutex_lock(&(dma_ch[channel].dmalock));
|
||||
dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
|
||||
mutex_unlock(&(dma_ch[channel].dmalock));
|
||||
|
||||
pr_debug("freedma() : END \n");
|
||||
}
|
||||
EXPORT_SYMBOL(free_dma);
|
||||
|
||||
void dma_enable_irq(unsigned int channel)
|
||||
{
|
||||
int ret_irq;
|
||||
|
||||
pr_debug("dma_enable_irq() : BEGIN \n");
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
ret_irq = channel2irq(channel);
|
||||
enable_irq(ret_irq);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_enable_irq);
|
||||
|
||||
void dma_disable_irq(unsigned int channel)
|
||||
{
|
||||
int ret_irq;
|
||||
|
||||
pr_debug("dma_disable_irq() : BEGIN \n");
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
ret_irq = channel2irq(channel);
|
||||
disable_irq(ret_irq);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_disable_irq);
|
||||
|
||||
int dma_channel_active(unsigned int channel)
|
||||
{
|
||||
if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dma_channel_active);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* stop the specific DMA channel.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void disable_dma(unsigned int channel)
|
||||
{
|
||||
pr_debug("stop_dma() : BEGIN \n");
|
||||
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */
|
||||
SSYNC();
|
||||
dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
|
||||
/* Needs to be enabled Later */
|
||||
pr_debug("stop_dma() : END \n");
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(disable_dma);
|
||||
|
||||
void enable_dma(unsigned int channel)
|
||||
{
|
||||
pr_debug("enable_dma() : BEGIN \n");
|
||||
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
|
||||
dma_ch[channel].regs->curr_x_count = 0;
|
||||
dma_ch[channel].regs->curr_y_count = 0;
|
||||
|
||||
dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */
|
||||
SSYNC();
|
||||
pr_debug("enable_dma() : END \n");
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(enable_dma);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Set the Start Address register for the specific DMA channel
|
||||
* This function can be used for register based DMA,
|
||||
* to setup the start address
|
||||
* addr: Starting address of the DMA Data to be transferred.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void set_dma_start_addr(unsigned int channel, unsigned long addr)
|
||||
{
|
||||
pr_debug("set_dma_start_addr() : BEGIN \n");
|
||||
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->start_addr = addr;
|
||||
SSYNC();
|
||||
pr_debug("set_dma_start_addr() : END\n");
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_start_addr);
|
||||
|
||||
void set_dma_next_desc_addr(unsigned int channel, unsigned long addr)
|
||||
{
|
||||
pr_debug("set_dma_next_desc_addr() : BEGIN \n");
|
||||
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->next_desc_ptr = addr;
|
||||
SSYNC();
|
||||
pr_debug("set_dma_start_addr() : END\n");
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_next_desc_addr);
|
||||
|
||||
void set_dma_x_count(unsigned int channel, unsigned short x_count)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->x_count = x_count;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_x_count);
|
||||
|
||||
void set_dma_y_count(unsigned int channel, unsigned short y_count)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->y_count = y_count;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_y_count);
|
||||
|
||||
void set_dma_x_modify(unsigned int channel, short x_modify)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->x_modify = x_modify;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_x_modify);
|
||||
|
||||
void set_dma_y_modify(unsigned int channel, short y_modify)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->y_modify = y_modify;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_y_modify);
|
||||
|
||||
void set_dma_config(unsigned int channel, unsigned short config)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->cfg = config;
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_config);
|
||||
|
||||
unsigned short
|
||||
set_bfin_dma_config(char direction, char flow_mode,
|
||||
char intr_mode, char dma_mode, char width)
|
||||
{
|
||||
unsigned short config;
|
||||
|
||||
config =
|
||||
((direction << 1) | (width << 2) | (dma_mode << 4) |
|
||||
(intr_mode << 6) | (flow_mode << 12) | RESTART);
|
||||
return config;
|
||||
}
|
||||
EXPORT_SYMBOL(set_bfin_dma_config);
|
||||
|
||||
void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8);
|
||||
|
||||
dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg;
|
||||
|
||||
SSYNC();
|
||||
}
|
||||
EXPORT_SYMBOL(set_dma_sg);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Get the DMA status of a specific DMA channel from the system.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
unsigned short get_dma_curr_irqstat(unsigned int channel)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
return dma_ch[channel].regs->irq_status;
|
||||
}
|
||||
EXPORT_SYMBOL(get_dma_curr_irqstat);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void clear_dma_irqstat(unsigned int channel)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
dma_ch[channel].regs->irq_status |= 3;
|
||||
}
|
||||
EXPORT_SYMBOL(clear_dma_irqstat);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Get current DMA xcount of a specific DMA channel from the system.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
unsigned short get_dma_curr_xcount(unsigned int channel)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
return dma_ch[channel].regs->curr_x_count;
|
||||
}
|
||||
EXPORT_SYMBOL(get_dma_curr_xcount);
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Get current DMA ycount of a specific DMA channel from the system.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
unsigned short get_dma_curr_ycount(unsigned int channel)
|
||||
{
|
||||
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
|
||||
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
|
||||
|
||||
return dma_ch[channel].regs->curr_y_count;
|
||||
}
|
||||
EXPORT_SYMBOL(get_dma_curr_ycount);
|
||||
|
||||
void *dma_memcpy(void *dest, const void *src, size_t size)
|
||||
{
|
||||
int direction; /* 1 - address decrease, 0 - address increase */
|
||||
int flag_align; /* 1 - address aligned, 0 - address unaligned */
|
||||
int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */
|
||||
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
|
||||
if ((unsigned long)src < memory_end)
|
||||
blackfin_dcache_flush_range((unsigned int)src,
|
||||
(unsigned int)(src + size));
|
||||
|
||||
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
|
||||
|
||||
if ((unsigned long)src < (unsigned long)dest)
|
||||
direction = 1;
|
||||
else
|
||||
direction = 0;
|
||||
|
||||
if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0)
|
||||
&& ((size % 2) == 0))
|
||||
flag_align = 1;
|
||||
else
|
||||
flag_align = 0;
|
||||
|
||||
if (size > 0x10000) /* size > 64K */
|
||||
flag_2D = 1;
|
||||
else
|
||||
flag_2D = 0;
|
||||
|
||||
/* Setup destination and source start address */
|
||||
if (direction) {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_D0_START_ADDR(dest + size - 2);
|
||||
bfin_write_MDMA_S0_START_ADDR(src + size - 2);
|
||||
} else {
|
||||
bfin_write_MDMA_D0_START_ADDR(dest + size - 1);
|
||||
bfin_write_MDMA_S0_START_ADDR(src + size - 1);
|
||||
}
|
||||
} else {
|
||||
bfin_write_MDMA_D0_START_ADDR(dest);
|
||||
bfin_write_MDMA_S0_START_ADDR(src);
|
||||
}
|
||||
|
||||
/* Setup destination and source xcount */
|
||||
if (flag_2D) {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_D0_X_COUNT(1024 / 2);
|
||||
bfin_write_MDMA_S0_X_COUNT(1024 / 2);
|
||||
} else {
|
||||
bfin_write_MDMA_D0_X_COUNT(1024);
|
||||
bfin_write_MDMA_S0_X_COUNT(1024);
|
||||
}
|
||||
bfin_write_MDMA_D0_Y_COUNT(size >> 10);
|
||||
bfin_write_MDMA_S0_Y_COUNT(size >> 10);
|
||||
} else {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_D0_X_COUNT(size / 2);
|
||||
bfin_write_MDMA_S0_X_COUNT(size / 2);
|
||||
} else {
|
||||
bfin_write_MDMA_D0_X_COUNT(size);
|
||||
bfin_write_MDMA_S0_X_COUNT(size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup destination and source xmodify and ymodify */
|
||||
if (direction) {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_D0_X_MODIFY(-2);
|
||||
bfin_write_MDMA_S0_X_MODIFY(-2);
|
||||
if (flag_2D) {
|
||||
bfin_write_MDMA_D0_Y_MODIFY(-2);
|
||||
bfin_write_MDMA_S0_Y_MODIFY(-2);
|
||||
}
|
||||
} else {
|
||||
bfin_write_MDMA_D0_X_MODIFY(-1);
|
||||
bfin_write_MDMA_S0_X_MODIFY(-1);
|
||||
if (flag_2D) {
|
||||
bfin_write_MDMA_D0_Y_MODIFY(-1);
|
||||
bfin_write_MDMA_S0_Y_MODIFY(-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_D0_X_MODIFY(2);
|
||||
bfin_write_MDMA_S0_X_MODIFY(2);
|
||||
if (flag_2D) {
|
||||
bfin_write_MDMA_D0_Y_MODIFY(2);
|
||||
bfin_write_MDMA_S0_Y_MODIFY(2);
|
||||
}
|
||||
} else {
|
||||
bfin_write_MDMA_D0_X_MODIFY(1);
|
||||
bfin_write_MDMA_S0_X_MODIFY(1);
|
||||
if (flag_2D) {
|
||||
bfin_write_MDMA_D0_Y_MODIFY(1);
|
||||
bfin_write_MDMA_S0_Y_MODIFY(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable source DMA */
|
||||
if (flag_2D) {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16);
|
||||
bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16);
|
||||
} else {
|
||||
bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D);
|
||||
bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D);
|
||||
}
|
||||
} else {
|
||||
if (flag_align) {
|
||||
bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
|
||||
bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
|
||||
} else {
|
||||
bfin_write_MDMA_S0_CONFIG(DMAEN);
|
||||
bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN);
|
||||
}
|
||||
}
|
||||
|
||||
while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
|
||||
;
|
||||
|
||||
bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() |
|
||||
(DMA_DONE | DMA_ERR));
|
||||
|
||||
bfin_write_MDMA_S0_CONFIG(0);
|
||||
bfin_write_MDMA_D0_CONFIG(0);
|
||||
|
||||
if ((unsigned long)dest < memory_end)
|
||||
blackfin_dcache_invalidate_range((unsigned int)dest,
|
||||
(unsigned int)(dest + size));
|
||||
|
||||
return dest;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_memcpy);
|
||||
|
||||
void *safe_dma_memcpy(void *dest, const void *src, size_t size)
|
||||
{
|
||||
int flags = 0;
|
||||
void *addr;
|
||||
local_irq_save(flags);
|
||||
addr = dma_memcpy(dest, src, size);
|
||||
local_irq_restore(flags);
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL(safe_dma_memcpy);
|
637
arch/blackfin/kernel/bfin_gpio.c
Normal file
637
arch/blackfin/kernel/bfin_gpio.c
Normal file
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/bfin_gpio.c
|
||||
* Based on:
|
||||
* Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
|
||||
*
|
||||
* Created:
|
||||
* Description: GPIO Abstraction Layer
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Number BF537/6/4 BF561 BF533/2/1
|
||||
*
|
||||
* GPIO_0 PF0 PF0 PF0
|
||||
* GPIO_1 PF1 PF1 PF1
|
||||
* GPIO_2 PF2 PF2 PF2
|
||||
* GPIO_3 PF3 PF3 PF3
|
||||
* GPIO_4 PF4 PF4 PF4
|
||||
* GPIO_5 PF5 PF5 PF5
|
||||
* GPIO_6 PF6 PF6 PF6
|
||||
* GPIO_7 PF7 PF7 PF7
|
||||
* GPIO_8 PF8 PF8 PF8
|
||||
* GPIO_9 PF9 PF9 PF9
|
||||
* GPIO_10 PF10 PF10 PF10
|
||||
* GPIO_11 PF11 PF11 PF11
|
||||
* GPIO_12 PF12 PF12 PF12
|
||||
* GPIO_13 PF13 PF13 PF13
|
||||
* GPIO_14 PF14 PF14 PF14
|
||||
* GPIO_15 PF15 PF15 PF15
|
||||
* GPIO_16 PG0 PF16
|
||||
* GPIO_17 PG1 PF17
|
||||
* GPIO_18 PG2 PF18
|
||||
* GPIO_19 PG3 PF19
|
||||
* GPIO_20 PG4 PF20
|
||||
* GPIO_21 PG5 PF21
|
||||
* GPIO_22 PG6 PF22
|
||||
* GPIO_23 PG7 PF23
|
||||
* GPIO_24 PG8 PF24
|
||||
* GPIO_25 PG9 PF25
|
||||
* GPIO_26 PG10 PF26
|
||||
* GPIO_27 PG11 PF27
|
||||
* GPIO_28 PG12 PF28
|
||||
* GPIO_29 PG13 PF29
|
||||
* GPIO_30 PG14 PF30
|
||||
* GPIO_31 PG15 PF31
|
||||
* GPIO_32 PH0 PF32
|
||||
* GPIO_33 PH1 PF33
|
||||
* GPIO_34 PH2 PF34
|
||||
* GPIO_35 PH3 PF35
|
||||
* GPIO_36 PH4 PF36
|
||||
* GPIO_37 PH5 PF37
|
||||
* GPIO_38 PH6 PF38
|
||||
* GPIO_39 PH7 PF39
|
||||
* GPIO_40 PH8 PF40
|
||||
* GPIO_41 PH9 PF41
|
||||
* GPIO_42 PH10 PF42
|
||||
* GPIO_43 PH11 PF43
|
||||
* GPIO_44 PH12 PF44
|
||||
* GPIO_45 PH13 PF45
|
||||
* GPIO_46 PH14 PF46
|
||||
* GPIO_47 PH15 PF47
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#ifdef BF533_FAMILY
|
||||
static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
|
||||
(struct gpio_port_t *) FIO_FLAG_D,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BF537_FAMILY
|
||||
static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
|
||||
(struct gpio_port_t *) PORTFIO,
|
||||
(struct gpio_port_t *) PORTGIO,
|
||||
(struct gpio_port_t *) PORTHIO,
|
||||
};
|
||||
|
||||
static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
|
||||
(unsigned short *) PORTF_FER,
|
||||
(unsigned short *) PORTG_FER,
|
||||
(unsigned short *) PORTH_FER,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BF561_FAMILY
|
||||
static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
|
||||
(struct gpio_port_t *) FIO0_FLAG_D,
|
||||
(struct gpio_port_t *) FIO1_FLAG_D,
|
||||
(struct gpio_port_t *) FIO2_FLAG_D,
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
|
||||
static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
|
||||
#ifdef BF533_FAMILY
|
||||
static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};
|
||||
#endif
|
||||
|
||||
#ifdef BF537_FAMILY
|
||||
static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
|
||||
#endif
|
||||
|
||||
#ifdef BF561_FAMILY
|
||||
static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
inline int check_gpio(unsigned short gpio)
|
||||
{
|
||||
if (gpio > MAX_BLACKFIN_GPIOS)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BF537_FAMILY
|
||||
void port_setup(unsigned short gpio, unsigned short usage)
|
||||
{
|
||||
if (usage == GPIO_USAGE) {
|
||||
if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
|
||||
printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
|
||||
"usage and GPIO %d detected!\n", gpio);
|
||||
*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
|
||||
} else
|
||||
*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
|
||||
SSYNC();
|
||||
}
|
||||
#else
|
||||
# define port_setup(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
void default_gpio(unsigned short gpio)
|
||||
{
|
||||
unsigned short bank,bitmask;
|
||||
|
||||
bank = gpio_bank(gpio);
|
||||
bitmask = gpio_bit(gpio);
|
||||
|
||||
gpio_bankb[bank]->maska_clear = bitmask;
|
||||
gpio_bankb[bank]->maskb_clear = bitmask;
|
||||
SSYNC();
|
||||
gpio_bankb[bank]->inen &= ~bitmask;
|
||||
gpio_bankb[bank]->dir &= ~bitmask;
|
||||
gpio_bankb[bank]->polar &= ~bitmask;
|
||||
gpio_bankb[bank]->both &= ~bitmask;
|
||||
gpio_bankb[bank]->edge &= ~bitmask;
|
||||
}
|
||||
|
||||
|
||||
int __init bfin_gpio_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "Blackfin GPIO Controller\n");
|
||||
|
||||
for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
|
||||
reserved_map[gpio_bank(i)] = 0;
|
||||
|
||||
#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
|
||||
# if defined(CONFIG_BFIN_MAC_RMII)
|
||||
reserved_map[PORT_H] = 0xC373;
|
||||
# else
|
||||
reserved_map[PORT_H] = 0xFFFF;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(bfin_gpio_init);
|
||||
|
||||
|
||||
/***********************************************************
|
||||
*
|
||||
* FUNCTIONS: Blackfin General Purpose Ports Access Functions
|
||||
*
|
||||
* INPUTS/OUTPUTS:
|
||||
* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
|
||||
*
|
||||
*
|
||||
* DESCRIPTION: These functions abstract direct register access
|
||||
* to Blackfin processor General Purpose
|
||||
* Ports Regsiters
|
||||
*
|
||||
* CAUTION: These functions do not belong to the GPIO Driver API
|
||||
*************************************************************
|
||||
* MODIFICATION HISTORY :
|
||||
**************************************************************/
|
||||
|
||||
/* Set a specific bit */
|
||||
|
||||
#define SET_GPIO(name) \
|
||||
void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
|
||||
{ \
|
||||
unsigned long flags; \
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
|
||||
local_irq_save(flags); \
|
||||
if (arg) \
|
||||
gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
|
||||
else \
|
||||
gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
|
||||
local_irq_restore(flags); \
|
||||
} \
|
||||
EXPORT_SYMBOL(set_gpio_ ## name);
|
||||
|
||||
SET_GPIO(dir)
|
||||
SET_GPIO(inen)
|
||||
SET_GPIO(polar)
|
||||
SET_GPIO(edge)
|
||||
SET_GPIO(both)
|
||||
|
||||
|
||||
#define SET_GPIO_SC(name) \
|
||||
void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
|
||||
{ \
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
|
||||
if (arg) \
|
||||
gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
|
||||
else \
|
||||
gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
|
||||
} \
|
||||
EXPORT_SYMBOL(set_gpio_ ## name);
|
||||
|
||||
SET_GPIO_SC(maska)
|
||||
SET_GPIO_SC(maskb)
|
||||
|
||||
#if defined(ANOMALY_05000311)
|
||||
void set_gpio_data(unsigned short gpio, unsigned short arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
local_irq_save(flags);
|
||||
if (arg)
|
||||
gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
|
||||
else
|
||||
gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
|
||||
bfin_read_CHIPID();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(set_gpio_data);
|
||||
#else
|
||||
SET_GPIO_SC(data)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(ANOMALY_05000311)
|
||||
void set_gpio_toggle(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
local_irq_save(flags);
|
||||
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
|
||||
bfin_read_CHIPID();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#else
|
||||
void set_gpio_toggle(unsigned short gpio)
|
||||
{
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
|
||||
}
|
||||
#endif
|
||||
EXPORT_SYMBOL(set_gpio_toggle);
|
||||
|
||||
|
||||
/*Set current PORT date (16-bit word)*/
|
||||
|
||||
#define SET_GPIO_P(name) \
|
||||
void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
|
||||
{ \
|
||||
gpio_bankb[gpio_bank(gpio)]->name = arg; \
|
||||
} \
|
||||
EXPORT_SYMBOL(set_gpiop_ ## name);
|
||||
|
||||
SET_GPIO_P(dir)
|
||||
SET_GPIO_P(inen)
|
||||
SET_GPIO_P(polar)
|
||||
SET_GPIO_P(edge)
|
||||
SET_GPIO_P(both)
|
||||
SET_GPIO_P(maska)
|
||||
SET_GPIO_P(maskb)
|
||||
|
||||
|
||||
#if defined(ANOMALY_05000311)
|
||||
void set_gpiop_data(unsigned short gpio, unsigned short arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
gpio_bankb[gpio_bank(gpio)]->data = arg;
|
||||
bfin_read_CHIPID();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(set_gpiop_data);
|
||||
#else
|
||||
SET_GPIO_P(data)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Get a specific bit */
|
||||
|
||||
#define GET_GPIO(name) \
|
||||
unsigned short get_gpio_ ## name(unsigned short gpio) \
|
||||
{ \
|
||||
return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
|
||||
} \
|
||||
EXPORT_SYMBOL(get_gpio_ ## name);
|
||||
|
||||
GET_GPIO(dir)
|
||||
GET_GPIO(inen)
|
||||
GET_GPIO(polar)
|
||||
GET_GPIO(edge)
|
||||
GET_GPIO(both)
|
||||
GET_GPIO(maska)
|
||||
GET_GPIO(maskb)
|
||||
|
||||
|
||||
#if defined(ANOMALY_05000311)
|
||||
unsigned short get_gpio_data(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned short ret;
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
local_irq_save(flags);
|
||||
ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
|
||||
bfin_read_CHIPID();
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_gpio_data);
|
||||
#else
|
||||
GET_GPIO(data)
|
||||
#endif
|
||||
|
||||
/*Get current PORT date (16-bit word)*/
|
||||
|
||||
#define GET_GPIO_P(name) \
|
||||
unsigned short get_gpiop_ ## name(unsigned short gpio) \
|
||||
{ \
|
||||
return (gpio_bankb[gpio_bank(gpio)]->name);\
|
||||
} \
|
||||
EXPORT_SYMBOL(get_gpiop_ ## name);
|
||||
|
||||
GET_GPIO_P(dir)
|
||||
GET_GPIO_P(inen)
|
||||
GET_GPIO_P(polar)
|
||||
GET_GPIO_P(edge)
|
||||
GET_GPIO_P(both)
|
||||
GET_GPIO_P(maska)
|
||||
GET_GPIO_P(maskb)
|
||||
|
||||
#if defined(ANOMALY_05000311)
|
||||
unsigned short get_gpiop_data(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned short ret;
|
||||
local_irq_save(flags);
|
||||
ret = gpio_bankb[gpio_bank(gpio)]->data;
|
||||
bfin_read_CHIPID();
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(get_gpiop_data);
|
||||
#else
|
||||
GET_GPIO_P(data)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/***********************************************************
|
||||
*
|
||||
* FUNCTIONS: Blackfin PM Setup API
|
||||
*
|
||||
* INPUTS/OUTPUTS:
|
||||
* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
|
||||
* type -
|
||||
* PM_WAKE_RISING
|
||||
* PM_WAKE_FALLING
|
||||
* PM_WAKE_HIGH
|
||||
* PM_WAKE_LOW
|
||||
* PM_WAKE_BOTH_EDGES
|
||||
*
|
||||
* DESCRIPTION: Blackfin PM Driver API
|
||||
*
|
||||
* CAUTION:
|
||||
*************************************************************
|
||||
* MODIFICATION HISTORY :
|
||||
**************************************************************/
|
||||
int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if ((check_gpio(gpio) < 0) || !type)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
|
||||
wakeup_flags_map[gpio] = type;
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_pm_wakeup_request);
|
||||
|
||||
void gpio_pm_wakeup_free(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_pm_wakeup_free);
|
||||
|
||||
static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
|
||||
{
|
||||
port_setup(gpio, GPIO_USAGE);
|
||||
set_gpio_dir(gpio, 0);
|
||||
set_gpio_inen(gpio, 1);
|
||||
|
||||
if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
|
||||
set_gpio_edge(gpio, 1);
|
||||
else
|
||||
set_gpio_edge(gpio, 0);
|
||||
|
||||
if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
|
||||
set_gpio_both(gpio, 1);
|
||||
else
|
||||
set_gpio_both(gpio, 0);
|
||||
|
||||
if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
|
||||
set_gpio_polar(gpio, 1);
|
||||
else
|
||||
set_gpio_polar(gpio, 0);
|
||||
|
||||
SSYNC();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 gpio_pm_setup(void)
|
||||
{
|
||||
u32 sic_iwr = 0;
|
||||
u16 bank, mask, i, gpio;
|
||||
|
||||
for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
|
||||
mask = wakeup_map[gpio_bank(i)];
|
||||
bank = gpio_bank(i);
|
||||
|
||||
gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb;
|
||||
gpio_bankb[bank]->maskb = 0;
|
||||
|
||||
if (mask) {
|
||||
#ifdef BF537_FAMILY
|
||||
gpio_bank_saved[bank].fer = *port_fer[bank];
|
||||
#endif
|
||||
gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
|
||||
gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
|
||||
gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
|
||||
gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
|
||||
gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
|
||||
|
||||
gpio = i;
|
||||
|
||||
while (mask) {
|
||||
if (mask & 1) {
|
||||
bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]);
|
||||
set_gpio_data(gpio, 0); /*Clear*/
|
||||
}
|
||||
gpio++;
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
|
||||
gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
|
||||
}
|
||||
}
|
||||
|
||||
if (sic_iwr)
|
||||
return sic_iwr;
|
||||
else
|
||||
return IWR_ENABLE_ALL;
|
||||
}
|
||||
|
||||
|
||||
void gpio_pm_restore(void)
|
||||
{
|
||||
u16 bank, mask, i;
|
||||
|
||||
for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
|
||||
mask = wakeup_map[gpio_bank(i)];
|
||||
bank = gpio_bank(i);
|
||||
|
||||
if (mask) {
|
||||
#ifdef BF537_FAMILY
|
||||
*port_fer[bank] = gpio_bank_saved[bank].fer;
|
||||
#endif
|
||||
gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
|
||||
gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir;
|
||||
gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
|
||||
gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
|
||||
gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
|
||||
}
|
||||
|
||||
gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************
|
||||
*
|
||||
* FUNCTIONS: Blackfin GPIO Driver
|
||||
*
|
||||
* INPUTS/OUTPUTS:
|
||||
* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
|
||||
*
|
||||
*
|
||||
* DESCRIPTION: Blackfin GPIO Driver API
|
||||
*
|
||||
* CAUTION:
|
||||
*************************************************************
|
||||
* MODIFICATION HISTORY :
|
||||
**************************************************************/
|
||||
|
||||
int gpio_request(unsigned short gpio, const char *label)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
|
||||
printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
|
||||
dump_stack();
|
||||
local_irq_restore(flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
port_setup(gpio, GPIO_USAGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_request);
|
||||
|
||||
|
||||
void gpio_free(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (check_gpio(gpio) < 0)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
|
||||
printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
|
||||
dump_stack();
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
default_gpio(gpio);
|
||||
|
||||
reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_free);
|
||||
|
||||
|
||||
void gpio_direction_input(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
|
||||
local_irq_save(flags);
|
||||
gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
|
||||
gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_input);
|
||||
|
||||
void gpio_direction_output(unsigned short gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
|
||||
|
||||
local_irq_save(flags);
|
||||
gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
|
||||
gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_output);
|
119
arch/blackfin/kernel/bfin_ksyms.c
Normal file
119
arch/blackfin/kernel/bfin_ksyms.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/bfin_ksyms.c
|
||||
* Based on: none - original work
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/checksum.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/* platform dependent support */
|
||||
|
||||
EXPORT_SYMBOL(__ioremap);
|
||||
EXPORT_SYMBOL(strcmp);
|
||||
EXPORT_SYMBOL(strncmp);
|
||||
EXPORT_SYMBOL(dump_thread);
|
||||
|
||||
EXPORT_SYMBOL(ip_fast_csum);
|
||||
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
EXPORT_SYMBOL(__up);
|
||||
EXPORT_SYMBOL(__down);
|
||||
EXPORT_SYMBOL(__down_trylock);
|
||||
EXPORT_SYMBOL(__down_interruptible);
|
||||
|
||||
EXPORT_SYMBOL(is_in_rom);
|
||||
|
||||
/* Networking helper routines. */
|
||||
EXPORT_SYMBOL(csum_partial_copy);
|
||||
|
||||
/* The following are special because they're not called
|
||||
* explicitly (the C compiler generates them). Fortunately,
|
||||
* their interface isn't gonna change any time soon now, so
|
||||
* it's OK to leave it out of version control.
|
||||
*/
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(memcmp);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(memchr);
|
||||
EXPORT_SYMBOL(get_wchan);
|
||||
|
||||
/*
|
||||
* libgcc functions - functions that are used internally by the
|
||||
* compiler... (prototypes are not correct though, but that
|
||||
* doesn't really matter since they're not versioned).
|
||||
*/
|
||||
extern void __ashldi3(void);
|
||||
extern void __ashrdi3(void);
|
||||
extern void __smulsi3_highpart(void);
|
||||
extern void __umulsi3_highpart(void);
|
||||
extern void __divsi3(void);
|
||||
extern void __lshrdi3(void);
|
||||
extern void __modsi3(void);
|
||||
extern void __muldi3(void);
|
||||
extern void __udivsi3(void);
|
||||
extern void __umodsi3(void);
|
||||
|
||||
/* gcc lib functions */
|
||||
EXPORT_SYMBOL(__ashldi3);
|
||||
EXPORT_SYMBOL(__ashrdi3);
|
||||
EXPORT_SYMBOL(__umulsi3_highpart);
|
||||
EXPORT_SYMBOL(__smulsi3_highpart);
|
||||
EXPORT_SYMBOL(__divsi3);
|
||||
EXPORT_SYMBOL(__lshrdi3);
|
||||
EXPORT_SYMBOL(__modsi3);
|
||||
EXPORT_SYMBOL(__muldi3);
|
||||
EXPORT_SYMBOL(__udivsi3);
|
||||
EXPORT_SYMBOL(__umodsi3);
|
||||
|
||||
EXPORT_SYMBOL(outsb);
|
||||
EXPORT_SYMBOL(insb);
|
||||
EXPORT_SYMBOL(outsw);
|
||||
EXPORT_SYMBOL(insw);
|
||||
EXPORT_SYMBOL(outsl);
|
||||
EXPORT_SYMBOL(insl);
|
||||
EXPORT_SYMBOL(irq_flags);
|
||||
EXPORT_SYMBOL(iounmap);
|
||||
EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
|
||||
EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
|
||||
EXPORT_SYMBOL(blackfin_icache_flush_range);
|
||||
EXPORT_SYMBOL(blackfin_dcache_flush_range);
|
||||
EXPORT_SYMBOL(blackfin_dflush_page);
|
||||
|
||||
EXPORT_SYMBOL(csum_partial);
|
||||
EXPORT_SYMBOL(__init_begin);
|
||||
EXPORT_SYMBOL(__init_end);
|
||||
EXPORT_SYMBOL(_ebss_l1);
|
||||
EXPORT_SYMBOL(_stext_l1);
|
||||
EXPORT_SYMBOL(_etext_l1);
|
||||
EXPORT_SYMBOL(_sdata_l1);
|
||||
EXPORT_SYMBOL(_ebss_b_l1);
|
||||
EXPORT_SYMBOL(_sdata_b_l1);
|
183
arch/blackfin/kernel/dma-mapping.c
Normal file
183
arch/blackfin/kernel/dma-mapping.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/dma-mapping.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: Dynamic DMA mapping support.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/bfin-global.h>
|
||||
|
||||
static spinlock_t dma_page_lock;
|
||||
static unsigned int *dma_page;
|
||||
static unsigned int dma_pages;
|
||||
static unsigned long dma_base;
|
||||
static unsigned long dma_size;
|
||||
static unsigned int dma_initialized;
|
||||
|
||||
void dma_alloc_init(unsigned long start, unsigned long end)
|
||||
{
|
||||
spin_lock_init(&dma_page_lock);
|
||||
dma_initialized = 0;
|
||||
|
||||
dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
|
||||
memset(dma_page, 0, PAGE_SIZE);
|
||||
dma_base = PAGE_ALIGN(start);
|
||||
dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
|
||||
dma_pages = dma_size >> PAGE_SHIFT;
|
||||
memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
|
||||
dma_initialized = 1;
|
||||
|
||||
printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
|
||||
dma_page, dma_pages, dma_base);
|
||||
}
|
||||
|
||||
static inline unsigned int get_pages(size_t size)
|
||||
{
|
||||
return ((size - 1) >> PAGE_SHIFT) + 1;
|
||||
}
|
||||
|
||||
static unsigned long __alloc_dma_pages(unsigned int pages)
|
||||
{
|
||||
unsigned long ret = 0, flags;
|
||||
int i, count = 0;
|
||||
|
||||
if (dma_initialized == 0)
|
||||
dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
|
||||
|
||||
spin_lock_irqsave(&dma_page_lock, flags);
|
||||
|
||||
for (i = 0; i < dma_pages;) {
|
||||
if (dma_page[i++] == 0) {
|
||||
if (++count == pages) {
|
||||
while (count--)
|
||||
dma_page[--i] = 1;
|
||||
ret = dma_base + (i << PAGE_SHIFT);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
count = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&dma_page_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __free_dma_pages(unsigned long addr, unsigned int pages)
|
||||
{
|
||||
unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if ((page + pages) > dma_pages) {
|
||||
printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
|
||||
BUG();
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dma_page_lock, flags);
|
||||
for (i = page; i < page + pages; i++) {
|
||||
dma_page[i] = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&dma_page_lock, flags);
|
||||
}
|
||||
|
||||
void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t * dma_handle, gfp_t gfp)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
ret = (void *)__alloc_dma_pages(get_pages(size));
|
||||
|
||||
if (ret) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = virt_to_phys(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_alloc_coherent);
|
||||
|
||||
void
|
||||
dma_free_coherent(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle)
|
||||
{
|
||||
__free_dma_pages((unsigned long)vaddr, get_pages(size));
|
||||
}
|
||||
EXPORT_SYMBOL(dma_free_coherent);
|
||||
|
||||
/*
|
||||
* Dummy functions defined for some existing drivers
|
||||
*/
|
||||
|
||||
dma_addr_t
|
||||
dma_map_single(struct device *dev, void *ptr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
invalidate_dcache_range((unsigned long)ptr,
|
||||
(unsigned long)ptr + size);
|
||||
|
||||
return (dma_addr_t) ptr;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_map_single);
|
||||
|
||||
int
|
||||
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
int i;
|
||||
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
for (i = 0; i < nents; i++)
|
||||
invalidate_dcache_range(sg_dma_address(&sg[i]),
|
||||
sg_dma_address(&sg[i]) +
|
||||
sg_dma_len(&sg[i]));
|
||||
|
||||
return nents;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_map_sg);
|
||||
|
||||
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_unmap_single);
|
||||
|
||||
void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nhwentries, enum dma_data_direction direction)
|
||||
{
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_unmap_sg);
|
49
arch/blackfin/kernel/dualcore_test.c
Normal file
49
arch/blackfin/kernel/dualcore_test.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/dualcore_test.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: Small test code for CoreB on a BF561
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static int *testarg = (int*)0xfeb00000;
|
||||
|
||||
static int test_init(void)
|
||||
{
|
||||
*testarg = 1;
|
||||
printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
|
||||
*testarg, testarg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_exit(void)
|
||||
{
|
||||
printk("Dual core test module removed: testarg = [%d]\n", *testarg);
|
||||
}
|
||||
|
||||
module_init(test_init);
|
||||
module_exit(test_exit);
|
94
arch/blackfin/kernel/entry.S
Normal file
94
arch/blackfin/kernel/entry.S
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/entry.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
#include <asm/mach-common/context.S>
|
||||
|
||||
#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
ENTRY(_ret_from_fork)
|
||||
SP += -12;
|
||||
call _schedule_tail;
|
||||
SP += 12;
|
||||
r0 = [sp + PT_IPEND];
|
||||
cc = bittst(r0,1);
|
||||
if cc jump .Lin_kernel;
|
||||
RESTORE_CONTEXT
|
||||
rti;
|
||||
.Lin_kernel:
|
||||
bitclr(r0,1);
|
||||
[sp + PT_IPEND] = r0;
|
||||
/* do a 'fake' RTI by jumping to [RETI]
|
||||
* to avoid clearing supervisor mode in child
|
||||
*/
|
||||
RESTORE_ALL_SYS
|
||||
p0 = reti;
|
||||
jump (p0);
|
||||
|
||||
ENTRY(_sys_fork)
|
||||
r0 = -EINVAL;
|
||||
rts;
|
||||
|
||||
ENTRY(_sys_vfork)
|
||||
r0 = sp;
|
||||
r0 += 24;
|
||||
[--sp] = rets;
|
||||
SP += -12;
|
||||
call _bfin_vfork;
|
||||
SP += 12;
|
||||
rets = [sp++];
|
||||
rts;
|
||||
|
||||
ENTRY(_sys_clone)
|
||||
r0 = sp;
|
||||
r0 += 24;
|
||||
[--sp] = rets;
|
||||
SP += -12;
|
||||
call _bfin_clone;
|
||||
SP += 12;
|
||||
rets = [sp++];
|
||||
rts;
|
||||
|
||||
ENTRY(_sys_rt_sigreturn)
|
||||
r0 = sp;
|
||||
r0 += 24;
|
||||
[--sp] = rets;
|
||||
SP += -12;
|
||||
call _do_rt_sigreturn;
|
||||
SP += 12;
|
||||
rets = [sp++];
|
||||
rts;
|
101
arch/blackfin/kernel/flat.c
Normal file
101
arch/blackfin/kernel/flat.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* arch/blackfin/kernel/flat.c
|
||||
*
|
||||
* Copyright (C) 2007 Analog Devices, Inc.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/flat.h>
|
||||
|
||||
#define FLAT_BFIN_RELOC_TYPE_16_BIT 0
|
||||
#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
|
||||
#define FLAT_BFIN_RELOC_TYPE_32_BIT 2
|
||||
|
||||
unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
|
||||
unsigned long relval,
|
||||
unsigned long flags,
|
||||
unsigned long *persistent)
|
||||
{
|
||||
unsigned short *usptr = (unsigned short *)ptr;
|
||||
int type = (relval >> 26) & 7;
|
||||
unsigned long val;
|
||||
|
||||
switch (type) {
|
||||
case FLAT_BFIN_RELOC_TYPE_16_BIT:
|
||||
case FLAT_BFIN_RELOC_TYPE_16H_BIT:
|
||||
usptr = (unsigned short *)ptr;
|
||||
pr_debug("*usptr = %x", get_unaligned(usptr));
|
||||
val = get_unaligned(usptr);
|
||||
val += *persistent;
|
||||
break;
|
||||
|
||||
case FLAT_BFIN_RELOC_TYPE_32_BIT:
|
||||
pr_debug("*ptr = %lx", get_unaligned(ptr));
|
||||
val = get_unaligned(ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
|
||||
type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack-relative relocs contain the offset into the stack, we
|
||||
* have to add the stack's start address here and return 1 from
|
||||
* flat_addr_absolute to prevent the normal address calculations
|
||||
*/
|
||||
if (relval & (1 << 29))
|
||||
return val + current->mm->context.end_brk;
|
||||
|
||||
if ((flags & FLAT_FLAG_GOTPIC) == 0)
|
||||
val = htonl(val);
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL(bfin_get_addr_from_rp);
|
||||
|
||||
/*
|
||||
* Insert the address ADDR into the symbol reference at RP;
|
||||
* RELVAL is the raw relocation-table entry from which RP is derived
|
||||
*/
|
||||
void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
|
||||
unsigned long relval)
|
||||
{
|
||||
unsigned short *usptr = (unsigned short *)ptr;
|
||||
int type = (relval >> 26) & 7;
|
||||
|
||||
switch (type) {
|
||||
case FLAT_BFIN_RELOC_TYPE_16_BIT:
|
||||
put_unaligned(addr, usptr);
|
||||
pr_debug("new value %x at %p", get_unaligned(usptr),
|
||||
usptr);
|
||||
break;
|
||||
|
||||
case FLAT_BFIN_RELOC_TYPE_16H_BIT:
|
||||
put_unaligned(addr >> 16, usptr);
|
||||
pr_debug("new value %x", get_unaligned(usptr));
|
||||
break;
|
||||
|
||||
case FLAT_BFIN_RELOC_TYPE_32_BIT:
|
||||
put_unaligned(addr, ptr);
|
||||
pr_debug("new ptr =%lx", get_unaligned(ptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bfin_put_addr_at_rp);
|
60
arch/blackfin/kernel/init_task.c
Normal file
60
arch/blackfin/kernel/init_task.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/init_task.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init_task.h>
|
||||
#include <linux/mqueue.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct files_struct init_files = INIT_FILES;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
EXPORT_SYMBOL(init_mm);
|
||||
|
||||
/*
|
||||
* Initial task structure.
|
||||
*
|
||||
* All other task structs will be allocated on slabs in fork.c
|
||||
*/
|
||||
struct task_struct init_task = INIT_TASK(init_task);
|
||||
EXPORT_SYMBOL(init_task);
|
||||
|
||||
/*
|
||||
* Initial thread structure.
|
||||
*
|
||||
* We need to make sure that this is 8192-byte aligned due to the
|
||||
* way process stacks are handled. This is done by having a special
|
||||
* "init_task" linker map entry.
|
||||
*/
|
||||
union thread_union init_thread_union
|
||||
__attribute__ ((__section__(".data.init_task"))) = {
|
||||
INIT_THREAD_INFO(init_task)};
|
147
arch/blackfin/kernel/irqchip.c
Normal file
147
arch/blackfin/kernel/irqchip.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/irqchip.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the simple DMA Implementation for Blackfin
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
static unsigned long irq_err_count;
|
||||
static spinlock_t irq_controller_lock;
|
||||
|
||||
/*
|
||||
* Dummy mask/unmask handler
|
||||
*/
|
||||
void dummy_mask_unmask_irq(unsigned int irq)
|
||||
{
|
||||
}
|
||||
|
||||
void ack_bad_irq(unsigned int irq)
|
||||
{
|
||||
irq_err_count += 1;
|
||||
printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
|
||||
}
|
||||
EXPORT_SYMBOL(ack_bad_irq);
|
||||
|
||||
static struct irq_chip bad_chip = {
|
||||
.ack = dummy_mask_unmask_irq,
|
||||
.mask = dummy_mask_unmask_irq,
|
||||
.unmask = dummy_mask_unmask_irq,
|
||||
};
|
||||
|
||||
static struct irq_desc bad_irq_desc = {
|
||||
.chip = &bad_chip,
|
||||
.handle_irq = handle_bad_irq,
|
||||
.depth = 1,
|
||||
};
|
||||
|
||||
int show_interrupts(struct seq_file *p, void *v)
|
||||
{
|
||||
int i = *(loff_t *) v;
|
||||
struct irqaction *action;
|
||||
unsigned long flags;
|
||||
|
||||
if (i < NR_IRQS) {
|
||||
spin_lock_irqsave(&irq_desc[i].lock, flags);
|
||||
action = irq_desc[i].action;
|
||||
if (!action)
|
||||
goto unlock;
|
||||
|
||||
seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
|
||||
seq_printf(p, " %s", action->name);
|
||||
for (action = action->next; action; action = action->next)
|
||||
seq_printf(p, ", %s", action->name);
|
||||
|
||||
seq_putc(p, '\n');
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
|
||||
} else if (i == NR_IRQS) {
|
||||
seq_printf(p, "Err: %10lu\n", irq_err_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_IRQ handles all hardware IRQ's. Decoded IRQs should not
|
||||
* come via this function. Instead, they should provide their
|
||||
* own 'handler'
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DO_IRQ_L1
|
||||
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
unsigned short pending, other_ints;
|
||||
|
||||
old_regs = set_irq_regs(regs);
|
||||
|
||||
/*
|
||||
* Some hardware gives randomly wrong interrupts. Rather
|
||||
* than crashing, do something sensible.
|
||||
*/
|
||||
if (irq >= NR_IRQS)
|
||||
desc = &bad_irq_desc;
|
||||
|
||||
irq_enter();
|
||||
|
||||
generic_handle_irq(irq);
|
||||
|
||||
/* If we're the only interrupt running (ignoring IRQ15 which is for
|
||||
syscalls), lower our priority to IRQ14 so that softirqs run at
|
||||
that level. If there's another, lower-level interrupt, irq_exit
|
||||
will defer softirqs to that. */
|
||||
CSYNC();
|
||||
pending = bfin_read_IPEND() & ~0x8000;
|
||||
other_ints = pending & (pending - 1);
|
||||
if (other_ints == 0)
|
||||
lower_to_irq14();
|
||||
irq_exit();
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
int irq;
|
||||
|
||||
spin_lock_init(&irq_controller_lock);
|
||||
for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
|
||||
*desc = bad_irq_desc;
|
||||
}
|
||||
|
||||
init_arch_irq();
|
||||
}
|
429
arch/blackfin/kernel/module.c
Normal file
429
arch/blackfin/kernel/module.c
Normal file
|
@ -0,0 +1,429 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/module.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/moduleloader.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
/*
|
||||
* handle arithmetic relocations.
|
||||
* See binutils/bfd/elf32-bfin.c for more details
|
||||
*/
|
||||
#define RELOC_STACK_SIZE 100
|
||||
static uint32_t reloc_stack[RELOC_STACK_SIZE];
|
||||
static unsigned int reloc_stack_tos;
|
||||
|
||||
#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
|
||||
|
||||
static void reloc_stack_push(uint32_t value)
|
||||
{
|
||||
reloc_stack[reloc_stack_tos++] = value;
|
||||
}
|
||||
|
||||
static uint32_t reloc_stack_pop(void)
|
||||
{
|
||||
return reloc_stack[--reloc_stack_tos];
|
||||
}
|
||||
|
||||
static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
switch (oper) {
|
||||
case R_add:
|
||||
value = reloc_stack[reloc_stack_tos - 2] +
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_sub:
|
||||
value = reloc_stack[reloc_stack_tos - 2] -
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_mult:
|
||||
value = reloc_stack[reloc_stack_tos - 2] *
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_div:
|
||||
value = reloc_stack[reloc_stack_tos - 2] /
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_mod:
|
||||
value = reloc_stack[reloc_stack_tos - 2] %
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_lshift:
|
||||
value = reloc_stack[reloc_stack_tos - 2] <<
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_rshift:
|
||||
value = reloc_stack[reloc_stack_tos - 2] >>
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_and:
|
||||
value = reloc_stack[reloc_stack_tos - 2] &
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_or:
|
||||
value = reloc_stack[reloc_stack_tos - 2] |
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_xor:
|
||||
value = reloc_stack[reloc_stack_tos - 2] ^
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_land:
|
||||
value = reloc_stack[reloc_stack_tos - 2] &&
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_lor:
|
||||
value = reloc_stack[reloc_stack_tos - 2] ||
|
||||
reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 2;
|
||||
break;
|
||||
case R_neg:
|
||||
value = -reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos--;
|
||||
break;
|
||||
case R_comp:
|
||||
value = ~reloc_stack[reloc_stack_tos - 1];
|
||||
reloc_stack_tos -= 1;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "module %s: unhandled reloction\n",
|
||||
mod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* now push the new value back on stack */
|
||||
reloc_stack_push(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void *module_alloc(unsigned long size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
return vmalloc(size);
|
||||
}
|
||||
|
||||
/* Free memory returned from module_alloc */
|
||||
void module_free(struct module *mod, void *module_region)
|
||||
{
|
||||
vfree(module_region);
|
||||
}
|
||||
|
||||
/* Transfer the section to the L1 memory */
|
||||
int
|
||||
module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
|
||||
char *secstrings, struct module *mod)
|
||||
{
|
||||
Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
|
||||
void *dest = NULL;
|
||||
|
||||
for (s = sechdrs; s < sechdrs_end; ++s) {
|
||||
if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
|
||||
((strcmp(".text", secstrings + s->sh_name)==0) &&
|
||||
(hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
|
||||
mod->arch.text_l1 = s;
|
||||
dest = l1_inst_sram_alloc(s->sh_size);
|
||||
if (dest == NULL) {
|
||||
printk(KERN_ERR
|
||||
"module %s: L1 instruction memory allocation failed\n",
|
||||
mod->name);
|
||||
return -1;
|
||||
}
|
||||
dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
s->sh_flags &= ~SHF_ALLOC;
|
||||
s->sh_addr = (unsigned long)dest;
|
||||
}
|
||||
if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
|
||||
((strcmp(".data", secstrings + s->sh_name)==0) &&
|
||||
(hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
|
||||
mod->arch.data_a_l1 = s;
|
||||
dest = l1_data_sram_alloc(s->sh_size);
|
||||
if (dest == NULL) {
|
||||
printk(KERN_ERR
|
||||
"module %s: L1 data memory allocation failed\n",
|
||||
mod->name);
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
s->sh_flags &= ~SHF_ALLOC;
|
||||
s->sh_addr = (unsigned long)dest;
|
||||
}
|
||||
if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
|
||||
((strcmp(".bss", secstrings + s->sh_name)==0) &&
|
||||
(hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
|
||||
mod->arch.bss_a_l1 = s;
|
||||
dest = l1_data_sram_alloc(s->sh_size);
|
||||
if (dest == NULL) {
|
||||
printk(KERN_ERR
|
||||
"module %s: L1 data memory allocation failed\n",
|
||||
mod->name);
|
||||
return -1;
|
||||
}
|
||||
memset(dest, 0, s->sh_size);
|
||||
s->sh_flags &= ~SHF_ALLOC;
|
||||
s->sh_addr = (unsigned long)dest;
|
||||
}
|
||||
if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
|
||||
mod->arch.data_b_l1 = s;
|
||||
dest = l1_data_B_sram_alloc(s->sh_size);
|
||||
if (dest == NULL) {
|
||||
printk(KERN_ERR
|
||||
"module %s: L1 data memory allocation failed\n",
|
||||
mod->name);
|
||||
return -1;
|
||||
}
|
||||
memcpy(dest, (void *)s->sh_addr, s->sh_size);
|
||||
s->sh_flags &= ~SHF_ALLOC;
|
||||
s->sh_addr = (unsigned long)dest;
|
||||
}
|
||||
if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
|
||||
mod->arch.bss_b_l1 = s;
|
||||
dest = l1_data_B_sram_alloc(s->sh_size);
|
||||
if (dest == NULL) {
|
||||
printk(KERN_ERR
|
||||
"module %s: L1 data memory allocation failed\n",
|
||||
mod->name);
|
||||
return -1;
|
||||
}
|
||||
memset(dest, 0, s->sh_size);
|
||||
s->sh_flags &= ~SHF_ALLOC;
|
||||
s->sh_addr = (unsigned long)dest;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec, struct module *me)
|
||||
{
|
||||
printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* FUNCTION : apply_relocate_add */
|
||||
/* ABSTRACT : Blackfin specific relocation handling for the loadable */
|
||||
/* modules. Modules are expected to be .o files. */
|
||||
/* Arithmetic relocations are handled. */
|
||||
/* We do not expect LSETUP to be split and hence is not */
|
||||
/* handled. */
|
||||
/* R_byte and R_byte2 are also not handled as the gas */
|
||||
/* does not generate it. */
|
||||
/*************************************************************************/
|
||||
int
|
||||
apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec,
|
||||
struct module *mod)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned short tmp;
|
||||
Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
|
||||
Elf32_Sym *sym;
|
||||
uint32_t *location32;
|
||||
uint16_t *location16;
|
||||
uint32_t value;
|
||||
|
||||
pr_debug("Applying relocate section %u to %u\n", relsec,
|
||||
sechdrs[relsec].sh_info);
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
location16 =
|
||||
(uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
|
||||
rel[i].r_offset);
|
||||
location32 = (uint32_t *) location16;
|
||||
/* This is the symbol it is referring to. Note that all
|
||||
undefined symbols have been resolved. */
|
||||
sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
|
||||
+ ELF32_R_SYM(rel[i].r_info);
|
||||
if (is_reloc_stack_empty()) {
|
||||
value = sym->st_value;
|
||||
} else {
|
||||
value = reloc_stack_pop();
|
||||
}
|
||||
value += rel[i].r_addend;
|
||||
pr_debug("location is %x, value is %x type is %d \n",
|
||||
(unsigned int) location32, value,
|
||||
ELF32_R_TYPE(rel[i].r_info));
|
||||
|
||||
switch (ELF32_R_TYPE(rel[i].r_info)) {
|
||||
|
||||
case R_pcrel24:
|
||||
case R_pcrel24_jump_l:
|
||||
/* Add the value, subtract its postition */
|
||||
location16 =
|
||||
(uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
|
||||
sh_addr + rel[i].r_offset - 2);
|
||||
location32 = (uint32_t *) location16;
|
||||
value -= (uint32_t) location32;
|
||||
value >>= 1;
|
||||
pr_debug("value is %x, before %x-%x after %x-%x\n", value,
|
||||
*location16, *(location16 + 1),
|
||||
(*location16 & 0xff00) | (value >> 16 & 0x00ff),
|
||||
value & 0xffff);
|
||||
*location16 =
|
||||
(*location16 & 0xff00) | (value >> 16 & 0x00ff);
|
||||
*(location16 + 1) = value & 0xffff;
|
||||
break;
|
||||
case R_pcrel12_jump:
|
||||
case R_pcrel12_jump_s:
|
||||
value -= (uint32_t) location32;
|
||||
value >>= 1;
|
||||
*location16 = (value & 0xfff);
|
||||
break;
|
||||
case R_pcrel10:
|
||||
value -= (uint32_t) location32;
|
||||
value >>= 1;
|
||||
*location16 = (value & 0x3ff);
|
||||
break;
|
||||
case R_luimm16:
|
||||
pr_debug("before %x after %x\n", *location16,
|
||||
(value & 0xffff));
|
||||
tmp = (value & 0xffff);
|
||||
if((unsigned long)location16 >= L1_CODE_START) {
|
||||
dma_memcpy(location16, &tmp, 2);
|
||||
} else
|
||||
*location16 = tmp;
|
||||
break;
|
||||
case R_huimm16:
|
||||
pr_debug("before %x after %x\n", *location16,
|
||||
((value >> 16) & 0xffff));
|
||||
tmp = ((value >> 16) & 0xffff);
|
||||
if((unsigned long)location16 >= L1_CODE_START) {
|
||||
dma_memcpy(location16, &tmp, 2);
|
||||
} else
|
||||
*location16 = tmp;
|
||||
break;
|
||||
case R_rimm16:
|
||||
*location16 = (value & 0xffff);
|
||||
break;
|
||||
case R_byte4_data:
|
||||
pr_debug("before %x after %x\n", *location32, value);
|
||||
*location32 = value;
|
||||
break;
|
||||
case R_push:
|
||||
reloc_stack_push(value);
|
||||
break;
|
||||
case R_const:
|
||||
reloc_stack_push(rel[i].r_addend);
|
||||
break;
|
||||
case R_add:
|
||||
case R_sub:
|
||||
case R_mult:
|
||||
case R_div:
|
||||
case R_mod:
|
||||
case R_lshift:
|
||||
case R_rshift:
|
||||
case R_and:
|
||||
case R_or:
|
||||
case R_xor:
|
||||
case R_land:
|
||||
case R_lor:
|
||||
case R_neg:
|
||||
case R_comp:
|
||||
reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "module %s: Unknown relocation: %u\n",
|
||||
mod->name, ELF32_R_TYPE(rel[i].r_info));
|
||||
return -ENOEXEC;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
module_finalize(const Elf_Ehdr * hdr,
|
||||
const Elf_Shdr * sechdrs, struct module *mod)
|
||||
{
|
||||
unsigned int i, strindex = 0, symindex = 0;
|
||||
char *secstrings;
|
||||
|
||||
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
|
||||
|
||||
for (i = 1; i < hdr->e_shnum; i++) {
|
||||
/* Internal symbols and strings. */
|
||||
if (sechdrs[i].sh_type == SHT_SYMTAB) {
|
||||
symindex = i;
|
||||
strindex = sechdrs[i].sh_link;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < hdr->e_shnum; i++) {
|
||||
const char *strtab = (char *)sechdrs[strindex].sh_addr;
|
||||
unsigned int info = sechdrs[i].sh_info;
|
||||
|
||||
/* Not a valid relocation section? */
|
||||
if (info >= hdr->e_shnum)
|
||||
continue;
|
||||
|
||||
if ((sechdrs[i].sh_type == SHT_RELA) &&
|
||||
((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
|
||||
((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
|
||||
(hdr->e_flags & FLG_CODE_IN_L1)))) {
|
||||
apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
|
||||
symindex, i, mod);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void module_arch_cleanup(struct module *mod)
|
||||
{
|
||||
if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
|
||||
l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
|
||||
if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
|
||||
l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
|
||||
if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
|
||||
l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
|
||||
if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
|
||||
l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
|
||||
if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
|
||||
l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
|
||||
}
|
394
arch/blackfin/kernel/process.c
Normal file
394
arch/blackfin/kernel/process.c
Normal file
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/process.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: Blackfin architecture-dependent process handling.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/a.out.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define LED_ON 0
|
||||
#define LED_OFF 1
|
||||
|
||||
asmlinkage void ret_from_fork(void);
|
||||
|
||||
/* Points to the SDRAM backup memory for the stack that is currently in
|
||||
* L1 scratchpad memory.
|
||||
*/
|
||||
void *current_l1_stack_save;
|
||||
|
||||
/* The number of tasks currently using a L1 stack area. The SRAM is
|
||||
* allocated/deallocated whenever this changes from/to zero.
|
||||
*/
|
||||
int nr_l1stack_tasks;
|
||||
|
||||
/* Start and length of the area in L1 scratchpad memory which we've allocated
|
||||
* for process stacks.
|
||||
*/
|
||||
void *l1_stack_base;
|
||||
unsigned long l1_stack_len;
|
||||
|
||||
/*
|
||||
* Powermanagement idle function, if any..
|
||||
*/
|
||||
void (*pm_idle)(void) = NULL;
|
||||
EXPORT_SYMBOL(pm_idle);
|
||||
|
||||
void (*pm_power_off)(void) = NULL;
|
||||
EXPORT_SYMBOL(pm_power_off);
|
||||
|
||||
/*
|
||||
* We are using a different LED from the one used to indicate timer interrupt.
|
||||
*/
|
||||
#if defined(CONFIG_BFIN_IDLE_LED)
|
||||
static inline void leds_switch(int flag)
|
||||
{
|
||||
unsigned short tmp = 0;
|
||||
|
||||
tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
|
||||
SSYNC();
|
||||
|
||||
if (flag == LED_ON)
|
||||
tmp &= ~CONFIG_BFIN_IDLE_LED_PIN; /* light on */
|
||||
else
|
||||
tmp |= CONFIG_BFIN_IDLE_LED_PIN; /* light off */
|
||||
|
||||
bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
|
||||
SSYNC();
|
||||
|
||||
}
|
||||
#else
|
||||
static inline void leds_switch(int flag)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The idle loop on BFIN
|
||||
*/
|
||||
#ifdef CONFIG_IDLE_L1
|
||||
void default_idle(void)__attribute__((l1_text));
|
||||
void cpu_idle(void)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
void default_idle(void)
|
||||
{
|
||||
while (!need_resched()) {
|
||||
leds_switch(LED_OFF);
|
||||
local_irq_disable();
|
||||
if (likely(!need_resched()))
|
||||
idle_with_irq_disabled();
|
||||
local_irq_enable();
|
||||
leds_switch(LED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void (*idle)(void) = default_idle;
|
||||
|
||||
/*
|
||||
* The idle thread. There's no useful work to be
|
||||
* done, so just try to conserve power and have a
|
||||
* low exit latency (ie sit in a loop waiting for
|
||||
* somebody to say that they'd like to reschedule)
|
||||
*/
|
||||
void cpu_idle(void)
|
||||
{
|
||||
/* endless idle loop with no priority at all */
|
||||
while (1) {
|
||||
idle();
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
}
|
||||
}
|
||||
|
||||
void machine_restart(char *__unused)
|
||||
{
|
||||
#if defined(CONFIG_BLKFIN_CACHE)
|
||||
bfin_write_IMEM_CONTROL(0x01);
|
||||
SSYNC();
|
||||
#endif
|
||||
bfin_reset();
|
||||
/* Dont do anything till the reset occurs */
|
||||
while (1) {
|
||||
SSYNC();
|
||||
}
|
||||
}
|
||||
|
||||
void machine_halt(void)
|
||||
{
|
||||
for (;;)
|
||||
asm volatile ("idle");
|
||||
}
|
||||
|
||||
void machine_power_off(void)
|
||||
{
|
||||
for (;;)
|
||||
asm volatile ("idle");
|
||||
}
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
printk(KERN_NOTICE "\n");
|
||||
printk(KERN_NOTICE
|
||||
"PC: %08lu Status: %04lu SysStatus: %04lu RETS: %08lu\n",
|
||||
regs->pc, regs->astat, regs->seqstat, regs->rets);
|
||||
printk(KERN_NOTICE
|
||||
"A0.x: %08lx A0.w: %08lx A1.x: %08lx A1.w: %08lx\n",
|
||||
regs->a0x, regs->a0w, regs->a1x, regs->a1w);
|
||||
printk(KERN_NOTICE "P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
|
||||
regs->p0, regs->p1, regs->p2, regs->p3);
|
||||
printk(KERN_NOTICE "P4: %08lx P5: %08lx\n", regs->p4, regs->p5);
|
||||
printk(KERN_NOTICE "R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
|
||||
if (!(regs->ipend))
|
||||
printk("USP: %08lx\n", rdusp());
|
||||
}
|
||||
|
||||
/* Fill in the fpu structure for a core dump. */
|
||||
|
||||
int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets run with P1 containing the
|
||||
* function to call, and R1 containing
|
||||
* the "args". Note P0 is clobbered on the way here.
|
||||
*/
|
||||
void kernel_thread_helper(void);
|
||||
__asm__(".section .text\n"
|
||||
".align 4\n"
|
||||
"_kernel_thread_helper:\n\t"
|
||||
"\tsp += -12;\n\t"
|
||||
"\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
|
||||
|
||||
/*
|
||||
* Create a kernel thread.
|
||||
*/
|
||||
pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
memset(®s, 0, sizeof(regs));
|
||||
|
||||
regs.r1 = (unsigned long)arg;
|
||||
regs.p1 = (unsigned long)fn;
|
||||
regs.pc = (unsigned long)kernel_thread_helper;
|
||||
regs.orig_p0 = -1;
|
||||
/* Set bit 2 to tell ret_from_fork we should be returning to kernel
|
||||
mode. */
|
||||
regs.ipend = 0x8002;
|
||||
__asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
|
||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
}
|
||||
|
||||
asmlinkage int bfin_vfork(struct pt_regs *regs)
|
||||
{
|
||||
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
asmlinkage int bfin_clone(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long clone_flags;
|
||||
unsigned long newsp;
|
||||
|
||||
/* syscall2 puts clone_flags in r0 and usp in r1 */
|
||||
clone_flags = regs->r0;
|
||||
newsp = regs->r1;
|
||||
if (!newsp)
|
||||
newsp = rdusp();
|
||||
else
|
||||
newsp -= 12;
|
||||
return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
copy_thread(int nr, unsigned long clone_flags,
|
||||
unsigned long usp, unsigned long topstk,
|
||||
struct task_struct *p, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *childregs;
|
||||
|
||||
childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
|
||||
*childregs = *regs;
|
||||
childregs->r0 = 0;
|
||||
|
||||
p->thread.usp = usp;
|
||||
p->thread.ksp = (unsigned long)childregs;
|
||||
p->thread.pc = (unsigned long)ret_from_fork;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in the user structure for a core dump..
|
||||
*/
|
||||
void dump_thread(struct pt_regs *regs, struct user *dump)
|
||||
{
|
||||
dump->magic = CMAGIC;
|
||||
dump->start_code = 0;
|
||||
dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
|
||||
dump->u_tsize = ((unsigned long)current->mm->end_code) >> PAGE_SHIFT;
|
||||
dump->u_dsize = ((unsigned long)(current->mm->brk +
|
||||
(PAGE_SIZE - 1))) >> PAGE_SHIFT;
|
||||
dump->u_dsize -= dump->u_tsize;
|
||||
dump->u_ssize = 0;
|
||||
|
||||
if (dump->start_stack < TASK_SIZE)
|
||||
dump->u_ssize =
|
||||
((unsigned long)(TASK_SIZE -
|
||||
dump->start_stack)) >> PAGE_SHIFT;
|
||||
|
||||
dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
|
||||
|
||||
dump->regs.r0 = regs->r0;
|
||||
dump->regs.r1 = regs->r1;
|
||||
dump->regs.r2 = regs->r2;
|
||||
dump->regs.r3 = regs->r3;
|
||||
dump->regs.r4 = regs->r4;
|
||||
dump->regs.r5 = regs->r5;
|
||||
dump->regs.r6 = regs->r6;
|
||||
dump->regs.r7 = regs->r7;
|
||||
dump->regs.p0 = regs->p0;
|
||||
dump->regs.p1 = regs->p1;
|
||||
dump->regs.p2 = regs->p2;
|
||||
dump->regs.p3 = regs->p3;
|
||||
dump->regs.p4 = regs->p4;
|
||||
dump->regs.p5 = regs->p5;
|
||||
dump->regs.orig_p0 = regs->orig_p0;
|
||||
dump->regs.a0w = regs->a0w;
|
||||
dump->regs.a1w = regs->a1w;
|
||||
dump->regs.a0x = regs->a0x;
|
||||
dump->regs.a1x = regs->a1x;
|
||||
dump->regs.rets = regs->rets;
|
||||
dump->regs.astat = regs->astat;
|
||||
dump->regs.pc = regs->pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_execve() executes a new program.
|
||||
*/
|
||||
|
||||
asmlinkage int sys_execve(char *name, char **argv, char **envp)
|
||||
{
|
||||
int error;
|
||||
char *filename;
|
||||
struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
|
||||
|
||||
lock_kernel();
|
||||
filename = getname(name);
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
goto out;
|
||||
error = do_execve(filename, argv, envp, regs);
|
||||
putname(filename);
|
||||
out:
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
unsigned long fp, pc;
|
||||
unsigned long stack_page;
|
||||
int count = 0;
|
||||
if (!p || p == current || p->state == TASK_RUNNING)
|
||||
return 0;
|
||||
|
||||
stack_page = (unsigned long)p;
|
||||
fp = p->thread.usp;
|
||||
do {
|
||||
if (fp < stack_page + sizeof(struct thread_info) ||
|
||||
fp >= 8184 + stack_page)
|
||||
return 0;
|
||||
pc = ((unsigned long *)fp)[1];
|
||||
if (!in_sched_functions(pc))
|
||||
return pc;
|
||||
fp = *(unsigned long *)fp;
|
||||
}
|
||||
while (count++ < 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ACCESS_CHECK)
|
||||
int _access_ok(unsigned long addr, unsigned long size)
|
||||
{
|
||||
|
||||
if (addr > (addr + size))
|
||||
return 0;
|
||||
if (segment_eq(get_fs(),KERNEL_DS))
|
||||
return 1;
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
if (addr >= memory_start && (addr + size) <= memory_end)
|
||||
return 1;
|
||||
if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
|
||||
return 1;
|
||||
#else
|
||||
if (addr >= memory_start && (addr + size) <= physical_mem_end)
|
||||
return 1;
|
||||
#endif
|
||||
if (addr >= (unsigned long)__init_begin &&
|
||||
addr + size <= (unsigned long)__init_end)
|
||||
return 1;
|
||||
if (addr >= L1_SCRATCH_START
|
||||
&& addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)
|
||||
return 1;
|
||||
#if L1_CODE_LENGTH != 0
|
||||
if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1)
|
||||
&& addr + size <= L1_CODE_START + L1_CODE_LENGTH)
|
||||
return 1;
|
||||
#endif
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1)
|
||||
&& addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)
|
||||
return 1;
|
||||
#endif
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
if (addr >= L1_DATA_B_START
|
||||
&& addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(_access_ok);
|
||||
#endif /* CONFIG_ACCESS_CHECK */
|
430
arch/blackfin/kernel/ptrace.c
Normal file
430
arch/blackfin/kernel/ptrace.c
Normal file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/ptrace.c
|
||||
* Based on: Taken from linux/kernel/ptrace.c
|
||||
* Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
|
||||
*
|
||||
* Created: 1/23/92
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/signal.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#define MAX_SHARED_LIBS 3
|
||||
#define TEXT_OFFSET 0
|
||||
/*
|
||||
* does not yet catch signals sent when the child dies.
|
||||
* in exit.c or in signal.c.
|
||||
*/
|
||||
|
||||
/* determines which bits in the SYSCFG reg the user has access to. */
|
||||
/* 1 = access 0 = no access */
|
||||
#define SYSCFG_MASK 0x0007 /* SYSCFG reg */
|
||||
/* sets the trace bits. */
|
||||
#define TRACE_BITS 0x0001
|
||||
|
||||
/* Find the stack offset for a register, relative to thread.esp0. */
|
||||
#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
|
||||
|
||||
/*
|
||||
* Get the address of the live pt_regs for the specified task.
|
||||
* These are saved onto the top kernel stack when the process
|
||||
* is not running.
|
||||
*
|
||||
* Note: if a user thread is execve'd from kernel space, the
|
||||
* kernel stack will not be empty on entry to the kernel, so
|
||||
* ptracing these tasks will fail.
|
||||
*/
|
||||
static inline struct pt_regs *get_user_regs(struct task_struct *task)
|
||||
{
|
||||
return (struct pt_regs *)
|
||||
((unsigned long)task->thread_info +
|
||||
(THREAD_SIZE - sizeof(struct pt_regs)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get all user integer registers.
|
||||
*/
|
||||
static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
|
||||
{
|
||||
struct pt_regs *regs = get_user_regs(tsk);
|
||||
return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
/* Mapping from PT_xxx to the stack offset at which the register is
|
||||
* saved. Notice that usp has no stack-slot and needs to be treated
|
||||
* specially (see get_reg/put_reg below).
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline long get_reg(struct task_struct *task, int regno)
|
||||
{
|
||||
unsigned char *reg_ptr;
|
||||
|
||||
struct pt_regs *regs =
|
||||
(struct pt_regs *)((unsigned long)task->thread_info +
|
||||
(THREAD_SIZE - sizeof(struct pt_regs)));
|
||||
reg_ptr = (char *)regs;
|
||||
|
||||
switch (regno) {
|
||||
case PT_USP:
|
||||
return task->thread.usp;
|
||||
default:
|
||||
if (regno <= 216)
|
||||
return *(long *)(reg_ptr + regno);
|
||||
}
|
||||
/* slight mystery ... never seems to come here but kernel misbehaves without this code! */
|
||||
|
||||
printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write contents of register REGNO in task TASK.
|
||||
*/
|
||||
static inline int
|
||||
put_reg(struct task_struct *task, int regno, unsigned long data)
|
||||
{
|
||||
char * reg_ptr;
|
||||
|
||||
struct pt_regs *regs =
|
||||
(struct pt_regs *)((unsigned long)task->thread_info +
|
||||
(THREAD_SIZE - sizeof(struct pt_regs)));
|
||||
reg_ptr = (char *)regs;
|
||||
|
||||
switch (regno) {
|
||||
case PT_PC:
|
||||
/*********************************************************************/
|
||||
/* At this point the kernel is most likely in exception. */
|
||||
/* The RETX register will be used to populate the pc of the process. */
|
||||
/*********************************************************************/
|
||||
regs->retx = data;
|
||||
regs->pc = data;
|
||||
break;
|
||||
case PT_RETX:
|
||||
break; /* regs->retx = data; break; */
|
||||
case PT_USP:
|
||||
regs->usp = data;
|
||||
task->thread.usp = data;
|
||||
break;
|
||||
default:
|
||||
if (regno <= 216)
|
||||
*(long *)(reg_ptr + regno) = data;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check that an address falls within the bounds of the target process's memory mappings
|
||||
*/
|
||||
static inline int is_user_addr_valid(struct task_struct *child,
|
||||
unsigned long start, unsigned long len)
|
||||
{
|
||||
struct vm_list_struct *vml;
|
||||
struct sram_list_struct *sraml;
|
||||
|
||||
for (vml = child->mm->context.vmlist; vml; vml = vml->next)
|
||||
if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
|
||||
return 0;
|
||||
|
||||
for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
|
||||
if (start >= (unsigned long)sraml->addr
|
||||
&& start + len <= (unsigned long)sraml->addr + sraml->length)
|
||||
return 0;
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Make sure the single step bit is not set.
|
||||
*/
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
unsigned long tmp;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
|
||||
put_reg(child, PT_SR, tmp);
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
{
|
||||
int ret;
|
||||
int add = 0;
|
||||
|
||||
switch (request) {
|
||||
/* when I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKDATA:
|
||||
pr_debug("ptrace: PEEKDATA\n");
|
||||
add = MAX_SHARED_LIBS * 4; /* space between text and data */
|
||||
/* fall through */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
{
|
||||
unsigned long tmp = 0;
|
||||
int copied;
|
||||
|
||||
ret = -EIO;
|
||||
pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
|
||||
sizeof(data));
|
||||
if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
|
||||
break;
|
||||
pr_debug("ptrace: user address is valid\n");
|
||||
|
||||
#if L1_CODE_LENGTH != 0
|
||||
if (addr + add >= L1_CODE_START
|
||||
&& addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
|
||||
safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
|
||||
copied = sizeof(tmp);
|
||||
} else
|
||||
#endif
|
||||
copied =
|
||||
access_process_vm(child, addr + add, &tmp,
|
||||
sizeof(tmp), 0);
|
||||
pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (unsigned long *)data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR:
|
||||
{
|
||||
unsigned long tmp;
|
||||
ret = -EIO;
|
||||
tmp = 0;
|
||||
if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
|
||||
printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
|
||||
"0 - %x sizeof(pt_regs) is %lx\n",
|
||||
(int)addr, sizeof(struct pt_regs));
|
||||
break;
|
||||
}
|
||||
if (addr == sizeof(struct pt_regs)) {
|
||||
/* PT_TEXT_ADDR */
|
||||
tmp = child->mm->start_code + TEXT_OFFSET;
|
||||
} else if (addr == (sizeof(struct pt_regs) + 4)) {
|
||||
/* PT_TEXT_END_ADDR */
|
||||
tmp = child->mm->end_code;
|
||||
} else if (addr == (sizeof(struct pt_regs) + 8)) {
|
||||
/* PT_DATA_ADDR */
|
||||
tmp = child->mm->start_data;
|
||||
#ifdef CONFIG_BINFMT_ELF_FDPIC
|
||||
} else if (addr == (sizeof(struct pt_regs) + 12)) {
|
||||
tmp = child->mm->context.exec_fdpic_loadmap;
|
||||
} else if (addr == (sizeof(struct pt_regs) + 16)) {
|
||||
tmp = child->mm->context.interp_fdpic_loadmap;
|
||||
#endif
|
||||
} else {
|
||||
tmp = get_reg(child, addr);
|
||||
}
|
||||
ret = put_user(tmp, (unsigned long *)data);
|
||||
break;
|
||||
}
|
||||
|
||||
/* when I and D space are separate, this will have to be fixed. */
|
||||
case PTRACE_POKEDATA:
|
||||
printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
|
||||
/* fall through */
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
{
|
||||
int copied;
|
||||
|
||||
ret = -EIO;
|
||||
pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
|
||||
addr, add, sizeof(data), data);
|
||||
if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
|
||||
break;
|
||||
pr_debug("ptrace: user address is valid\n");
|
||||
|
||||
#if L1_CODE_LENGTH != 0
|
||||
if (addr + add >= L1_CODE_START
|
||||
&& addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
|
||||
safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
|
||||
copied = sizeof(data);
|
||||
} else
|
||||
#endif
|
||||
copied =
|
||||
access_process_vm(child, addr + add, &data,
|
||||
sizeof(data), 1);
|
||||
pr_debug("ptrace: copied size %d\n", copied);
|
||||
if (copied != sizeof(data))
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
|
||||
printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (addr >= (sizeof(struct pt_regs))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (addr == PT_SYSCFG) {
|
||||
data &= SYSCFG_MASK;
|
||||
data |= get_reg(child, PT_SYSCFG);
|
||||
}
|
||||
ret = put_reg(child, addr, data);
|
||||
break;
|
||||
|
||||
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
|
||||
case PTRACE_CONT:
|
||||
{ /* restart after signal. */
|
||||
long tmp;
|
||||
|
||||
pr_debug("ptrace_cont\n");
|
||||
|
||||
ret = -EIO;
|
||||
if (!valid_signal(data))
|
||||
break;
|
||||
if (request == PTRACE_SYSCALL)
|
||||
set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
else
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
|
||||
child->exit_code = data;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
|
||||
put_reg(child, PT_SYSCFG, tmp);
|
||||
pr_debug("before wake_up_process\n");
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* make the child exit. Best I can do is send it a sigkill.
|
||||
* perhaps it should be put in the status that it wants to
|
||||
* exit.
|
||||
*/
|
||||
case PTRACE_KILL:
|
||||
{
|
||||
long tmp;
|
||||
ret = 0;
|
||||
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
|
||||
break;
|
||||
child->exit_code = SIGKILL;
|
||||
/* make sure the single step bit is not set. */
|
||||
tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
|
||||
put_reg(child, PT_SYSCFG, tmp);
|
||||
wake_up_process(child);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SINGLESTEP:
|
||||
{ /* set the trap flag. */
|
||||
long tmp;
|
||||
|
||||
pr_debug("single step\n");
|
||||
ret = -EIO;
|
||||
if (!valid_signal(data))
|
||||
break;
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
|
||||
tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
|
||||
put_reg(child, PT_SYSCFG, tmp);
|
||||
|
||||
child->exit_code = data;
|
||||
/* give it a chance to run. */
|
||||
wake_up_process(child);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_DETACH:
|
||||
{ /* detach a process that was attached. */
|
||||
ret = ptrace_detach(child, data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETREGS:
|
||||
{
|
||||
|
||||
/* Get all gp regs from the child. */
|
||||
ret = ptrace_getregs(child, (void __user *)data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS:
|
||||
{
|
||||
printk(KERN_NOTICE
|
||||
"ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
|
||||
/* Set all gp regs in the child. */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage void syscall_trace(void)
|
||||
{
|
||||
|
||||
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
return;
|
||||
|
||||
if (!(current->ptrace & PT_PTRACED))
|
||||
return;
|
||||
|
||||
/* the 0x80 provides a way for the tracing parent to distinguish
|
||||
* between a syscall stop and SIGTRAP delivery
|
||||
*/
|
||||
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
|
||||
? 0x80 : 0));
|
||||
|
||||
/*
|
||||
* this isn't the same as continuing with a signal, but it will do
|
||||
* for normal use. strace only continues with a signal if the
|
||||
* stopping signal is not SIGTRAP. -brl
|
||||
*/
|
||||
if (current->exit_code) {
|
||||
send_sig(current->exit_code, current, 1);
|
||||
current->exit_code = 0;
|
||||
}
|
||||
}
|
902
arch/blackfin/kernel/setup.c
Normal file
902
arch/blackfin/kernel/setup.c
Normal file
|
@ -0,0 +1,902 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/setup.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include <linux/ext2_fs.h>
|
||||
#include <linux/cramfs_fs.h>
|
||||
#include <linux/romfs_fs.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cplbinit.h>
|
||||
|
||||
unsigned long memory_start, memory_end, physical_mem_end;
|
||||
unsigned long reserved_mem_dcache_on;
|
||||
unsigned long reserved_mem_icache_on;
|
||||
EXPORT_SYMBOL(memory_start);
|
||||
EXPORT_SYMBOL(memory_end);
|
||||
EXPORT_SYMBOL(physical_mem_end);
|
||||
EXPORT_SYMBOL(_ramend);
|
||||
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
|
||||
unsigned long _ebss;
|
||||
EXPORT_SYMBOL(memory_mtd_end);
|
||||
EXPORT_SYMBOL(memory_mtd_start);
|
||||
EXPORT_SYMBOL(mtd_size);
|
||||
#endif
|
||||
|
||||
char command_line[COMMAND_LINE_SIZE];
|
||||
|
||||
#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
|
||||
static void generate_cpl_tables(void);
|
||||
#endif
|
||||
|
||||
void __init bf53x_cache_init(void)
|
||||
{
|
||||
#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
|
||||
generate_cpl_tables();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLKFIN_CACHE
|
||||
bfin_icache_init();
|
||||
printk(KERN_INFO "Instruction Cache Enabled\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLKFIN_DCACHE
|
||||
bfin_dcache_init();
|
||||
printk(KERN_INFO "Data Cache Enabled"
|
||||
# if defined CONFIG_BLKFIN_WB
|
||||
" (write-back)"
|
||||
# elif defined CONFIG_BLKFIN_WT
|
||||
" (write-through)"
|
||||
# endif
|
||||
"\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void bf53x_relocate_l1_mem(void)
|
||||
{
|
||||
unsigned long l1_code_length;
|
||||
unsigned long l1_data_a_length;
|
||||
unsigned long l1_data_b_length;
|
||||
|
||||
l1_code_length = _etext_l1 - _stext_l1;
|
||||
if (l1_code_length > L1_CODE_LENGTH)
|
||||
l1_code_length = L1_CODE_LENGTH;
|
||||
/* cannot complain as printk is not available as yet.
|
||||
* But we can continue booting and complain later!
|
||||
*/
|
||||
|
||||
/* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
|
||||
dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
|
||||
|
||||
l1_data_a_length = _ebss_l1 - _sdata_l1;
|
||||
if (l1_data_a_length > L1_DATA_A_LENGTH)
|
||||
l1_data_a_length = L1_DATA_A_LENGTH;
|
||||
|
||||
/* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
|
||||
dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
|
||||
|
||||
l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
|
||||
if (l1_data_b_length > L1_DATA_B_LENGTH)
|
||||
l1_data_b_length = L1_DATA_B_LENGTH;
|
||||
|
||||
/* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
|
||||
dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
|
||||
l1_data_a_length, l1_data_b_length);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Initial parsing of the command line. Currently, we support:
|
||||
* - Controlling the linux memory size: mem=xxx[KMG]
|
||||
* - Controlling the physical memory size: max_mem=xxx[KMG][$][#]
|
||||
* $ -> reserved memory is dcacheable
|
||||
* # -> reserved memory is icacheable
|
||||
*/
|
||||
static __init void parse_cmdline_early(char *cmdline_p)
|
||||
{
|
||||
char c = ' ', *to = cmdline_p;
|
||||
unsigned int memsize;
|
||||
for (;;) {
|
||||
if (c == ' ') {
|
||||
|
||||
if (!memcmp(to, "mem=", 4)) {
|
||||
to += 4;
|
||||
memsize = memparse(to, &to);
|
||||
if (memsize)
|
||||
_ramend = memsize;
|
||||
|
||||
} else if (!memcmp(to, "max_mem=", 8)) {
|
||||
to += 8;
|
||||
memsize = memparse(to, &to);
|
||||
if (memsize) {
|
||||
physical_mem_end = memsize;
|
||||
if (*to != ' ') {
|
||||
if (*to == '$'
|
||||
|| *(to + 1) == '$')
|
||||
reserved_mem_dcache_on =
|
||||
1;
|
||||
if (*to == '#'
|
||||
|| *(to + 1) == '#')
|
||||
reserved_mem_icache_on =
|
||||
1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
c = *(to++);
|
||||
if (!c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
int bootmap_size;
|
||||
unsigned long l1_length, sclk, cclk;
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
unsigned long mtd_phys = 0;
|
||||
#endif
|
||||
|
||||
cclk = get_cclk();
|
||||
sclk = get_sclk();
|
||||
|
||||
#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273)
|
||||
if (cclk == sclk)
|
||||
panic("ANOMALY 05000273, SCLK can not be same as CCLK");
|
||||
#endif
|
||||
|
||||
#if defined(ANOMALY_05000266)
|
||||
bfin_read_IMDMA_D0_IRQ_STATUS();
|
||||
bfin_read_IMDMA_D1_IRQ_STATUS();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SERIAL_EARLY_INIT
|
||||
bfin_console_init(); /* early console registration */
|
||||
/* this give a chance to get printk() working before crash. */
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
|
||||
/* we need to initialize the Flashrom device here since we might
|
||||
* do things with flash early on in the boot
|
||||
*/
|
||||
flash_probe();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CMDLINE_BOOL)
|
||||
memset(command_line, 0, sizeof(command_line));
|
||||
strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
|
||||
command_line[sizeof(command_line) - 1] = 0;
|
||||
#endif
|
||||
|
||||
/* Keep a copy of command line */
|
||||
*cmdline_p = &command_line[0];
|
||||
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
|
||||
boot_command_line[COMMAND_LINE_SIZE - 1] = 0;
|
||||
|
||||
/* setup memory defaults from the user config */
|
||||
physical_mem_end = 0;
|
||||
_ramend = CONFIG_MEM_SIZE * 1024 * 1024;
|
||||
|
||||
parse_cmdline_early(&command_line[0]);
|
||||
|
||||
if (physical_mem_end == 0)
|
||||
physical_mem_end = _ramend;
|
||||
|
||||
/* by now the stack is part of the init task */
|
||||
memory_end = _ramend - DMA_UNCACHED_REGION;
|
||||
|
||||
_ramstart = (unsigned long)__bss_stop;
|
||||
memory_start = PAGE_ALIGN(_ramstart);
|
||||
|
||||
#if defined(CONFIG_MTD_UCLINUX)
|
||||
/* generic memory mapped MTD driver */
|
||||
memory_mtd_end = memory_end;
|
||||
|
||||
mtd_phys = _ramstart;
|
||||
mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
|
||||
|
||||
# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
|
||||
if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
|
||||
mtd_size =
|
||||
PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_CRAMFS)
|
||||
if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC)
|
||||
mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4)));
|
||||
# endif
|
||||
|
||||
# if defined(CONFIG_ROMFS_FS)
|
||||
if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
|
||||
&& ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
|
||||
mtd_size =
|
||||
PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
|
||||
# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
|
||||
/* Due to a Hardware Anomaly we need to limit the size of usable
|
||||
* instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
|
||||
* 05000263 - Hardware loop corrupted when taking an ICPLB exception
|
||||
*/
|
||||
# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
|
||||
if (memory_end >= 56 * 1024 * 1024)
|
||||
memory_end = 56 * 1024 * 1024;
|
||||
# else
|
||||
if (memory_end >= 60 * 1024 * 1024)
|
||||
memory_end = 60 * 1024 * 1024;
|
||||
# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
|
||||
# endif /* ANOMALY_05000263 */
|
||||
# endif /* CONFIG_ROMFS_FS */
|
||||
|
||||
memory_end -= mtd_size;
|
||||
|
||||
if (mtd_size == 0) {
|
||||
console_init();
|
||||
panic("Don't boot kernel without rootfs attached.\n");
|
||||
}
|
||||
|
||||
/* Relocate MTD image to the top of memory after the uncached memory area */
|
||||
dma_memcpy((char *)memory_end, __bss_stop, mtd_size);
|
||||
|
||||
memory_mtd_start = memory_end;
|
||||
_ebss = memory_mtd_start; /* define _ebss for compatible */
|
||||
#endif /* CONFIG_MTD_UCLINUX */
|
||||
|
||||
#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
|
||||
/* Due to a Hardware Anomaly we need to limit the size of usable
|
||||
* instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
|
||||
* 05000263 - Hardware loop corrupted when taking an ICPLB exception
|
||||
*/
|
||||
#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
|
||||
if (memory_end >= 56 * 1024 * 1024)
|
||||
memory_end = 56 * 1024 * 1024;
|
||||
#else
|
||||
if (memory_end >= 60 * 1024 * 1024)
|
||||
memory_end = 60 * 1024 * 1024;
|
||||
#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
|
||||
printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
|
||||
#endif /* ANOMALY_05000263 */
|
||||
|
||||
#if !defined(CONFIG_MTD_UCLINUX)
|
||||
memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
|
||||
#endif
|
||||
init_mm.start_code = (unsigned long)_stext;
|
||||
init_mm.end_code = (unsigned long)_etext;
|
||||
init_mm.end_data = (unsigned long)_edata;
|
||||
init_mm.brk = (unsigned long)0;
|
||||
|
||||
init_leds();
|
||||
|
||||
printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n");
|
||||
printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
|
||||
if (bfin_revid() != bfin_compiled_revid())
|
||||
printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
|
||||
bfin_compiled_revid(), bfin_revid());
|
||||
if (bfin_revid() < SUPPORTED_REVID)
|
||||
printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
|
||||
CPU, bfin_revid());
|
||||
printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
|
||||
|
||||
printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
|
||||
cclk / 1000000, sclk / 1000000);
|
||||
|
||||
#if defined(ANOMALY_05000273)
|
||||
if ((cclk >> 1) <= sclk)
|
||||
printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
|
||||
printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
|
||||
|
||||
printk(KERN_INFO "Memory map:\n"
|
||||
KERN_INFO " text = 0x%p-0x%p\n"
|
||||
KERN_INFO " init = 0x%p-0x%p\n"
|
||||
KERN_INFO " data = 0x%p-0x%p\n"
|
||||
KERN_INFO " stack = 0x%p-0x%p\n"
|
||||
KERN_INFO " bss = 0x%p-0x%p\n"
|
||||
KERN_INFO " available = 0x%p-0x%p\n"
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
KERN_INFO " rootfs = 0x%p-0x%p\n"
|
||||
#endif
|
||||
#if DMA_UNCACHED_REGION > 0
|
||||
KERN_INFO " DMA Zone = 0x%p-0x%p\n"
|
||||
#endif
|
||||
, _stext, _etext,
|
||||
__init_begin, __init_end,
|
||||
_sdata, _edata,
|
||||
(void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
|
||||
__bss_start, __bss_stop,
|
||||
(void*)_ramstart, (void*)memory_end
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
, (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
|
||||
#endif
|
||||
#if DMA_UNCACHED_REGION > 0
|
||||
, (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
|
||||
#endif
|
||||
);
|
||||
|
||||
/*
|
||||
* 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, /* map goes here */
|
||||
PAGE_OFFSET >> PAGE_SHIFT,
|
||||
memory_end >> PAGE_SHIFT);
|
||||
/*
|
||||
* free the usable memory, we have to make sure we do not free
|
||||
* the bootmem bitmap so we then reserve it after freeing it :-)
|
||||
*/
|
||||
free_bootmem(memory_start, memory_end - memory_start);
|
||||
|
||||
reserve_bootmem(memory_start, bootmap_size);
|
||||
/*
|
||||
* get kmalloc into gear
|
||||
*/
|
||||
paging_init();
|
||||
|
||||
/* check the size of the l1 area */
|
||||
l1_length = _etext_l1 - _stext_l1;
|
||||
if (l1_length > L1_CODE_LENGTH)
|
||||
panic("L1 memory overflow\n");
|
||||
|
||||
l1_length = _ebss_l1 - _sdata_l1;
|
||||
if (l1_length > L1_DATA_A_LENGTH)
|
||||
panic("L1 memory overflow\n");
|
||||
|
||||
bf53x_cache_init();
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP)
|
||||
/* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
|
||||
bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
|
||||
bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
|
||||
SSYNC();
|
||||
# endif
|
||||
# if defined (CONFIG_BFIN561_EZKIT)
|
||||
bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12));
|
||||
SSYNC();
|
||||
# endif /* defined (CONFIG_BFIN561_EZKIT) */
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "Hardware Trace Enabled\n");
|
||||
bfin_write_TBUFCTL(0x03);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BF561)
|
||||
static struct cpu cpu[2];
|
||||
#else
|
||||
static struct cpu cpu[1];
|
||||
#endif
|
||||
static int __init topology_init(void)
|
||||
{
|
||||
#if defined (CONFIG_BF561)
|
||||
register_cpu(&cpu[0], 0);
|
||||
register_cpu(&cpu[1], 1);
|
||||
return 0;
|
||||
#else
|
||||
return register_cpu(cpu, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
subsys_initcall(topology_init);
|
||||
|
||||
#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
|
||||
u16 lock_kernel_check(u32 start, u32 end)
|
||||
{
|
||||
if ((start <= (u32) _stext && end >= (u32) _end)
|
||||
|| (start >= (u32) _stext && end <= (u32) _end))
|
||||
return IN_KERNEL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned short __init
|
||||
fill_cplbtab(struct cplb_tab *table,
|
||||
unsigned long start, unsigned long end,
|
||||
unsigned long block_size, unsigned long cplb_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (block_size) {
|
||||
case SIZE_4M:
|
||||
i = 3;
|
||||
break;
|
||||
case SIZE_1M:
|
||||
i = 2;
|
||||
break;
|
||||
case SIZE_4K:
|
||||
i = 1;
|
||||
break;
|
||||
case SIZE_1K:
|
||||
default:
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
|
||||
|
||||
while ((start < end) && (table->pos < table->size)) {
|
||||
|
||||
table->tab[table->pos++] = start;
|
||||
|
||||
if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
|
||||
table->tab[table->pos++] =
|
||||
cplb_data | CPLB_LOCK | CPLB_DIRTY;
|
||||
else
|
||||
table->tab[table->pos++] = cplb_data;
|
||||
|
||||
start += block_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned short __init
|
||||
close_cplbtab(struct cplb_tab *table)
|
||||
{
|
||||
|
||||
while (table->pos < table->size) {
|
||||
|
||||
table->tab[table->pos++] = 0;
|
||||
table->tab[table->pos++] = 0; /* !CPLB_VALID */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init generate_cpl_tables(void)
|
||||
{
|
||||
|
||||
u16 i, j, process;
|
||||
u32 a_start, a_end, as, ae, as_1m;
|
||||
|
||||
struct cplb_tab *t_i = NULL;
|
||||
struct cplb_tab *t_d = NULL;
|
||||
struct s_cplb cplb;
|
||||
|
||||
cplb.init_i.size = MAX_CPLBS;
|
||||
cplb.init_d.size = MAX_CPLBS;
|
||||
cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
|
||||
cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
|
||||
|
||||
cplb.init_i.pos = 0;
|
||||
cplb.init_d.pos = 0;
|
||||
cplb.switch_i.pos = 0;
|
||||
cplb.switch_d.pos = 0;
|
||||
|
||||
cplb.init_i.tab = icplb_table;
|
||||
cplb.init_d.tab = dcplb_table;
|
||||
cplb.switch_i.tab = ipdt_table;
|
||||
cplb.switch_d.tab = dpdt_table;
|
||||
|
||||
cplb_data[SDRAM_KERN].end = memory_end;
|
||||
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
|
||||
cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
|
||||
cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
|
||||
# if defined(CONFIG_ROMFS_FS)
|
||||
cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
|
||||
|
||||
/*
|
||||
* The ROMFS_FS size is often not multiple of 1MB.
|
||||
* This can cause multiple CPLB sets covering the same memory area.
|
||||
* This will then cause multiple CPLB hit exceptions.
|
||||
* Workaround: We ensure a contiguous memory area by extending the kernel
|
||||
* memory section over the mtd section.
|
||||
* For ROMFS_FS memory must be covered with ICPLBs anyways.
|
||||
* So there is no difference between kernel and mtd memory setup.
|
||||
*/
|
||||
|
||||
cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
|
||||
cplb_data[SDRAM_RAM_MTD].valid = 0;
|
||||
|
||||
# endif
|
||||
#else
|
||||
cplb_data[SDRAM_RAM_MTD].valid = 0;
|
||||
#endif
|
||||
|
||||
cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
|
||||
cplb_data[SDRAM_DMAZ].end = _ramend;
|
||||
|
||||
cplb_data[RES_MEM].start = _ramend;
|
||||
cplb_data[RES_MEM].end = physical_mem_end;
|
||||
|
||||
if (reserved_mem_dcache_on)
|
||||
cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
|
||||
else
|
||||
cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
|
||||
|
||||
if (reserved_mem_icache_on)
|
||||
cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
|
||||
else
|
||||
cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
|
||||
|
||||
for (i = ZERO_P; i <= L2_MEM; i++) {
|
||||
|
||||
if (cplb_data[i].valid) {
|
||||
|
||||
as_1m = cplb_data[i].start % SIZE_1M;
|
||||
|
||||
/* We need to make sure all sections are properly 1M aligned
|
||||
* However between Kernel Memory and the Kernel mtd section, depending on the
|
||||
* rootfs size, there can be overlapping memory areas.
|
||||
*/
|
||||
|
||||
if (as_1m && i!=L1I_MEM && i!=L1D_MEM) {
|
||||
#ifdef CONFIG_MTD_UCLINUX
|
||||
if (i == SDRAM_RAM_MTD) {
|
||||
if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
|
||||
cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
|
||||
else
|
||||
cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
|
||||
} else
|
||||
#endif
|
||||
printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
|
||||
cplb_data[i].name, cplb_data[i].start);
|
||||
}
|
||||
|
||||
as = cplb_data[i].start % SIZE_4M;
|
||||
ae = cplb_data[i].end % SIZE_4M;
|
||||
|
||||
if (as)
|
||||
a_start = cplb_data[i].start + (SIZE_4M - (as));
|
||||
else
|
||||
a_start = cplb_data[i].start;
|
||||
|
||||
a_end = cplb_data[i].end - ae;
|
||||
|
||||
for (j = INITIAL_T; j <= SWITCH_T; j++) {
|
||||
|
||||
switch (j) {
|
||||
case INITIAL_T:
|
||||
if (cplb_data[i].attr & INITIAL_T) {
|
||||
t_i = &cplb.init_i;
|
||||
t_d = &cplb.init_d;
|
||||
process = 1;
|
||||
} else
|
||||
process = 0;
|
||||
break;
|
||||
case SWITCH_T:
|
||||
if (cplb_data[i].attr & SWITCH_T) {
|
||||
t_i = &cplb.switch_i;
|
||||
t_d = &cplb.switch_d;
|
||||
process = 1;
|
||||
} else
|
||||
process = 0;
|
||||
break;
|
||||
default:
|
||||
process = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (process) {
|
||||
if (cplb_data[i].attr & I_CPLB) {
|
||||
|
||||
if (cplb_data[i].psize) {
|
||||
fill_cplbtab(t_i,
|
||||
cplb_data[i].start,
|
||||
cplb_data[i].end,
|
||||
cplb_data[i].psize,
|
||||
cplb_data[i].i_conf);
|
||||
} else {
|
||||
/*icplb_table */
|
||||
#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
|
||||
if (i == SDRAM_KERN) {
|
||||
fill_cplbtab(t_i,
|
||||
cplb_data[i].start,
|
||||
cplb_data[i].end,
|
||||
SIZE_4M,
|
||||
cplb_data[i].i_conf);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fill_cplbtab(t_i,
|
||||
cplb_data[i].start,
|
||||
a_start,
|
||||
SIZE_1M,
|
||||
cplb_data[i].i_conf);
|
||||
fill_cplbtab(t_i,
|
||||
a_start,
|
||||
a_end,
|
||||
SIZE_4M,
|
||||
cplb_data[i].i_conf);
|
||||
fill_cplbtab(t_i, a_end,
|
||||
cplb_data[i].end,
|
||||
SIZE_1M,
|
||||
cplb_data[i].i_conf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (cplb_data[i].attr & D_CPLB) {
|
||||
|
||||
if (cplb_data[i].psize) {
|
||||
fill_cplbtab(t_d,
|
||||
cplb_data[i].start,
|
||||
cplb_data[i].end,
|
||||
cplb_data[i].psize,
|
||||
cplb_data[i].d_conf);
|
||||
} else {
|
||||
/*dcplb_table*/
|
||||
fill_cplbtab(t_d,
|
||||
cplb_data[i].start,
|
||||
a_start, SIZE_1M,
|
||||
cplb_data[i].d_conf);
|
||||
fill_cplbtab(t_d, a_start,
|
||||
a_end, SIZE_4M,
|
||||
cplb_data[i].d_conf);
|
||||
fill_cplbtab(t_d, a_end,
|
||||
cplb_data[i].end,
|
||||
SIZE_1M,
|
||||
cplb_data[i].d_conf);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* close tables */
|
||||
|
||||
close_cplbtab(&cplb.init_i);
|
||||
close_cplbtab(&cplb.init_d);
|
||||
|
||||
cplb.init_i.tab[cplb.init_i.pos] = -1;
|
||||
cplb.init_d.tab[cplb.init_d.pos] = -1;
|
||||
cplb.switch_i.tab[cplb.switch_i.pos] = -1;
|
||||
cplb.switch_d.tab[cplb.switch_d.pos] = -1;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline u_long get_vco(void)
|
||||
{
|
||||
u_long msel;
|
||||
u_long vco;
|
||||
|
||||
msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
|
||||
if (0 == msel)
|
||||
msel = 64;
|
||||
|
||||
vco = CONFIG_CLKIN_HZ;
|
||||
vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */
|
||||
vco = msel * vco;
|
||||
return vco;
|
||||
}
|
||||
|
||||
/*Get the Core clock*/
|
||||
u_long get_cclk(void)
|
||||
{
|
||||
u_long csel, ssel;
|
||||
if (bfin_read_PLL_STAT() & 0x1)
|
||||
return CONFIG_CLKIN_HZ;
|
||||
|
||||
ssel = bfin_read_PLL_DIV();
|
||||
csel = ((ssel >> 4) & 0x03);
|
||||
ssel &= 0xf;
|
||||
if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */
|
||||
return get_vco() / ssel;
|
||||
return get_vco() >> csel;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(get_cclk);
|
||||
|
||||
/* Get the System clock */
|
||||
u_long get_sclk(void)
|
||||
{
|
||||
u_long ssel;
|
||||
|
||||
if (bfin_read_PLL_STAT() & 0x1)
|
||||
return CONFIG_CLKIN_HZ;
|
||||
|
||||
ssel = (bfin_read_PLL_DIV() & 0xf);
|
||||
if (0 == ssel) {
|
||||
printk(KERN_WARNING "Invalid System Clock\n");
|
||||
ssel = 1;
|
||||
}
|
||||
|
||||
return get_vco() / ssel;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(get_sclk);
|
||||
|
||||
/*
|
||||
* Get CPU information for use by the procfs.
|
||||
*/
|
||||
static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
{
|
||||
char *cpu, *mmu, *fpu, *name;
|
||||
uint32_t revid;
|
||||
|
||||
u_long cclk = 0, sclk = 0;
|
||||
u_int dcache_size = 0, dsup_banks = 0;
|
||||
|
||||
cpu = CPU;
|
||||
mmu = "none";
|
||||
fpu = "none";
|
||||
revid = bfin_revid();
|
||||
name = bfin_board_name;
|
||||
|
||||
cclk = get_cclk();
|
||||
sclk = get_sclk();
|
||||
|
||||
seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
|
||||
"MMU:\t\t%s\n"
|
||||
"FPU:\t\t%s\n"
|
||||
"Core Clock:\t%9lu Hz\n"
|
||||
"System Clock:\t%9lu Hz\n"
|
||||
"BogoMips:\t%lu.%02lu\n"
|
||||
"Calibration:\t%lu loops\n",
|
||||
cpu, revid, mmu, fpu,
|
||||
cclk,
|
||||
sclk,
|
||||
(loops_per_jiffy * HZ) / 500000,
|
||||
((loops_per_jiffy * HZ) / 5000) % 100,
|
||||
(loops_per_jiffy * HZ));
|
||||
seq_printf(m, "Board Name:\t%s\n", name);
|
||||
seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
|
||||
seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
|
||||
if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
|
||||
seq_printf(m, "I-CACHE:\tON\n");
|
||||
else
|
||||
seq_printf(m, "I-CACHE:\tOFF\n");
|
||||
if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
|
||||
seq_printf(m, "D-CACHE:\tON"
|
||||
#if defined CONFIG_BLKFIN_WB
|
||||
" (write-back)"
|
||||
#elif defined CONFIG_BLKFIN_WT
|
||||
" (write-through)"
|
||||
#endif
|
||||
"\n");
|
||||
else
|
||||
seq_printf(m, "D-CACHE:\tOFF\n");
|
||||
|
||||
|
||||
switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
|
||||
case ACACHE_BSRAM:
|
||||
seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
|
||||
dcache_size = 16;
|
||||
dsup_banks = 1;
|
||||
break;
|
||||
case ACACHE_BCACHE:
|
||||
seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
|
||||
dcache_size = 32;
|
||||
dsup_banks = 2;
|
||||
break;
|
||||
case ASRAM_BSRAM:
|
||||
seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
|
||||
dcache_size = 0;
|
||||
dsup_banks = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024);
|
||||
seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
|
||||
seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
|
||||
BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES);
|
||||
seq_printf(m,
|
||||
"D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
|
||||
dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS,
|
||||
BLKFIN_DLINES);
|
||||
#ifdef CONFIG_BLKFIN_CACHE_LOCK
|
||||
switch (read_iloc()) {
|
||||
case WAY0_L:
|
||||
seq_printf(m, "Way0 Locked-Down\n");
|
||||
break;
|
||||
case WAY1_L:
|
||||
seq_printf(m, "Way1 Locked-Down\n");
|
||||
break;
|
||||
case WAY01_L:
|
||||
seq_printf(m, "Way0,Way1 Locked-Down\n");
|
||||
break;
|
||||
case WAY2_L:
|
||||
seq_printf(m, "Way2 Locked-Down\n");
|
||||
break;
|
||||
case WAY02_L:
|
||||
seq_printf(m, "Way0,Way2 Locked-Down\n");
|
||||
break;
|
||||
case WAY12_L:
|
||||
seq_printf(m, "Way1,Way2 Locked-Down\n");
|
||||
break;
|
||||
case WAY012_L:
|
||||
seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
|
||||
break;
|
||||
case WAY3_L:
|
||||
seq_printf(m, "Way3 Locked-Down\n");
|
||||
break;
|
||||
case WAY03_L:
|
||||
seq_printf(m, "Way0,Way3 Locked-Down\n");
|
||||
break;
|
||||
case WAY13_L:
|
||||
seq_printf(m, "Way1,Way3 Locked-Down\n");
|
||||
break;
|
||||
case WAY013_L:
|
||||
seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
|
||||
break;
|
||||
case WAY32_L:
|
||||
seq_printf(m, "Way3,Way2 Locked-Down\n");
|
||||
break;
|
||||
case WAY320_L:
|
||||
seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
|
||||
break;
|
||||
case WAY321_L:
|
||||
seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
|
||||
break;
|
||||
case WAYALL_L:
|
||||
seq_printf(m, "All Ways are locked\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(m, "No Ways are locked\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *c_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
|
||||
}
|
||||
|
||||
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
return c_start(m, pos);
|
||||
}
|
||||
|
||||
static void c_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
}
|
||||
|
||||
struct seq_operations cpuinfo_op = {
|
||||
.start = c_start,
|
||||
.next = c_next,
|
||||
.stop = c_stop,
|
||||
.show = show_cpuinfo,
|
||||
};
|
||||
|
||||
void cmdline_init(unsigned long r0)
|
||||
{
|
||||
if (r0)
|
||||
strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE);
|
||||
}
|
356
arch/blackfin/kernel/signal.c
Normal file
356
arch/blackfin/kernel/signal.c
Normal file
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/signal.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/signal.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/personality.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/ucontext.h>
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
struct fdpic_func_descriptor {
|
||||
unsigned long text;
|
||||
unsigned long GOT;
|
||||
};
|
||||
|
||||
struct rt_sigframe {
|
||||
int sig;
|
||||
struct siginfo *pinfo;
|
||||
void *puc;
|
||||
char retcode[8];
|
||||
struct siginfo info;
|
||||
struct ucontext uc;
|
||||
};
|
||||
|
||||
asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
|
||||
{
|
||||
return do_sigaltstack(uss, uoss, rdusp());
|
||||
}
|
||||
|
||||
static inline int
|
||||
rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
|
||||
{
|
||||
unsigned long usp = 0;
|
||||
int err = 0;
|
||||
|
||||
#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
|
||||
|
||||
/* restore passed registers */
|
||||
RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3);
|
||||
RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7);
|
||||
RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3);
|
||||
RESTORE(p4); RESTORE(p5);
|
||||
err |= __get_user(usp, &sc->sc_usp);
|
||||
wrusp(usp);
|
||||
RESTORE(a0w); RESTORE(a1w);
|
||||
RESTORE(a0x); RESTORE(a1x);
|
||||
RESTORE(astat);
|
||||
RESTORE(rets);
|
||||
RESTORE(pc);
|
||||
RESTORE(retx);
|
||||
RESTORE(fp);
|
||||
RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3);
|
||||
RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3);
|
||||
RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3);
|
||||
RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3);
|
||||
RESTORE(lc0); RESTORE(lc1);
|
||||
RESTORE(lt0); RESTORE(lt1);
|
||||
RESTORE(lb0); RESTORE(lb1);
|
||||
RESTORE(seqstat);
|
||||
|
||||
regs->orig_p0 = -1; /* disable syscall checks */
|
||||
|
||||
*pr0 = regs->r0;
|
||||
return err;
|
||||
}
|
||||
|
||||
asmlinkage int do_rt_sigreturn(unsigned long __unused)
|
||||
{
|
||||
struct pt_regs *regs = (struct pt_regs *)__unused;
|
||||
unsigned long usp = rdusp();
|
||||
struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
|
||||
sigset_t set;
|
||||
int r0;
|
||||
|
||||
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(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
|
||||
goto badframe;
|
||||
|
||||
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
|
||||
goto badframe;
|
||||
|
||||
return r0;
|
||||
|
||||
badframe:
|
||||
force_sig(SIGSEGV, current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x)
|
||||
|
||||
SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3);
|
||||
SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7);
|
||||
SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3);
|
||||
SETUP(p4); SETUP(p5);
|
||||
err |= __put_user(rdusp(), &sc->sc_usp);
|
||||
SETUP(a0w); SETUP(a1w);
|
||||
SETUP(a0x); SETUP(a1x);
|
||||
SETUP(astat);
|
||||
SETUP(rets);
|
||||
SETUP(pc);
|
||||
SETUP(retx);
|
||||
SETUP(fp);
|
||||
SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3);
|
||||
SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3);
|
||||
SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3);
|
||||
SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3);
|
||||
SETUP(lc0); SETUP(lc1);
|
||||
SETUP(lt0); SETUP(lt1);
|
||||
SETUP(lb0); SETUP(lb1);
|
||||
SETUP(seqstat);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void push_cache(unsigned long vaddr, unsigned int len)
|
||||
{
|
||||
flush_icache_range(vaddr, vaddr + len);
|
||||
}
|
||||
|
||||
static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
size_t frame_size)
|
||||
{
|
||||
unsigned long usp;
|
||||
|
||||
/* Default to using normal stack. */
|
||||
usp = rdusp();
|
||||
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if (ka->sa.sa_flags & SA_ONSTACK) {
|
||||
if (!on_sig_stack(usp))
|
||||
usp = current->sas_ss_sp + current->sas_ss_size;
|
||||
}
|
||||
return (void *)((usp - frame_size) & -8UL);
|
||||
}
|
||||
|
||||
static int
|
||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
|
||||
sigset_t * set, struct pt_regs *regs)
|
||||
{
|
||||
struct rt_sigframe *frame;
|
||||
int err = 0;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
|
||||
err |= __put_user((current_thread_info()->exec_domain
|
||||
&& current_thread_info()->exec_domain->signal_invmap
|
||||
&& sig < 32
|
||||
? current_thread_info()->exec_domain->
|
||||
signal_invmap[sig] : sig), &frame->sig);
|
||||
|
||||
err |= __put_user(&frame->info, &frame->pinfo);
|
||||
err |= __put_user(&frame->uc, &frame->puc);
|
||||
err |= copy_siginfo_to_user(&frame->info, info);
|
||||
|
||||
/* Create the ucontext. */
|
||||
err |= __put_user(0, &frame->uc.uc_flags);
|
||||
err |= __put_user(0, &frame->uc.uc_link);
|
||||
err |=
|
||||
__put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||
err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
|
||||
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
|
||||
err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
/* Set up to return from userspace. */
|
||||
err |= __put_user(0x28, &(frame->retcode[0]));
|
||||
err |= __put_user(0xe1, &(frame->retcode[1]));
|
||||
err |= __put_user(0xad, &(frame->retcode[2]));
|
||||
err |= __put_user(0x00, &(frame->retcode[3]));
|
||||
err |= __put_user(0xa0, &(frame->retcode[4]));
|
||||
err |= __put_user(0x00, &(frame->retcode[5]));
|
||||
|
||||
if (err)
|
||||
goto give_sigsegv;
|
||||
|
||||
push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
|
||||
|
||||
/* Set up registers for signal handler */
|
||||
wrusp((unsigned long)frame);
|
||||
if (get_personality & FDPIC_FUNCPTRS) {
|
||||
struct fdpic_func_descriptor __user *funcptr =
|
||||
(struct fdpic_func_descriptor *) ka->sa.sa_handler;
|
||||
__get_user(regs->pc, &funcptr->text);
|
||||
__get_user(regs->p3, &funcptr->GOT);
|
||||
} else
|
||||
regs->pc = (unsigned long)ka->sa.sa_handler;
|
||||
regs->rets = (unsigned long)(frame->retcode);
|
||||
|
||||
regs->r0 = frame->sig;
|
||||
regs->r1 = (unsigned long)(&frame->info);
|
||||
regs->r2 = (unsigned long)(&frame->uc);
|
||||
|
||||
return 0;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == SIGSEGV)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
force_sig(SIGSEGV, current);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static inline void
|
||||
handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
|
||||
{
|
||||
switch (regs->r0) {
|
||||
case -ERESTARTNOHAND:
|
||||
if (!has_handler)
|
||||
goto do_restart;
|
||||
regs->r0 = -EINTR;
|
||||
break;
|
||||
|
||||
case -ERESTARTSYS:
|
||||
if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
|
||||
regs->r0 = -EINTR;
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case -ERESTARTNOINTR:
|
||||
do_restart:
|
||||
regs->p0 = regs->orig_p0;
|
||||
regs->r0 = regs->orig_r0;
|
||||
regs->pc -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
static int
|
||||
handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
|
||||
sigset_t *oldset, struct pt_regs *regs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* are we from a system call? to see pt_regs->orig_p0 */
|
||||
if (regs->orig_p0 >= 0)
|
||||
/* If so, check system call restarting.. */
|
||||
handle_restart(regs, ka, 1);
|
||||
|
||||
/* set up the stack frame */
|
||||
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
|
||||
if (ret == 0) {
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sigorsets(¤t->blocked, ¤t->blocked,
|
||||
&ka->sa.sa_mask);
|
||||
if (!(ka->sa.sa_flags & SA_NODEFER))
|
||||
sigaddset(¤t->blocked, sig);
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
||||
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
||||
* mistake.
|
||||
*
|
||||
* Note that we go through the signals twice: once to check the signals
|
||||
* that the kernel can handle, and then we build all the user-level signal
|
||||
* handling stack-frames in one go after that.
|
||||
*/
|
||||
asmlinkage void do_signal(struct pt_regs *regs)
|
||||
{
|
||||
siginfo_t info;
|
||||
int signr;
|
||||
struct k_sigaction ka;
|
||||
sigset_t *oldset;
|
||||
|
||||
current->thread.esp0 = (unsigned long)regs;
|
||||
|
||||
if (try_to_freeze())
|
||||
goto no_signal;
|
||||
|
||||
if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
||||
oldset = ¤t->saved_sigmask;
|
||||
else
|
||||
oldset = ¤t->blocked;
|
||||
|
||||
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
||||
if (signr > 0) {
|
||||
/* Whee! Actually deliver the signal. */
|
||||
if (handle_signal(signr, &info, &ka, oldset, regs) == 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);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
no_signal:
|
||||
/* Did we come from a system call? */
|
||||
if (regs->orig_p0 >= 0)
|
||||
/* Restart the system call - no handlers present */
|
||||
handle_restart(regs, NULL, 0);
|
||||
|
||||
/* 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, ¤t->saved_sigmask, NULL);
|
||||
}
|
||||
}
|
115
arch/blackfin/kernel/sys_bfin.c
Normal file
115
arch/blackfin/kernel/sys_bfin.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/sys_bfin.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains various random system calls that
|
||||
* have a non-standard calling sequence on the Linux/bfin
|
||||
* platform.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sem.h>
|
||||
#include <linux/msg.h>
|
||||
#include <linux/shm.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/ipc.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
/*
|
||||
* sys_pipe() is the normal C calling standard for creating
|
||||
* a pipe. It's not the way unix traditionally does this, though.
|
||||
*/
|
||||
asmlinkage int sys_pipe(unsigned long *fildes)
|
||||
{
|
||||
int fd[2];
|
||||
int error;
|
||||
|
||||
error = do_pipe(fd);
|
||||
if (!error) {
|
||||
if (copy_to_user(fildes, fd, 2 * sizeof(int)))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/* common code for old and new mmaps */
|
||||
static inline long
|
||||
do_mmap2(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long pgoff)
|
||||
{
|
||||
int error = -EBADF;
|
||||
struct file *file = NULL;
|
||||
|
||||
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
|
||||
if (!(flags & MAP_ANONYMOUS)) {
|
||||
file = fget(fd);
|
||||
if (!file)
|
||||
goto out;
|
||||
}
|
||||
|
||||
down_write(¤t->mm->mmap_sem);
|
||||
error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
|
||||
up_write(¤t->mm->mmap_sem);
|
||||
|
||||
if (file)
|
||||
fput(file);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, unsigned long pgoff)
|
||||
{
|
||||
return do_mmap2(addr, len, prot, flags, fd, pgoff);
|
||||
}
|
||||
|
||||
asmlinkage int sys_getpagesize(void)
|
||||
{
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
|
||||
{
|
||||
return sram_alloc_with_lsl(size, flags);
|
||||
}
|
||||
|
||||
asmlinkage int sys_sram_free(const void *addr)
|
||||
{
|
||||
return sram_free_with_lsl(addr);
|
||||
}
|
||||
|
||||
asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
|
||||
{
|
||||
return safe_dma_memcpy(dest, src, len);
|
||||
}
|
326
arch/blackfin/kernel/time.c
Normal file
326
arch/blackfin/kernel/time.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/time.c
|
||||
* Based on: none - original work
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This file contains the bfin-specific time handling details.
|
||||
* Most of the stuff is located in the machine specific files.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
/* This is an NTP setting */
|
||||
#define TICK_SIZE (tick_nsec / 1000)
|
||||
|
||||
static void time_sched_init(irqreturn_t(*timer_routine)
|
||||
(int, void *));
|
||||
static unsigned long gettimeoffset(void);
|
||||
static inline void do_leds(void);
|
||||
|
||||
#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
|
||||
void __init init_leds(void)
|
||||
{
|
||||
unsigned int tmp = 0;
|
||||
|
||||
#if defined(CONFIG_BFIN_ALIVE_LED)
|
||||
/* config pins as output. */
|
||||
tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
|
||||
SSYNC();
|
||||
bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
|
||||
SSYNC();
|
||||
|
||||
/* First set led be off */
|
||||
tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
|
||||
SSYNC();
|
||||
bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); /* light off */
|
||||
SSYNC();
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_IDLE_LED)
|
||||
/* config pins as output. */
|
||||
tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
|
||||
SSYNC();
|
||||
bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
|
||||
SSYNC();
|
||||
|
||||
/* First set led be off */
|
||||
tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
|
||||
SSYNC();
|
||||
bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); /* light off */
|
||||
SSYNC();
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void __init init_leds(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_ALIVE_LED)
|
||||
static inline void do_leds(void)
|
||||
{
|
||||
static unsigned int count = 50;
|
||||
static int flag = 0;
|
||||
unsigned short tmp = 0;
|
||||
|
||||
if (--count == 0) {
|
||||
count = 50;
|
||||
flag = ~flag;
|
||||
}
|
||||
tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
|
||||
SSYNC();
|
||||
|
||||
if (flag)
|
||||
tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN; /* light on */
|
||||
else
|
||||
tmp |= CONFIG_BFIN_ALIVE_LED_PIN; /* light off */
|
||||
|
||||
bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
|
||||
SSYNC();
|
||||
|
||||
}
|
||||
#else
|
||||
static inline void do_leds(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct irqaction bfin_timer_irq = {
|
||||
.name = "BFIN Timer Tick",
|
||||
.flags = IRQF_DISABLED
|
||||
};
|
||||
|
||||
/*
|
||||
* The way that the Blackfin core timer works is:
|
||||
* - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
|
||||
* - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
|
||||
*
|
||||
* If you take the fastest clock (1ns, or 1GHz to make the math work easier)
|
||||
* 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
|
||||
* (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
|
||||
* to use TSCALE, and program it to zero (which is pass CCLK through).
|
||||
* If you feel like using it, try to keep HZ * TIMESCALE to some
|
||||
* value that divides easy (like power of 2).
|
||||
*/
|
||||
|
||||
#define TIME_SCALE 1
|
||||
|
||||
static void
|
||||
time_sched_init(irqreturn_t(*timer_routine) (int, void *))
|
||||
{
|
||||
u32 tcount;
|
||||
|
||||
/* power up the timer, but don't enable it just yet */
|
||||
bfin_write_TCNTL(1);
|
||||
CSYNC();
|
||||
|
||||
/*
|
||||
* the TSCALE prescaler counter.
|
||||
*/
|
||||
bfin_write_TSCALE((TIME_SCALE - 1));
|
||||
|
||||
tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
|
||||
bfin_write_TPERIOD(tcount);
|
||||
bfin_write_TCOUNT(tcount);
|
||||
|
||||
/* now enable the timer */
|
||||
CSYNC();
|
||||
|
||||
bfin_write_TCNTL(7);
|
||||
|
||||
bfin_timer_irq.handler = (irq_handler_t)timer_routine;
|
||||
/* call setup_irq instead of request_irq because request_irq calls
|
||||
* kmalloc which has not been initialized yet
|
||||
*/
|
||||
setup_irq(IRQ_CORETMR, &bfin_timer_irq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Should return useconds since last timer tick
|
||||
*/
|
||||
static unsigned long gettimeoffset(void)
|
||||
{
|
||||
unsigned long offset;
|
||||
unsigned long clocks_per_jiffy;
|
||||
|
||||
clocks_per_jiffy = bfin_read_TPERIOD();
|
||||
offset =
|
||||
(clocks_per_jiffy -
|
||||
bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
|
||||
USEC_PER_SEC);
|
||||
|
||||
/* Check if we just wrapped the counters and maybe missed a tick */
|
||||
if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
|
||||
&& (offset < (100000 / HZ / 2)))
|
||||
offset += (USEC_PER_SEC / HZ);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline int set_rtc_mmss(unsigned long nowtime)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* timer_interrupt() needs to keep up the real-time clock,
|
||||
* as well as call the "do_timer()" routine every clocktick
|
||||
*/
|
||||
#ifdef CONFIG_CORE_TIMER_IRQ_L1
|
||||
irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
irqreturn_t timer_interrupt(int irq, void *dummy)
|
||||
{
|
||||
/* last time the cmos clock got updated */
|
||||
static long last_rtc_update = 0;
|
||||
|
||||
write_seqlock(&xtime_lock);
|
||||
|
||||
do_timer(1);
|
||||
do_leds();
|
||||
|
||||
#ifndef CONFIG_SMP
|
||||
update_process_times(user_mode(get_irq_regs()));
|
||||
#endif
|
||||
profile_tick(CPU_PROFILING);
|
||||
|
||||
/*
|
||||
* If we have an externally synchronized Linux clock, then update
|
||||
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
|
||||
* called as close as possible to 500 ms before the new second starts.
|
||||
*/
|
||||
|
||||
if (ntp_synced() &&
|
||||
xtime.tv_sec > last_rtc_update + 660 &&
|
||||
(xtime.tv_nsec / NSEC_PER_USEC) >=
|
||||
500000 - ((unsigned)TICK_SIZE) / 2
|
||||
&& (xtime.tv_nsec / NSEC_PER_USEC) <=
|
||||
500000 + ((unsigned)TICK_SIZE) / 2) {
|
||||
if (set_rtc_mmss(xtime.tv_sec) == 0)
|
||||
last_rtc_update = xtime.tv_sec;
|
||||
else
|
||||
/* Do it again in 60s. */
|
||||
last_rtc_update = xtime.tv_sec - 600;
|
||||
}
|
||||
write_sequnlock(&xtime_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
|
||||
|
||||
#ifdef CONFIG_RTC_DRV_BFIN
|
||||
/* [#2663] hack to filter junk RTC values that would cause
|
||||
* userspace to have to deal with time values greater than
|
||||
* 2^31 seconds (which uClibc cannot cope with yet)
|
||||
*/
|
||||
if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
|
||||
printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
|
||||
bfin_write_RTC_STAT(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize xtime. From now on, xtime is updated with timer interrupts */
|
||||
xtime.tv_sec = secs_since_1970;
|
||||
xtime.tv_nsec = 0;
|
||||
|
||||
wall_to_monotonic.tv_sec = -xtime.tv_sec;
|
||||
|
||||
time_sched_init(timer_interrupt);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_GENERIC_TIME
|
||||
void do_gettimeofday(struct timeval *tv)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long seq;
|
||||
unsigned long usec, sec;
|
||||
|
||||
do {
|
||||
seq = read_seqbegin_irqsave(&xtime_lock, flags);
|
||||
usec = gettimeoffset();
|
||||
sec = xtime.tv_sec;
|
||||
usec += (xtime.tv_nsec / NSEC_PER_USEC);
|
||||
}
|
||||
while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
|
||||
|
||||
while (usec >= USEC_PER_SEC) {
|
||||
usec -= USEC_PER_SEC;
|
||||
sec++;
|
||||
}
|
||||
|
||||
tv->tv_sec = sec;
|
||||
tv->tv_usec = usec;
|
||||
}
|
||||
EXPORT_SYMBOL(do_gettimeofday);
|
||||
|
||||
int do_settimeofday(struct timespec *tv)
|
||||
{
|
||||
time_t wtm_sec, sec = tv->tv_sec;
|
||||
long wtm_nsec, nsec = tv->tv_nsec;
|
||||
|
||||
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
|
||||
return -EINVAL;
|
||||
|
||||
write_seqlock_irq(&xtime_lock);
|
||||
/*
|
||||
* This is revolting. We need to set the xtime.tv_usec
|
||||
* correctly. However, the value in this location is
|
||||
* is value at the last tick.
|
||||
* Discover what correction gettimeofday
|
||||
* would have done, and then undo it!
|
||||
*/
|
||||
nsec -= (gettimeoffset() * NSEC_PER_USEC);
|
||||
|
||||
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
|
||||
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
|
||||
|
||||
set_normalized_timespec(&xtime, sec, nsec);
|
||||
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
|
||||
|
||||
ntp_clear();
|
||||
|
||||
write_sequnlock_irq(&xtime_lock);
|
||||
clock_was_set();
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(do_settimeofday);
|
||||
#endif /* !CONFIG_GENERIC_TIME */
|
||||
|
||||
/*
|
||||
* Scheduler clock - returns current time in nanosec units.
|
||||
*/
|
||||
unsigned long long sched_clock(void)
|
||||
{
|
||||
return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
|
||||
}
|
649
arch/blackfin/kernel/traps.c
Normal file
649
arch/blackfin/kernel/traps.c
Normal file
|
@ -0,0 +1,649 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/traps.c
|
||||
* Based on:
|
||||
* Author: Hamish Macdonald
|
||||
*
|
||||
* Created:
|
||||
* Description: uses S/W interrupt 15 for the system calls
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/irq_handler.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
# include <linux/debugger.h>
|
||||
# include <linux/kgdb.h>
|
||||
#endif
|
||||
|
||||
/* Initiate the event table handler */
|
||||
void __init trap_init(void)
|
||||
{
|
||||
CSYNC();
|
||||
bfin_write_EVT3(trap);
|
||||
CSYNC();
|
||||
}
|
||||
|
||||
asmlinkage void trap_c(struct pt_regs *fp);
|
||||
|
||||
int kstack_depth_to_print = 48;
|
||||
|
||||
static int printk_address(unsigned long address)
|
||||
{
|
||||
struct vm_list_struct *vml;
|
||||
struct task_struct *p;
|
||||
struct mm_struct *mm;
|
||||
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
unsigned long offset = 0, symsize;
|
||||
const char *symname;
|
||||
char *modname;
|
||||
char *delim = ":";
|
||||
char namebuf[128];
|
||||
|
||||
/* look up the address and see if we are in kernel space */
|
||||
symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
|
||||
|
||||
if (symname) {
|
||||
/* yeah! kernel space! */
|
||||
if (!modname)
|
||||
modname = delim = "";
|
||||
return printk("<0x%p> { %s%s%s%s + 0x%lx }",
|
||||
(void*)address, delim, modname, delim, symname,
|
||||
(unsigned long)offset);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* looks like we're off in user-land, so let's walk all the
|
||||
* mappings of all our processes and see if we can't be a whee
|
||||
* bit more specific
|
||||
*/
|
||||
write_lock_irq(&tasklist_lock);
|
||||
for_each_process(p) {
|
||||
mm = get_task_mm(p);
|
||||
if (!mm)
|
||||
continue;
|
||||
|
||||
vml = mm->context.vmlist;
|
||||
while (vml) {
|
||||
struct vm_area_struct *vma = vml->vma;
|
||||
|
||||
if (address >= vma->vm_start && address < vma->vm_end) {
|
||||
char *name = p->comm;
|
||||
struct file *file = vma->vm_file;
|
||||
if (file) {
|
||||
char _tmpbuf[256];
|
||||
name = d_path(file->f_dentry,
|
||||
file->f_vfsmnt,
|
||||
_tmpbuf,
|
||||
sizeof(_tmpbuf));
|
||||
}
|
||||
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
return printk("<0x%p> [ %s + 0x%lx ]",
|
||||
(void*)address, name,
|
||||
(unsigned long)
|
||||
((address - vma->vm_start) +
|
||||
(vma->vm_pgoff << PAGE_SHIFT)));
|
||||
}
|
||||
|
||||
vml = vml->next;
|
||||
}
|
||||
}
|
||||
write_unlock_irq(&tasklist_lock);
|
||||
|
||||
/* we were unable to find this address anywhere */
|
||||
return printk("[<0x%p>]", (void*)address);
|
||||
}
|
||||
|
||||
#define trace_buffer_save(x) \
|
||||
do { \
|
||||
(x) = bfin_read_TBUFCTL(); \
|
||||
bfin_write_TBUFCTL((x) & ~TBUFEN); \
|
||||
} while (0)
|
||||
#define trace_buffer_restore(x) \
|
||||
do { \
|
||||
bfin_write_TBUFCTL((x)); \
|
||||
} while (0)
|
||||
|
||||
asmlinkage void trap_c(struct pt_regs *fp)
|
||||
{
|
||||
int j, sig = 0;
|
||||
siginfo_t info;
|
||||
unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0)
|
||||
# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0)
|
||||
#else
|
||||
# define CHK_DEBUGGER_TRAP() do { } while (0)
|
||||
# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
|
||||
#endif
|
||||
|
||||
trace_buffer_save(j);
|
||||
|
||||
/* trap_c() will be called for exceptions. During exceptions
|
||||
* processing, the pc value should be set with retx value.
|
||||
* With this change we can cleanup some code in signal.c- TODO
|
||||
*/
|
||||
fp->orig_pc = fp->retx;
|
||||
/* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
|
||||
trapnr, fp->ipend, fp->pc, fp->retx); */
|
||||
|
||||
/* send the appropriate signal to the user program */
|
||||
switch (trapnr) {
|
||||
|
||||
/* This table works in conjuction with the one in ./mach-common/entry.S
|
||||
* Some exceptions are handled there (in assembly, in exception space)
|
||||
* Some are handled here, (in C, in interrupt space)
|
||||
* Some, like CPLB, are handled in both, where the normal path is
|
||||
* handled in assembly/exception space, and the error path is handled
|
||||
* here
|
||||
*/
|
||||
|
||||
/* 0x00 - Linux Syscall, getting here is an error */
|
||||
/* 0x01 - userspace gdb breakpoint, handled here */
|
||||
case VEC_EXCPT01:
|
||||
info.si_code = TRAP_ILLTRAP;
|
||||
sig = SIGTRAP;
|
||||
CHK_DEBUGGER_TRAP_MAYBE();
|
||||
/* Check if this is a breakpoint in kernel space */
|
||||
if (fp->ipend & 0xffc0)
|
||||
return;
|
||||
else
|
||||
break;
|
||||
#ifdef CONFIG_KGDB
|
||||
case VEC_EXCPT02 : /* gdb connection */
|
||||
info.si_code = TRAP_ILLTRAP;
|
||||
sig = SIGTRAP;
|
||||
CHK_DEBUGGER_TRAP();
|
||||
return;
|
||||
#else
|
||||
/* 0x02 - User Defined, Caught by default */
|
||||
#endif
|
||||
/* 0x03 - Atomic test and set */
|
||||
case VEC_EXCPT03:
|
||||
info.si_code = SEGV_STACKFLOW;
|
||||
sig = SIGSEGV;
|
||||
printk(KERN_EMERG EXC_0x03);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x04 - spinlock - handled by _ex_spinlock,
|
||||
getting here is an error */
|
||||
/* 0x05 - User Defined, Caught by default */
|
||||
/* 0x06 - User Defined, Caught by default */
|
||||
/* 0x07 - User Defined, Caught by default */
|
||||
/* 0x08 - User Defined, Caught by default */
|
||||
/* 0x09 - User Defined, Caught by default */
|
||||
/* 0x0A - User Defined, Caught by default */
|
||||
/* 0x0B - User Defined, Caught by default */
|
||||
/* 0x0C - User Defined, Caught by default */
|
||||
/* 0x0D - User Defined, Caught by default */
|
||||
/* 0x0E - User Defined, Caught by default */
|
||||
/* 0x0F - User Defined, Caught by default */
|
||||
/* 0x10 HW Single step, handled here */
|
||||
case VEC_STEP:
|
||||
info.si_code = TRAP_STEP;
|
||||
sig = SIGTRAP;
|
||||
CHK_DEBUGGER_TRAP_MAYBE();
|
||||
/* Check if this is a single step in kernel space */
|
||||
if (fp->ipend & 0xffc0)
|
||||
return;
|
||||
else
|
||||
break;
|
||||
/* 0x11 - Trace Buffer Full, handled here */
|
||||
case VEC_OVFLOW:
|
||||
info.si_code = TRAP_TRACEFLOW;
|
||||
sig = SIGTRAP;
|
||||
printk(KERN_EMERG EXC_0x11);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x12 - Reserved, Caught by default */
|
||||
/* 0x13 - Reserved, Caught by default */
|
||||
/* 0x14 - Reserved, Caught by default */
|
||||
/* 0x15 - Reserved, Caught by default */
|
||||
/* 0x16 - Reserved, Caught by default */
|
||||
/* 0x17 - Reserved, Caught by default */
|
||||
/* 0x18 - Reserved, Caught by default */
|
||||
/* 0x19 - Reserved, Caught by default */
|
||||
/* 0x1A - Reserved, Caught by default */
|
||||
/* 0x1B - Reserved, Caught by default */
|
||||
/* 0x1C - Reserved, Caught by default */
|
||||
/* 0x1D - Reserved, Caught by default */
|
||||
/* 0x1E - Reserved, Caught by default */
|
||||
/* 0x1F - Reserved, Caught by default */
|
||||
/* 0x20 - Reserved, Caught by default */
|
||||
/* 0x21 - Undefined Instruction, handled here */
|
||||
case VEC_UNDEF_I:
|
||||
info.si_code = ILL_ILLOPC;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x21);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x22 - Illegal Instruction Combination, handled here */
|
||||
case VEC_ILGAL_I:
|
||||
info.si_code = ILL_ILLPARAOP;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x22);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x23 - Data CPLB Protection Violation,
|
||||
normal case is handled in _cplb_hdr */
|
||||
case VEC_CPLB_VL:
|
||||
info.si_code = ILL_CPLB_VI;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x23);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x24 - Data access misaligned, handled here */
|
||||
case VEC_MISALI_D:
|
||||
info.si_code = BUS_ADRALN;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG EXC_0x24);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x25 - Unrecoverable Event, handled here */
|
||||
case VEC_UNCOV:
|
||||
info.si_code = ILL_ILLEXCPT;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x25);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
|
||||
error case is handled here */
|
||||
case VEC_CPLB_M:
|
||||
info.si_code = BUS_ADRALN;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG EXC_0x26);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
|
||||
case VEC_CPLB_MHIT:
|
||||
info.si_code = ILL_CPLB_MULHIT;
|
||||
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
|
||||
sig = SIGSEGV;
|
||||
printk(KERN_EMERG "\n\nNULL pointer access (probably)\n");
|
||||
#else
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x27);
|
||||
#endif
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x28 - Emulation Watchpoint, handled here */
|
||||
case VEC_WATCH:
|
||||
info.si_code = TRAP_WATCHPT;
|
||||
sig = SIGTRAP;
|
||||
pr_debug(EXC_0x28);
|
||||
CHK_DEBUGGER_TRAP_MAYBE();
|
||||
/* Check if this is a watchpoint in kernel space */
|
||||
if (fp->ipend & 0xffc0)
|
||||
return;
|
||||
else
|
||||
break;
|
||||
#ifdef CONFIG_BF535
|
||||
/* 0x29 - Instruction fetch access error (535 only) */
|
||||
case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
|
||||
info.si_code = BUS_OPFETCH;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n");
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
#else
|
||||
/* 0x29 - Reserved, Caught by default */
|
||||
#endif
|
||||
/* 0x2A - Instruction fetch misaligned, handled here */
|
||||
case VEC_MISALI_I:
|
||||
info.si_code = BUS_ADRALN;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG EXC_0x2A);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x2B - Instruction CPLB protection Violation,
|
||||
handled in _cplb_hdr */
|
||||
case VEC_CPLB_I_VL:
|
||||
info.si_code = ILL_CPLB_VI;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x2B);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
|
||||
case VEC_CPLB_I_M:
|
||||
info.si_code = ILL_CPLB_MISS;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG EXC_0x2C);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x2D - Instruction CPLB Multiple Hits, handled here */
|
||||
case VEC_CPLB_I_MHIT:
|
||||
info.si_code = ILL_CPLB_MULHIT;
|
||||
#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
|
||||
sig = SIGSEGV;
|
||||
printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n");
|
||||
#else
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x2D);
|
||||
#endif
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x2E - Illegal use of Supervisor Resource, handled here */
|
||||
case VEC_ILL_RES:
|
||||
info.si_code = ILL_PRVOPC;
|
||||
sig = SIGILL;
|
||||
printk(KERN_EMERG EXC_0x2E);
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
/* 0x2F - Reserved, Caught by default */
|
||||
/* 0x30 - Reserved, Caught by default */
|
||||
/* 0x31 - Reserved, Caught by default */
|
||||
/* 0x32 - Reserved, Caught by default */
|
||||
/* 0x33 - Reserved, Caught by default */
|
||||
/* 0x34 - Reserved, Caught by default */
|
||||
/* 0x35 - Reserved, Caught by default */
|
||||
/* 0x36 - Reserved, Caught by default */
|
||||
/* 0x37 - Reserved, Caught by default */
|
||||
/* 0x38 - Reserved, Caught by default */
|
||||
/* 0x39 - Reserved, Caught by default */
|
||||
/* 0x3A - Reserved, Caught by default */
|
||||
/* 0x3B - Reserved, Caught by default */
|
||||
/* 0x3C - Reserved, Caught by default */
|
||||
/* 0x3D - Reserved, Caught by default */
|
||||
/* 0x3E - Reserved, Caught by default */
|
||||
/* 0x3F - Reserved, Caught by default */
|
||||
default:
|
||||
info.si_code = TRAP_ILLTRAP;
|
||||
sig = SIGTRAP;
|
||||
printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
|
||||
(fp->seqstat & SEQSTAT_EXCAUSE));
|
||||
CHK_DEBUGGER_TRAP();
|
||||
break;
|
||||
}
|
||||
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void *)fp->pc;
|
||||
force_sig_info(sig, &info, current);
|
||||
if (sig != 0 && sig != SIGTRAP) {
|
||||
unsigned long stack;
|
||||
dump_bfin_regs(fp, (void *)fp->retx);
|
||||
dump_bfin_trace_buffer();
|
||||
show_stack(current, &stack);
|
||||
if (current->mm == NULL)
|
||||
panic("Kernel exception");
|
||||
}
|
||||
|
||||
/* if the address that we are about to return to is not valid, set it
|
||||
* to a valid address, if we have a current application or panic
|
||||
*/
|
||||
if (!(fp->pc <= physical_mem_end
|
||||
#if L1_CODE_LENGTH != 0
|
||||
|| (fp->pc >= L1_CODE_START &&
|
||||
fp->pc <= (L1_CODE_START + L1_CODE_LENGTH))
|
||||
#endif
|
||||
)) {
|
||||
if (current->mm) {
|
||||
fp->pc = current->mm->start_code;
|
||||
} else {
|
||||
printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n");
|
||||
panic("Help - I've fallen and can't get up\n");
|
||||
}
|
||||
}
|
||||
|
||||
trace_buffer_restore(j);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Typical exception handling routines */
|
||||
|
||||
void dump_bfin_trace_buffer(void)
|
||||
{
|
||||
int tflags;
|
||||
trace_buffer_save(tflags);
|
||||
|
||||
if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
|
||||
int i;
|
||||
printk(KERN_EMERG "Hardware Trace:\n");
|
||||
for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
|
||||
printk(KERN_EMERG "%2i Target : ", i);
|
||||
printk_address((unsigned long)bfin_read_TBUF());
|
||||
printk("\n" KERN_EMERG " Source : ");
|
||||
printk_address((unsigned long)bfin_read_TBUF());
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
trace_buffer_restore(tflags);
|
||||
}
|
||||
EXPORT_SYMBOL(dump_bfin_trace_buffer);
|
||||
|
||||
static void show_trace(struct task_struct *tsk, unsigned long *sp)
|
||||
{
|
||||
unsigned long addr;
|
||||
|
||||
printk("\nCall Trace:");
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
printk("\n");
|
||||
#endif
|
||||
|
||||
while (!kstack_end(sp)) {
|
||||
addr = *sp++;
|
||||
/*
|
||||
* 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))
|
||||
print_ip_sym(addr);
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *task, unsigned long *stack)
|
||||
{
|
||||
unsigned long *endstack, addr;
|
||||
int i;
|
||||
|
||||
/* Cannot call dump_bfin_trace_buffer() here as show_stack() is
|
||||
* called externally in some places in the kernel.
|
||||
*/
|
||||
|
||||
if (!stack) {
|
||||
if (task)
|
||||
stack = (unsigned long *)task->thread.ksp;
|
||||
else
|
||||
stack = (unsigned long *)&stack;
|
||||
}
|
||||
|
||||
addr = (unsigned long)stack;
|
||||
endstack = (unsigned long *)PAGE_ALIGN(addr);
|
||||
|
||||
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
|
||||
for (i = 0; i < kstack_depth_to_print; i++) {
|
||||
if (stack + 1 > endstack)
|
||||
break;
|
||||
if (i % 8 == 0)
|
||||
printk("\n" KERN_EMERG " ");
|
||||
printk(" %08lx", *stack++);
|
||||
}
|
||||
|
||||
show_trace(task, stack);
|
||||
}
|
||||
|
||||
void dump_stack(void)
|
||||
{
|
||||
unsigned long stack;
|
||||
int tflags;
|
||||
trace_buffer_save(tflags);
|
||||
dump_bfin_trace_buffer();
|
||||
show_stack(current, &stack);
|
||||
trace_buffer_restore(tflags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(dump_stack);
|
||||
|
||||
void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
|
||||
{
|
||||
if (current->pid) {
|
||||
printk("\nCURRENT PROCESS:\n\n");
|
||||
printk("COMM=%s PID=%d\n", current->comm, current->pid);
|
||||
} else {
|
||||
printk
|
||||
("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n");
|
||||
}
|
||||
|
||||
if (current->mm) {
|
||||
printk("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
|
||||
"BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n",
|
||||
(void*)current->mm->start_code,
|
||||
(void*)current->mm->end_code,
|
||||
(void*)current->mm->start_data,
|
||||
(void*)current->mm->end_data,
|
||||
(void*)current->mm->end_data,
|
||||
(void*)current->mm->brk,
|
||||
(void*)current->mm->start_stack);
|
||||
}
|
||||
|
||||
printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr);
|
||||
if (retaddr != 0 && retaddr <= (void*)physical_mem_end
|
||||
#if L1_CODE_LENGTH != 0
|
||||
/* FIXME: Copy the code out of L1 Instruction SRAM through dma
|
||||
memcpy. */
|
||||
&& !(retaddr >= (void*)L1_CODE_START
|
||||
&& retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
|
||||
#endif
|
||||
) {
|
||||
int i = 0;
|
||||
unsigned short x = 0;
|
||||
for (i = -16; i < 8; i++) {
|
||||
if (get_user(x, (unsigned short *)retaddr + i))
|
||||
break;
|
||||
#ifndef CONFIG_DEBUG_HWERR
|
||||
/* If one of the last few instructions was a STI
|
||||
* it is likily that the error occured awhile ago
|
||||
* and we just noticed
|
||||
*/
|
||||
if (x >= 0x0040 && x <= 0x0047 && i <= 0)
|
||||
panic("\n\nWARNING : You should reconfigure the kernel to turn on\n"
|
||||
" 'Hardware error interrupt debugging'\n"
|
||||
" The rest of this error is meanless\n");
|
||||
#endif
|
||||
|
||||
if (i == -8)
|
||||
printk("\n");
|
||||
if (i == 0)
|
||||
printk("X\n");
|
||||
printk("%04x ", x);
|
||||
}
|
||||
} else
|
||||
printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n");
|
||||
|
||||
printk("\n\n");
|
||||
|
||||
printk("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n",
|
||||
fp->rete, fp->retn, fp->retx, fp->rets);
|
||||
printk("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg);
|
||||
printk("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp);
|
||||
printk("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
|
||||
fp->r0, fp->r1, fp->r2, fp->r3);
|
||||
printk("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
|
||||
fp->r4, fp->r5, fp->r6, fp->r7);
|
||||
printk("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
|
||||
fp->p0, fp->p1, fp->p2, fp->p3);
|
||||
printk("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp);
|
||||
printk("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
|
||||
fp->a0w, fp->a0x, fp->a1w, fp->a1x);
|
||||
|
||||
printk("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0,
|
||||
fp->lc0);
|
||||
printk("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1,
|
||||
fp->lc1);
|
||||
printk("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0,
|
||||
fp->m0, fp->i0);
|
||||
printk("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1,
|
||||
fp->m1, fp->i1);
|
||||
printk("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2,
|
||||
fp->m2, fp->i2);
|
||||
printk("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3,
|
||||
fp->m3, fp->i3);
|
||||
|
||||
printk("\nUSP: %08lx ASTAT: %08lx\n", rdusp(), fp->astat);
|
||||
if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
|
||||
printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
|
||||
printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
|
||||
}
|
||||
|
||||
printk("\n\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
|
||||
asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
asmlinkage int sys_bfin_spinlock(int *spinlock)
|
||||
{
|
||||
int ret = 0;
|
||||
int tmp = 0;
|
||||
|
||||
local_irq_disable();
|
||||
ret = get_user(tmp, spinlock);
|
||||
if (ret == 0) {
|
||||
if (tmp)
|
||||
ret = 1;
|
||||
tmp = 1;
|
||||
put_user(tmp, spinlock);
|
||||
}
|
||||
local_irq_enable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
|
||||
{
|
||||
switch (cplb_panic) {
|
||||
case CPLB_NO_UNLOCKED:
|
||||
printk(KERN_EMERG "All CPLBs are locked\n");
|
||||
break;
|
||||
case CPLB_PROT_VIOL:
|
||||
return;
|
||||
case CPLB_NO_ADDR_MATCH:
|
||||
return;
|
||||
case CPLB_UNKNOWN_ERR:
|
||||
printk(KERN_EMERG "Unknown CPLB Exception\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
|
||||
printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
|
||||
dump_bfin_regs(fp, (void *)fp->retx);
|
||||
dump_stack();
|
||||
panic("Unrecoverable event\n");
|
||||
}
|
228
arch/blackfin/kernel/vmlinux.lds.S
Normal file
228
arch/blackfin/kernel/vmlinux.lds.S
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* File: arch/blackfin/kernel/vmlinux.lds.S
|
||||
* Based on: none - original work
|
||||
* Author:
|
||||
*
|
||||
* Created: Tue Sep 21 2004
|
||||
* Description: Master linker script for blackfin architecture
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define VMLINUX_SYMBOL(_sym_) _##_sym_
|
||||
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
#include <asm/mem_map.h>
|
||||
|
||||
|
||||
OUTPUT_FORMAT("elf32-bfin")
|
||||
ENTRY(__start)
|
||||
_jiffies = _jiffies_64;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ram : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD)
|
||||
l1_data_a : ORIGIN = L1_DATA_A_START, LENGTH = L1_DATA_A_LENGTH
|
||||
l1_data_b : ORIGIN = L1_DATA_B_START, LENGTH = L1_DATA_B_LENGTH
|
||||
l1_code : ORIGIN = L1_CODE_START, LENGTH = L1_CODE_LENGTH
|
||||
l1_scratch : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = CONFIG_BOOT_LOAD;
|
||||
|
||||
.text :
|
||||
{
|
||||
_text = .;
|
||||
__stext = .;
|
||||
*(.text)
|
||||
SCHED_TEXT
|
||||
*(.text.lock)
|
||||
. = ALIGN(16);
|
||||
___start___ex_table = .;
|
||||
*(__ex_table)
|
||||
___stop___ex_table = .;
|
||||
|
||||
*($code)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(__vermagic) /* Kernel version magic */
|
||||
*(.rodata1)
|
||||
*(.fixup)
|
||||
*(.spinlock.text)
|
||||
|
||||
/* Kernel symbol table: Normal symbols */
|
||||
. = ALIGN(4);
|
||||
___start___ksymtab = .;
|
||||
*(__ksymtab)
|
||||
___stop___ksymtab = .;
|
||||
|
||||
/* Kernel symbol table: GPL-only symbols */
|
||||
___start___ksymtab_gpl = .;
|
||||
*(__ksymtab_gpl)
|
||||
___stop___ksymtab_gpl = .;
|
||||
|
||||
/* Kernel symbol table: Normal unused symbols */ \
|
||||
___start___ksymtab_unused = .;
|
||||
*(__ksymtab_unused)
|
||||
___stop___ksymtab_unused = .;
|
||||
|
||||
/* Kernel symbol table: GPL-only unused symbols */
|
||||
___start___ksymtab_unused_gpl = .;
|
||||
*(__ksymtab_unused_gpl)
|
||||
___stop___ksymtab_unused_gpl = .;
|
||||
|
||||
|
||||
/* Kernel symbol table: GPL-future symbols */
|
||||
___start___ksymtab_gpl_future = .;
|
||||
*(__ksymtab_gpl_future)
|
||||
___stop___ksymtab_gpl_future = .;
|
||||
|
||||
/* Kernel symbol table: Normal symbols */
|
||||
___start___kcrctab = .;
|
||||
*(__kcrctab)
|
||||
___stop___kcrctab = .;
|
||||
|
||||
/* Kernel symbol table: GPL-only symbols */
|
||||
___start___kcrctab_gpl = .;
|
||||
*(__kcrctab_gpl)
|
||||
___stop___kcrctab_gpl = .;
|
||||
|
||||
/* Kernel symbol table: GPL-future symbols */
|
||||
___start___kcrctab_gpl_future = .;
|
||||
*(__kcrctab_gpl_future)
|
||||
___stop___kcrctab_gpl_future = .;
|
||||
|
||||
/* Kernel symbol table: strings */
|
||||
*(__ksymtab_strings)
|
||||
|
||||
. = ALIGN(4);
|
||||
__etext = .;
|
||||
} > ram
|
||||
|
||||
.init :
|
||||
{
|
||||
. = ALIGN(4096);
|
||||
___init_begin = .;
|
||||
__sinittext = .;
|
||||
*(.init.text)
|
||||
__einittext = .;
|
||||
*(.init.data)
|
||||
. = ALIGN(16);
|
||||
___setup_start = .;
|
||||
*(.init.setup)
|
||||
___setup_end = .;
|
||||
___start___param = .;
|
||||
*(__param)
|
||||
___stop___param = .;
|
||||
___initcall_start = .;
|
||||
INITCALLS
|
||||
___initcall_end = .;
|
||||
___con_initcall_start = .;
|
||||
*(.con_initcall.init)
|
||||
___con_initcall_end = .;
|
||||
___security_initcall_start = .;
|
||||
*(.security_initcall.init)
|
||||
___security_initcall_end = .;
|
||||
. = ALIGN(4);
|
||||
___initramfs_start = .;
|
||||
*(.init.ramfs)
|
||||
___initramfs_end = .;
|
||||
. = ALIGN(4);
|
||||
___init_end = .;
|
||||
} > ram
|
||||
|
||||
__l1_lma_start = .;
|
||||
|
||||
.text_l1 :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__stext_l1 = .;
|
||||
*(.l1.text)
|
||||
|
||||
. = ALIGN(4);
|
||||
__etext_l1 = .;
|
||||
} > l1_code AT > ram
|
||||
|
||||
.data_l1 :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__sdata_l1 = .;
|
||||
*(.l1.data)
|
||||
__edata_l1 = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__sbss_l1 = .;
|
||||
*(.l1.bss)
|
||||
|
||||
. = ALIGN(32);
|
||||
*(.data_l1.cacheline_aligned)
|
||||
|
||||
. = ALIGN(4);
|
||||
__ebss_l1 = .;
|
||||
} > l1_data_a AT > ram
|
||||
.data_b_l1 :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__sdata_b_l1 = .;
|
||||
*(.l1.data.B)
|
||||
__edata_b_l1 = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
__sbss_b_l1 = .;
|
||||
*(.l1.bss.B)
|
||||
|
||||
. = ALIGN(4);
|
||||
__ebss_b_l1 = .;
|
||||
} > l1_data_b AT > ram
|
||||
|
||||
.data :
|
||||
{
|
||||
__sdata = .;
|
||||
. = ALIGN(0x2000);
|
||||
*(.data.init_task)
|
||||
*(.data)
|
||||
|
||||
. = ALIGN(32);
|
||||
*(.data.cacheline_aligned)
|
||||
|
||||
. = ALIGN(0x2000);
|
||||
__edata = .;
|
||||
} > ram
|
||||
|
||||
/DISCARD/ : { /* Exit code and data*/
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
} > ram
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
___bss_start = .;
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
___bss_stop = .;
|
||||
__end = . ;
|
||||
} > ram
|
||||
}
|
11
arch/blackfin/lib/Makefile
Normal file
11
arch/blackfin/lib/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# arch/blackfin/lib/Makefile
|
||||
#
|
||||
|
||||
lib-y := \
|
||||
ashldi3.o ashrdi3.o lshrdi3.o \
|
||||
muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
|
||||
checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
|
||||
strcmp.o strcpy.o strncmp.o strncpy.o \
|
||||
umulsi3_highpart.o smulsi3_highpart.o \
|
||||
ins.o outs.o
|
58
arch/blackfin/lib/ashldi3.c
Normal file
58
arch/blackfin/lib/ashldi3.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/ashldi3.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "gcclib.h"
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
DItype __ashldi3(DItype u, word_type b)
|
||||
{
|
||||
DIunion w;
|
||||
word_type bm;
|
||||
DIunion uu;
|
||||
|
||||
if (b == 0)
|
||||
return u;
|
||||
|
||||
uu.ll = u;
|
||||
|
||||
bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
|
||||
if (bm <= 0) {
|
||||
w.s.low = 0;
|
||||
w.s.high = (USItype) uu.s.low << -bm;
|
||||
} else {
|
||||
USItype carries = (USItype) uu.s.low >> bm;
|
||||
w.s.low = (USItype) uu.s.low << b;
|
||||
w.s.high = ((USItype) uu.s.high << b) | carries;
|
||||
}
|
||||
|
||||
return w.ll;
|
||||
}
|
59
arch/blackfin/lib/ashrdi3.c
Normal file
59
arch/blackfin/lib/ashrdi3.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/ashrdi3.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "gcclib.h"
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
DItype __ashrdi3(DItype u, word_type b)
|
||||
{
|
||||
DIunion w;
|
||||
word_type bm;
|
||||
DIunion uu;
|
||||
|
||||
if (b == 0)
|
||||
return u;
|
||||
|
||||
uu.ll = u;
|
||||
|
||||
bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
|
||||
if (bm <= 0) {
|
||||
/* w.s.high = 1..1 or 0..0 */
|
||||
w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
|
||||
w.s.low = uu.s.high >> -bm;
|
||||
} else {
|
||||
USItype carries = (USItype) uu.s.high << bm;
|
||||
w.s.high = uu.s.high >> b;
|
||||
w.s.low = ((USItype) uu.s.low >> b) | carries;
|
||||
}
|
||||
|
||||
return w.ll;
|
||||
}
|
140
arch/blackfin/lib/checksum.c
Normal file
140
arch/blackfin/lib/checksum.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/checksum.c
|
||||
* Based on: none - original work
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: An implementation of the TCP/IP protocol suite for the LINUX
|
||||
* operating system. INET is implemented using the BSD Socket
|
||||
* interface as the means of communication with the user level.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <net/checksum.h>
|
||||
#include <asm/checksum.h>
|
||||
|
||||
#ifdef CONFIG_IP_CHECKSUM_L1
|
||||
static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
static unsigned short do_csum(const unsigned char *buff, int len)
|
||||
{
|
||||
register unsigned long sum = 0;
|
||||
int swappem = 0;
|
||||
|
||||
if (1 & (unsigned long)buff) {
|
||||
sum = *buff << 8;
|
||||
buff++;
|
||||
len--;
|
||||
++swappem;
|
||||
}
|
||||
|
||||
while (len > 1) {
|
||||
sum += *(unsigned short *)buff;
|
||||
buff += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
sum += *buff;
|
||||
|
||||
/* Fold 32-bit sum to 16 bits */
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
if (swappem)
|
||||
sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
|
||||
|
||||
return sum;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of ip_compute_csum() optimized for IP headers,
|
||||
* which always checksum on 4 octet boundaries.
|
||||
*/
|
||||
unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
|
||||
{
|
||||
return ~do_csum(iph, ihl * 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* computes the checksum of a memory block at buff, length len,
|
||||
* and adds in "sum" (32-bit)
|
||||
*
|
||||
* returns a 32-bit number suitable for feeding into itself
|
||||
* or csum_tcpudp_magic
|
||||
*
|
||||
* this function must be called with even lengths, except
|
||||
* for the last fragment, which may be odd
|
||||
*
|
||||
* it's best to have buff aligned on a 32-bit boundary
|
||||
*/
|
||||
unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
|
||||
{
|
||||
/*
|
||||
* Just in case we get nasty checksum data...
|
||||
* Like 0xffff6ec3 in the case of our IPv6 multicast header.
|
||||
* We fold to begin with, as well as at the end.
|
||||
*/
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
sum += do_csum(buff, len);
|
||||
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*
|
||||
* this routine is used for miscellaneous IP-like checksums, mainly
|
||||
* in icmp.c
|
||||
*/
|
||||
unsigned short ip_compute_csum(const unsigned char *buff, int len)
|
||||
{
|
||||
return ~do_csum(buff, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy from fs while checksumming, otherwise like csum_partial
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
|
||||
int len, int sum, int *csum_err)
|
||||
{
|
||||
if (csum_err)
|
||||
*csum_err = 0;
|
||||
memcpy(dst, src, len);
|
||||
return csum_partial(dst, len, sum);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy from ds while checksumming, otherwise like csum_partial
|
||||
*/
|
||||
|
||||
unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
|
||||
int len, int sum)
|
||||
{
|
||||
memcpy(dst, src, len);
|
||||
return csum_partial(dst, len, sum);
|
||||
}
|
216
arch/blackfin/lib/divsi3.S
Normal file
216
arch/blackfin/lib/divsi3.S
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/divsi3.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: 16 / 32 bit signed division.
|
||||
* Special cases :
|
||||
* 1) If(numerator == 0)
|
||||
* return 0
|
||||
* 2) If(denominator ==0)
|
||||
* return positive max = 0x7fffffff
|
||||
* 3) If(numerator == denominator)
|
||||
* return 1
|
||||
* 4) If(denominator ==1)
|
||||
* return numerator
|
||||
* 5) If(denominator == -1)
|
||||
* return -numerator
|
||||
*
|
||||
* Operand : R0 - Numerator (i)
|
||||
* R1 - Denominator (i)
|
||||
* R0 - Quotient (o)
|
||||
* Registers Used : R2-R7,P0-P2
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
.global ___divsi3;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2;
|
||||
___divsi3 :
|
||||
|
||||
|
||||
R3 = R0 ^ R1;
|
||||
R0 = ABS R0;
|
||||
|
||||
CC = V;
|
||||
|
||||
r3 = rot r3 by -1;
|
||||
r1 = abs r1; /* now both positive, r3.30 means "negate result",
|
||||
** r3.31 means overflow, add one to result
|
||||
*/
|
||||
cc = r0 < r1;
|
||||
if cc jump .Lret_zero;
|
||||
r2 = r1 >> 15;
|
||||
cc = r2;
|
||||
if cc jump .Lidents;
|
||||
r2 = r1 << 16;
|
||||
cc = r2 <= r0;
|
||||
if cc jump .Lidents;
|
||||
|
||||
DIVS(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
DIVQ(R0, R1);
|
||||
|
||||
R0 = R0.L (Z);
|
||||
r1 = r3 >> 31; /* add overflow issue back in */
|
||||
r0 = r0 + r1;
|
||||
r1 = -r0;
|
||||
cc = bittst(r3, 30);
|
||||
if cc r0 = r1;
|
||||
RTS;
|
||||
|
||||
/* Can't use the primitives. Test common identities.
|
||||
** If the identity is true, return the value in R2.
|
||||
*/
|
||||
|
||||
.Lidents:
|
||||
CC = R1 == 0; /* check for divide by zero */
|
||||
IF CC JUMP .Lident_return;
|
||||
|
||||
CC = R0 == 0; /* check for division of zero */
|
||||
IF CC JUMP .Lzero_return;
|
||||
|
||||
CC = R0 == R1; /* check for identical operands */
|
||||
IF CC JUMP .Lident_return;
|
||||
|
||||
CC = R1 == 1; /* check for divide by 1 */
|
||||
IF CC JUMP .Lident_return;
|
||||
|
||||
R2.L = ONES R1;
|
||||
R2 = R2.L (Z);
|
||||
CC = R2 == 1;
|
||||
IF CC JUMP .Lpower_of_two;
|
||||
|
||||
/* Identities haven't helped either.
|
||||
** Perform the full division process.
|
||||
*/
|
||||
|
||||
P1 = 31; /* Set loop counter */
|
||||
|
||||
[--SP] = (R7:5); /* Push registers R5-R7 */
|
||||
R2 = -R1;
|
||||
[--SP] = R2;
|
||||
R2 = R0 << 1; /* R2 lsw of dividend */
|
||||
R6 = R0 ^ R1; /* Get sign */
|
||||
R5 = R6 >> 31; /* Shift sign to LSB */
|
||||
|
||||
R0 = 0 ; /* Clear msw partial remainder */
|
||||
R2 = R2 | R5; /* Shift quotient bit */
|
||||
R6 = R0 ^ R1; /* Get new quotient bit */
|
||||
|
||||
LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */
|
||||
.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */
|
||||
R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
|
||||
R0 = R0 << 1 || R5 = [SP];
|
||||
R0 = R0 | R7; /* and add carry */
|
||||
CC = R6 < 0; /* Check quotient(AQ) */
|
||||
/* we might be subtracting divisor (AQ==0) */
|
||||
IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/
|
||||
R0 = R0 + R5; /* do add or subtract, as indicated by AQ */
|
||||
R6 = R0 ^ R1; /* Generate next quotient bit */
|
||||
R5 = R6 >> 31;
|
||||
/* Assume AQ==1, shift in zero */
|
||||
BITTGL(R5,0); /* tweak AQ to be what we want to shift in */
|
||||
.Llend: R2 = R2 + R5; /* and then set shifted-in value to
|
||||
** tweaked AQ.
|
||||
*/
|
||||
r1 = r3 >> 31;
|
||||
r2 = r2 + r1;
|
||||
cc = bittst(r3,30);
|
||||
r0 = -r2;
|
||||
if !cc r0 = r2;
|
||||
SP += 4;
|
||||
(R7:5)= [SP++]; /* Pop registers R6-R7 */
|
||||
RTS;
|
||||
|
||||
.Lident_return:
|
||||
CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
|
||||
R2 = -1 (X);
|
||||
R2 >>= 1;
|
||||
IF CC JUMP .Ltrue_ident_return;
|
||||
|
||||
CC = R0 == R1; /* check for identical operands => 1 */
|
||||
R2 = 1 (Z);
|
||||
IF CC JUMP .Ltrue_ident_return;
|
||||
|
||||
R2 = R0; /* assume divide by 1 => numerator */
|
||||
/*FALLTHRU*/
|
||||
|
||||
.Ltrue_ident_return:
|
||||
R0 = R2; /* Return an identity value */
|
||||
R2 = -R2;
|
||||
CC = bittst(R3,30);
|
||||
IF CC R0 = R2;
|
||||
.Lzero_return:
|
||||
RTS; /* ...including zero */
|
||||
|
||||
.Lpower_of_two:
|
||||
/* Y has a single bit set, which means it's a power of two.
|
||||
** That means we can perform the division just by shifting
|
||||
** X to the right the appropriate number of bits
|
||||
*/
|
||||
|
||||
/* signbits returns the number of sign bits, minus one.
|
||||
** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
|
||||
** to shift right n-signbits spaces. It also means 0x80000000
|
||||
** is a special case, because that *also* gives a signbits of 0
|
||||
*/
|
||||
|
||||
R2 = R0 >> 31;
|
||||
CC = R1 < 0;
|
||||
IF CC JUMP .Ltrue_ident_return;
|
||||
|
||||
R1.l = SIGNBITS R1;
|
||||
R1 = R1.L (Z);
|
||||
R1 += -30;
|
||||
R0 = LSHIFT R0 by R1.L;
|
||||
r1 = r3 >> 31;
|
||||
r0 = r0 + r1;
|
||||
R2 = -R0; // negate result if necessary
|
||||
CC = bittst(R3,30);
|
||||
IF CC R0 = R2;
|
||||
RTS;
|
||||
|
||||
.Lret_zero:
|
||||
R0 = 0;
|
||||
RTS;
|
47
arch/blackfin/lib/gcclib.h
Normal file
47
arch/blackfin/lib/gcclib.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/gcclib.h
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define BITS_PER_UNIT 8
|
||||
#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
|
||||
|
||||
typedef unsigned int UQItype __attribute__ ((mode(QI)));
|
||||
typedef int SItype __attribute__ ((mode(SI)));
|
||||
typedef unsigned int USItype __attribute__ ((mode(SI)));
|
||||
typedef int DItype __attribute__ ((mode(DI)));
|
||||
typedef int word_type __attribute__ ((mode(__word__)));
|
||||
typedef unsigned int UDItype __attribute__ ((mode(DI)));
|
||||
|
||||
struct DIstruct {
|
||||
SItype low, high;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
struct DIstruct s;
|
||||
DItype ll;
|
||||
} DIunion;
|
69
arch/blackfin/lib/ins.S
Normal file
69
arch/blackfin/lib/ins.S
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/ins.S
|
||||
* Based on:
|
||||
* Author: Bas Vermeulen <bas@buyways.nl>
|
||||
*
|
||||
* Created: Tue Mar 22 15:27:24 CEST 2005
|
||||
* Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
* Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_insl)
|
||||
P0 = R0; /* P0 = port */
|
||||
cli R3;
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
SSYNC;
|
||||
LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
|
||||
.Llong_loop_s: R0 = [P0];
|
||||
.Llong_loop_e: [P1++] = R0;
|
||||
sti R3;
|
||||
RTS;
|
||||
|
||||
ENTRY(_insw)
|
||||
P0 = R0; /* P0 = port */
|
||||
cli R3;
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
SSYNC;
|
||||
LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
|
||||
.Lword_loop_s: R0 = W[P0];
|
||||
.Lword_loop_e: W[P1++] = R0;
|
||||
sti R3;
|
||||
RTS;
|
||||
|
||||
ENTRY(_insb)
|
||||
P0 = R0; /* P0 = port */
|
||||
cli R3;
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
SSYNC;
|
||||
LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
|
||||
.Lbyte_loop_s: R0 = B[P0];
|
||||
.Lbyte_loop_e: B[P1++] = R0;
|
||||
sti R3;
|
||||
RTS;
|
72
arch/blackfin/lib/lshrdi3.c
Normal file
72
arch/blackfin/lib/lshrdi3.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/lshrdi3.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define BITS_PER_UNIT 8
|
||||
|
||||
typedef int SItype __attribute__ ((mode(SI)));
|
||||
typedef unsigned int USItype __attribute__ ((mode(SI)));
|
||||
typedef int DItype __attribute__ ((mode(DI)));
|
||||
typedef int word_type __attribute__ ((mode(__word__)));
|
||||
|
||||
struct DIstruct {
|
||||
SItype high, low;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
struct DIstruct s;
|
||||
DItype ll;
|
||||
} DIunion;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
DItype __lshrdi3(DItype u, word_type b)
|
||||
{
|
||||
DIunion w;
|
||||
word_type bm;
|
||||
DIunion uu;
|
||||
|
||||
if (b == 0)
|
||||
return u;
|
||||
|
||||
uu.ll = u;
|
||||
|
||||
bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
|
||||
if (bm <= 0) {
|
||||
w.s.high = 0;
|
||||
w.s.low = (USItype) uu.s.high >> -bm;
|
||||
} else {
|
||||
USItype carries = (USItype) uu.s.high << bm;
|
||||
w.s.high = (USItype) uu.s.high >> b;
|
||||
w.s.low = ((USItype) uu.s.low >> b) | carries;
|
||||
}
|
||||
|
||||
return w.ll;
|
||||
}
|
70
arch/blackfin/lib/memchr.S
Normal file
70
arch/blackfin/lib/memchr.S
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/memchr.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *memchr(const void *s, int c, size_t n);
|
||||
* R0 = address (s)
|
||||
* R1 = sought byte (c)
|
||||
* R2 = count (n)
|
||||
*
|
||||
* Returns pointer to located character.
|
||||
*/
|
||||
|
||||
.text
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_memchr)
|
||||
P0 = R0; /* P0 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
R1 = R1.B(Z);
|
||||
CC = R2 == 0;
|
||||
IF CC JUMP .Lfailed;
|
||||
|
||||
.Lbytes:
|
||||
LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
|
||||
|
||||
.Lbyte_loop_s:
|
||||
R3 = B[P0++](Z);
|
||||
CC = R3 == R1;
|
||||
IF CC JUMP .Lfound;
|
||||
.Lbyte_loop_e:
|
||||
NOP;
|
||||
|
||||
.Lfailed:
|
||||
R0=0;
|
||||
RTS;
|
||||
|
||||
.Lfound:
|
||||
R0 = P0;
|
||||
R0 += -1;
|
||||
RTS;
|
||||
|
||||
.size _memchr,.-_memchr
|
110
arch/blackfin/lib/memcmp.S
Normal file
110
arch/blackfin/lib/memcmp.S
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/memcmp.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* int memcmp(const void *s1, const void *s2, size_t n);
|
||||
* R0 = First Address (s1)
|
||||
* R1 = Second Address (s2)
|
||||
* R2 = count (n)
|
||||
*
|
||||
* Favours word aligned data.
|
||||
*/
|
||||
|
||||
.text
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_memcmp)
|
||||
I1 = P3;
|
||||
P0 = R0; /* P0 = s1 address */
|
||||
P3 = R1; /* P3 = s2 Address */
|
||||
P2 = R2 ; /* P2 = count */
|
||||
CC = R2 <= 7(IU);
|
||||
IF CC JUMP .Ltoo_small;
|
||||
I0 = R1; /* s2 */
|
||||
R1 = R1 | R0; /* OR addresses together */
|
||||
R1 <<= 30; /* check bottom two bits */
|
||||
CC = AZ; /* AZ set if zero. */
|
||||
IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned. */
|
||||
|
||||
P1 = P2 >> 2; /* count = n/4 */
|
||||
R3 = 3;
|
||||
R2 = R2 & R3; /* remainder */
|
||||
P2 = R2; /* set remainder */
|
||||
|
||||
LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1;
|
||||
.Lquad_loop_s:
|
||||
MNOP || R0 = [P0++] || R1 = [I0++];
|
||||
CC = R0 == R1;
|
||||
IF !CC JUMP .Lquad_different;
|
||||
.Lquad_loop_e:
|
||||
NOP;
|
||||
|
||||
P3 = I0; /* s2 */
|
||||
.Ltoo_small:
|
||||
CC = P2 == 0; /* Check zero count*/
|
||||
IF CC JUMP .Lfinished; /* very unlikely*/
|
||||
|
||||
.Lbytes:
|
||||
LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
|
||||
.Lbyte_loop_s:
|
||||
R1 = B[P3++](Z); /* *s2 */
|
||||
R0 = B[P0++](Z); /* *s1 */
|
||||
CC = R0 == R1;
|
||||
IF !CC JUMP .Ldifferent;
|
||||
.Lbyte_loop_e:
|
||||
NOP;
|
||||
|
||||
.Ldifferent:
|
||||
R0 = R0 - R1;
|
||||
P3 = I1;
|
||||
RTS;
|
||||
|
||||
.Lquad_different:
|
||||
/* We've read two quads which don't match.
|
||||
* Can't just compare them, because we're
|
||||
* a little-endian machine, so the MSBs of
|
||||
* the regs occur at later addresses in the
|
||||
* string.
|
||||
* Arrange to re-read those two quads again,
|
||||
* byte-by-byte.
|
||||
*/
|
||||
P0 += -4; /* back up to the start of the */
|
||||
P3 = I0; /* quads, and increase the*/
|
||||
P2 += 4; /* remainder count*/
|
||||
P3 += -4;
|
||||
JUMP .Lbytes;
|
||||
|
||||
.Lfinished:
|
||||
R0 = 0;
|
||||
P3 = I1;
|
||||
RTS;
|
||||
|
||||
.size _memcmp,.-_memcmp
|
142
arch/blackfin/lib/memcpy.S
Normal file
142
arch/blackfin/lib/memcpy.S
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/memcpy.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: internal version of memcpy(), issued by the compiler
|
||||
* to copy blocks of data around.
|
||||
* This is really memmove() - it has to be able to deal with
|
||||
* possible overlaps, because that ambiguity is when the compiler
|
||||
* gives up and calls a function. We have our own, internal version
|
||||
* so that we get something we trust, even if the user has redefined
|
||||
* the normal symbol.
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
/* void *memcpy(void *dest, const void *src, size_t n);
|
||||
* R0 = To Address (dest) (leave unchanged to form result)
|
||||
* R1 = From Address (src)
|
||||
* R2 = count
|
||||
*
|
||||
* Note: Favours word alignment
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MEMCPY_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_memcpy)
|
||||
CC = R2 <= 0; /* length not positive? */
|
||||
IF CC JUMP .L_P1L2147483647; /* Nothing to do */
|
||||
|
||||
P0 = R0 ; /* dst*/
|
||||
P1 = R1 ; /* src*/
|
||||
P2 = R2 ; /* length */
|
||||
|
||||
/* check for overlapping data */
|
||||
CC = R1 < R0; /* src < dst */
|
||||
IF !CC JUMP .Lno_overlap;
|
||||
R3 = R1 + R2;
|
||||
CC = R0 < R3; /* and dst < src+len */
|
||||
IF CC JUMP .Lhas_overlap;
|
||||
|
||||
.Lno_overlap:
|
||||
/* Check for aligned data.*/
|
||||
|
||||
R3 = R1 | R0;
|
||||
R0 = 0x3;
|
||||
R3 = R3 & R0;
|
||||
CC = R3; /* low bits set on either address? */
|
||||
IF CC JUMP .Lnot_aligned;
|
||||
|
||||
/* Both addresses are word-aligned, so we can copy
|
||||
at least part of the data using word copies.*/
|
||||
P2 = P2 >> 2;
|
||||
CC = P2 <= 2;
|
||||
IF !CC JUMP .Lmore_than_seven;
|
||||
/* less than eight bytes... */
|
||||
P2 = R2;
|
||||
LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
|
||||
R0 = R1; /* setup src address for return */
|
||||
.Lthree_start:
|
||||
R3 = B[P1++] (X);
|
||||
.Lthree_end:
|
||||
B[P0++] = R3;
|
||||
|
||||
RTS;
|
||||
|
||||
.Lmore_than_seven:
|
||||
/* There's at least eight bytes to copy. */
|
||||
P2 += -1; /* because we unroll one iteration */
|
||||
LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
|
||||
R0 = R1;
|
||||
I1 = P1;
|
||||
R3 = [I1++];
|
||||
.Lword_loop:
|
||||
MNOP || [P0++] = R3 || R3 = [I1++];
|
||||
|
||||
[P0++] = R3;
|
||||
/* Any remaining bytes to copy? */
|
||||
R3 = 0x3;
|
||||
R3 = R2 & R3;
|
||||
CC = R3 == 0;
|
||||
P1 = I1; /* in case there's something left, */
|
||||
IF !CC JUMP .Lbytes_left;
|
||||
RTS;
|
||||
.Lbytes_left: P2 = R3;
|
||||
.Lnot_aligned:
|
||||
/* From here, we're copying byte-by-byte. */
|
||||
LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
|
||||
R0 = R1; /* Save src address for return */
|
||||
.Lbyte_start:
|
||||
R1 = B[P1++] (X);
|
||||
.Lbyte_end:
|
||||
B[P0++] = R1;
|
||||
|
||||
.L_P1L2147483647:
|
||||
RTS;
|
||||
|
||||
.Lhas_overlap:
|
||||
/* Need to reverse the copying, because the
|
||||
* dst would clobber the src.
|
||||
* Don't bother to work out alignment for
|
||||
* the reverse case.
|
||||
*/
|
||||
R0 = R1; /* save src for later. */
|
||||
P0 = P0 + P2;
|
||||
P0 += -1;
|
||||
P1 = P1 + P2;
|
||||
P1 += -1;
|
||||
LSETUP(.Lover_start, .Lover_end) LC0=P2;
|
||||
.Lover_start:
|
||||
R1 = B[P1--] (X);
|
||||
.Lover_end:
|
||||
B[P0--] = R1;
|
||||
|
||||
RTS;
|
103
arch/blackfin/lib/memmove.S
Normal file
103
arch/blackfin/lib/memmove.S
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/memmove.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.align 2
|
||||
|
||||
/*
|
||||
* C Library function MEMMOVE
|
||||
* R0 = To Address (leave unchanged to form result)
|
||||
* R1 = From Address
|
||||
* R2 = count
|
||||
* Data may overlap
|
||||
*/
|
||||
|
||||
ENTRY(_memmove)
|
||||
I1 = P3;
|
||||
P0 = R0; /* P0 = To address */
|
||||
P3 = R1; /* P3 = From Address */
|
||||
P2 = R2; /* P2 = count */
|
||||
CC = P2 == 0; /* Check zero count*/
|
||||
IF CC JUMP .Lfinished; /* very unlikely */
|
||||
|
||||
CC = R1 < R0 (IU); /* From < To */
|
||||
IF !CC JUMP .Lno_overlap;
|
||||
R3 = R1 + R2;
|
||||
CC = R0 <= R3 (IU); /* (From+len) >= To */
|
||||
IF CC JUMP .Loverlap;
|
||||
.Lno_overlap:
|
||||
R3 = 11;
|
||||
CC = R2 <= R3;
|
||||
IF CC JUMP .Lbytes;
|
||||
R3 = R1 | R0; /* OR addresses together */
|
||||
R3 <<= 30; /* check bottom two bits */
|
||||
CC = AZ; /* AZ set if zero.*/
|
||||
IF !CC JUMP .Lbytes; /* Jump if addrs not aligned.*/
|
||||
|
||||
I0 = P3;
|
||||
P1 = P2 >> 2; /* count = n/4 */
|
||||
P1 += -1;
|
||||
R3 = 3;
|
||||
R2 = R2 & R3; /* remainder */
|
||||
P2 = R2; /* set remainder */
|
||||
R1 = [I0++];
|
||||
|
||||
LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1;
|
||||
.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
|
||||
[P0++] = R1;
|
||||
|
||||
CC = P2 == 0; /* any remaining bytes? */
|
||||
P3 = I0; /* Ammend P3 to updated ptr. */
|
||||
IF !CC JUMP .Lbytes;
|
||||
P3 = I1;
|
||||
RTS;
|
||||
|
||||
.Lbytes: LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2;
|
||||
.Lbyte2_s: R1 = B[P3++](Z);
|
||||
.Lbyte2_e: B[P0++] = R1;
|
||||
|
||||
.Lfinished: P3 = I1;
|
||||
RTS;
|
||||
|
||||
.Loverlap:
|
||||
P2 += -1;
|
||||
P0 = P0 + P2;
|
||||
P3 = P3 + P2;
|
||||
R1 = B[P3--] (Z);
|
||||
CC = P2 == 0;
|
||||
IF CC JUMP .Lno_loop;
|
||||
LSETUP (.Lol_s, .Lol_e) LC0 = P2;
|
||||
.Lol_s: B[P0--] = R1;
|
||||
.Lol_e: R1 = B[P3--] (Z);
|
||||
.Lno_loop: B[P0] = R1;
|
||||
P3 = I1;
|
||||
RTS;
|
||||
|
||||
.size _memmove,.-_memmove
|
109
arch/blackfin/lib/memset.S
Normal file
109
arch/blackfin/lib/memset.S
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/memset.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.align 2
|
||||
|
||||
#ifdef CONFIG_MEMSET_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C Library function MEMSET
|
||||
* R0 = address (leave unchanged to form result)
|
||||
* R1 = filler byte
|
||||
* R2 = count
|
||||
* Favours word aligned data.
|
||||
*/
|
||||
|
||||
ENTRY(_memset)
|
||||
P0 = R0 ; /* P0 = address */
|
||||
P2 = R2 ; /* P2 = count */
|
||||
R3 = R0 + R2; /* end */
|
||||
CC = R2 <= 7(IU);
|
||||
IF CC JUMP .Ltoo_small;
|
||||
R1 = R1.B (Z); /* R1 = fill char */
|
||||
R2 = 3;
|
||||
R2 = R0 & R2; /* addr bottom two bits */
|
||||
CC = R2 == 0; /* AZ set if zero. */
|
||||
IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */
|
||||
|
||||
.Laligned:
|
||||
P1 = P2 >> 2; /* count = n/4 */
|
||||
R2 = R1 << 8; /* create quad filler */
|
||||
R2.L = R2.L + R1.L(NS);
|
||||
R2.H = R2.L + R1.H(NS);
|
||||
P2 = R3;
|
||||
|
||||
LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
|
||||
.Lquad_loop:
|
||||
[P0++] = R2;
|
||||
|
||||
CC = P0 == P2;
|
||||
IF !CC JUMP .Lbytes_left;
|
||||
RTS;
|
||||
|
||||
.Lbytes_left:
|
||||
R2 = R3; /* end point */
|
||||
R3 = P0; /* current position */
|
||||
R2 = R2 - R3; /* bytes left */
|
||||
P2 = R2;
|
||||
|
||||
.Ltoo_small:
|
||||
CC = P2 == 0; /* Check zero count */
|
||||
IF CC JUMP .Lfinished; /* Unusual */
|
||||
|
||||
.Lbytes:
|
||||
LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
|
||||
.Lbyte_loop:
|
||||
B[P0++] = R1;
|
||||
|
||||
.Lfinished:
|
||||
RTS;
|
||||
|
||||
.Lforce_align:
|
||||
CC = BITTST (R0, 0); /* odd byte */
|
||||
R0 = 4;
|
||||
R0 = R0 - R2;
|
||||
P1 = R0;
|
||||
R0 = P0; /* Recover return address */
|
||||
IF !CC JUMP .Lskip1;
|
||||
B[P0++] = R1;
|
||||
.Lskip1:
|
||||
CC = R2 <= 2; /* 2 bytes */
|
||||
P2 -= P1; /* reduce count */
|
||||
IF !CC JUMP .Laligned;
|
||||
B[P0++] = R1;
|
||||
B[P0++] = R1;
|
||||
JUMP .Laligned;
|
||||
|
||||
.size _memset,.-_memset
|
79
arch/blackfin/lib/modsi3.S
Normal file
79
arch/blackfin/lib/modsi3.S
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/modsi3.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: This program computes 32 bit signed remainder. It calls div32 function
|
||||
* for quotient estimation.
|
||||
*
|
||||
* Registers used :
|
||||
* Numerator/ Denominator in R0, R1
|
||||
* R0 - returns remainder.
|
||||
* R2-R7
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
.global ___modsi3;
|
||||
.type ___modsi3, STT_FUNC;
|
||||
.extern ___divsi3;
|
||||
.type ___divsi3, STT_FUNC;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
___modsi3:
|
||||
|
||||
CC=R0==0;
|
||||
IF CC JUMP .LRETURN_R0; /* Return 0, if numerator == 0 */
|
||||
CC=R1==0;
|
||||
IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 0 */
|
||||
CC=R0==R1;
|
||||
IF CC JUMP .LRETURN_ZERO; /* Return 0, if numerator == denominator */
|
||||
CC = R1 == 1;
|
||||
IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 1 */
|
||||
CC = R1 == -1;
|
||||
IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == -1 */
|
||||
|
||||
/* Valid input. Use __divsi3() to compute the quotient, and then
|
||||
* derive the remainder from that. */
|
||||
|
||||
[--SP] = (R7:6); /* Push R7 and R6 */
|
||||
[--SP] = RETS; /* and return address */
|
||||
R7 = R0; /* Copy of R0 */
|
||||
R6 = R1; /* Save for later */
|
||||
SP += -12; /* Should always provide this space */
|
||||
CALL ___divsi3; /* Compute signed quotient using ___divsi3()*/
|
||||
SP += 12;
|
||||
R0 *= R6; /* Quotient * divisor */
|
||||
R0 = R7 - R0; /* Dividend - (quotient * divisor) */
|
||||
RETS = [SP++]; /* Get back return address */
|
||||
(R7:6) = [SP++]; /* Pop registers R7 and R4 */
|
||||
RTS; /* Store remainder */
|
||||
|
||||
.LRETURN_ZERO:
|
||||
R0 = 0;
|
||||
.LRETURN_R0:
|
||||
RTS;
|
99
arch/blackfin/lib/muldi3.c
Normal file
99
arch/blackfin/lib/muldi3.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/muldi3.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef SI_TYPE_SIZE
|
||||
#define SI_TYPE_SIZE 32
|
||||
#endif
|
||||
#define __ll_b (1L << (SI_TYPE_SIZE / 2))
|
||||
#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
|
||||
#define __ll_highpart(t) ((usitype) (t) / __ll_b)
|
||||
#define BITS_PER_UNIT 8
|
||||
|
||||
#if !defined(umul_ppmm)
|
||||
#define umul_ppmm(w1, w0, u, v) \
|
||||
do { \
|
||||
usitype __x0, __x1, __x2, __x3; \
|
||||
usitype __ul, __vl, __uh, __vh; \
|
||||
\
|
||||
__ul = __ll_lowpart (u); \
|
||||
__uh = __ll_highpart (u); \
|
||||
__vl = __ll_lowpart (v); \
|
||||
__vh = __ll_highpart (v); \
|
||||
\
|
||||
__x0 = (usitype) __ul * __vl; \
|
||||
__x1 = (usitype) __ul * __vh; \
|
||||
__x2 = (usitype) __uh * __vl; \
|
||||
__x3 = (usitype) __uh * __vh; \
|
||||
\
|
||||
__x1 += __ll_highpart (__x0);/* this can't give carry */ \
|
||||
__x1 += __x2; /* but this indeed can */ \
|
||||
if (__x1 < __x2) /* did we get it? */ \
|
||||
__x3 += __ll_b; /* yes, add it in the proper pos. */ \
|
||||
\
|
||||
(w1) = __x3 + __ll_highpart (__x1); \
|
||||
(w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if !defined(__umulsidi3)
|
||||
#define __umulsidi3(u, v) \
|
||||
({diunion __w; \
|
||||
umul_ppmm (__w.s.high, __w.s.low, u, v); \
|
||||
__w.ll; })
|
||||
#endif
|
||||
|
||||
typedef unsigned int usitype __attribute__ ((mode(SI)));
|
||||
typedef int sitype __attribute__ ((mode(SI)));
|
||||
typedef int ditype __attribute__ ((mode(DI)));
|
||||
typedef int word_type __attribute__ ((mode(__word__)));
|
||||
|
||||
struct distruct {
|
||||
sitype low, high;
|
||||
};
|
||||
typedef union {
|
||||
struct distruct s;
|
||||
ditype ll;
|
||||
} diunion;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
ditype __muldi3(ditype u, ditype v)
|
||||
{
|
||||
diunion w;
|
||||
diunion uu, vv;
|
||||
|
||||
uu.ll = u, vv.ll = v;
|
||||
w.ll = __umulsidi3(uu.s.low, vv.s.low);
|
||||
w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
|
||||
+ (usitype) uu.s.high * (usitype) vv.s.low);
|
||||
|
||||
return w.ll;
|
||||
}
|
62
arch/blackfin/lib/outs.S
Normal file
62
arch/blackfin/lib/outs.S
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/outs.S
|
||||
* Based on:
|
||||
* Author: Bas Vermeulen <bas@buyways.nl>
|
||||
*
|
||||
* Created: Tue Mar 22 15:27:24 CEST 2005
|
||||
* Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
|
||||
*
|
||||
* Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.align 2
|
||||
|
||||
ENTRY(_outsl)
|
||||
P0 = R0; /* P0 = port */
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
|
||||
LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
|
||||
.Llong_loop_s: R0 = [P1++];
|
||||
.Llong_loop_e: [P0] = R0;
|
||||
RTS;
|
||||
|
||||
ENTRY(_outsw)
|
||||
P0 = R0; /* P0 = port */
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
|
||||
LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
|
||||
.Lword_loop_s: R0 = W[P1++];
|
||||
.Lword_loop_e: W[P0] = R0;
|
||||
RTS;
|
||||
|
||||
ENTRY(_outsb)
|
||||
P0 = R0; /* P0 = port */
|
||||
P1 = R1; /* P1 = address */
|
||||
P2 = R2; /* P2 = count */
|
||||
|
||||
LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
|
||||
.Lbyte_loop_s: R0 = B[P1++];
|
||||
.Lbyte_loop_e: B[P0] = R0;
|
||||
RTS;
|
30
arch/blackfin/lib/smulsi3_highpart.S
Normal file
30
arch/blackfin/lib/smulsi3_highpart.S
Normal file
|
@ -0,0 +1,30 @@
|
|||
.align 2
|
||||
.global ___smulsi3_highpart;
|
||||
.type ___smulsi3_highpart, STT_FUNC;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
___smulsi3_highpart:
|
||||
R2 = R1.L * R0.L (FU);
|
||||
R3 = R1.H * R0.L (IS,M);
|
||||
R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M);
|
||||
|
||||
R1.L = R2.H + R1.L;
|
||||
cc = ac0;
|
||||
R2 = cc;
|
||||
|
||||
R1.L = R1.L + R3.L;
|
||||
cc = ac0;
|
||||
R1 >>>= 16;
|
||||
R3 >>>= 16;
|
||||
R1 = R1 + R3;
|
||||
R1 = R1 + R2;
|
||||
R2 = cc;
|
||||
R1 = R1 + R2;
|
||||
|
||||
R0 = R0 + R1;
|
||||
RTS;
|
11
arch/blackfin/lib/strcmp.c
Normal file
11
arch/blackfin/lib/strcmp.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define strcmp __inline_strcmp
|
||||
#include <asm/string.h>
|
||||
#undef strcmp
|
||||
|
||||
int strcmp(const char *dest, const char *src)
|
||||
{
|
||||
return __inline_strcmp(dest, src);
|
||||
}
|
||||
|
11
arch/blackfin/lib/strcpy.c
Normal file
11
arch/blackfin/lib/strcpy.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define strcpy __inline_strcpy
|
||||
#include <asm/string.h>
|
||||
#undef strcpy
|
||||
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
return __inline_strcpy(dest, src);
|
||||
}
|
||||
|
11
arch/blackfin/lib/strncmp.c
Normal file
11
arch/blackfin/lib/strncmp.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define strncmp __inline_strncmp
|
||||
#include <asm/string.h>
|
||||
#undef strncmp
|
||||
|
||||
int strncmp(const char *cs, const char *ct, size_t count)
|
||||
{
|
||||
return __inline_strncmp(cs, ct, count);
|
||||
}
|
||||
|
11
arch/blackfin/lib/strncpy.c
Normal file
11
arch/blackfin/lib/strncpy.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define strncpy __inline_strncpy
|
||||
#include <asm/string.h>
|
||||
#undef strncpy
|
||||
|
||||
char *strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
return __inline_strncpy(dest, src, n);
|
||||
}
|
||||
|
298
arch/blackfin/lib/udivsi3.S
Normal file
298
arch/blackfin/lib/udivsi3.S
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/udivsi3.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
#define CARRY AC0
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
|
||||
ENTRY(___udivsi3)
|
||||
|
||||
CC = R0 < R1 (IU); /* If X < Y, always return 0 */
|
||||
IF CC JUMP .Lreturn_ident;
|
||||
|
||||
R2 = R1 << 16;
|
||||
CC = R2 <= R0 (IU);
|
||||
IF CC JUMP .Lidents;
|
||||
|
||||
R2 = R0 >> 31; /* if X is a 31-bit number */
|
||||
R3 = R1 >> 15; /* and Y is a 15-bit number */
|
||||
R2 = R2 | R3; /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
|
||||
CC = R2;
|
||||
IF CC JUMP .Ly_16bit;
|
||||
|
||||
/* METHOD 1: FAST DIVQ
|
||||
We know we have a 31-bit dividend, and 15-bit divisor so we can use the
|
||||
simple divq approach (first setting AQ to 0 - implying unsigned division,
|
||||
then 16 DIVQ's).
|
||||
*/
|
||||
|
||||
AQ = CC; /* Clear AQ (CC==0) */
|
||||
|
||||
/* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
|
||||
we need to shift the dividend one bit to the left.
|
||||
We have already checked that we have a 31-bit number so we are safe to do
|
||||
that.
|
||||
*/
|
||||
R0 <<= 1;
|
||||
DIVQ(R0, R1); // 1
|
||||
DIVQ(R0, R1); // 2
|
||||
DIVQ(R0, R1); // 3
|
||||
DIVQ(R0, R1); // 4
|
||||
DIVQ(R0, R1); // 5
|
||||
DIVQ(R0, R1); // 6
|
||||
DIVQ(R0, R1); // 7
|
||||
DIVQ(R0, R1); // 8
|
||||
DIVQ(R0, R1); // 9
|
||||
DIVQ(R0, R1); // 10
|
||||
DIVQ(R0, R1); // 11
|
||||
DIVQ(R0, R1); // 12
|
||||
DIVQ(R0, R1); // 13
|
||||
DIVQ(R0, R1); // 14
|
||||
DIVQ(R0, R1); // 15
|
||||
DIVQ(R0, R1); // 16
|
||||
R0 = R0.L (Z);
|
||||
RTS;
|
||||
|
||||
.Ly_16bit:
|
||||
/* We know that the upper 17 bits of Y might have bits set,
|
||||
** or that the sign bit of X might have a bit. If Y is a
|
||||
** 16-bit number, but not bigger, then we can use the builtins
|
||||
** with a post-divide correction.
|
||||
** R3 currently holds Y>>15, which means R3's LSB is the
|
||||
** bit we're interested in.
|
||||
*/
|
||||
|
||||
/* According to the ISR, to use the Divide primitives for
|
||||
** unsigned integer divide, the useable range is 31 bits
|
||||
*/
|
||||
CC = ! BITTST(R0, 31);
|
||||
|
||||
/* IF condition is true we can scale our inputs and use the divide primitives,
|
||||
** with some post-adjustment
|
||||
*/
|
||||
R3 += -1; /* if so, Y is 0x00008nnn */
|
||||
CC &= AZ;
|
||||
|
||||
/* If condition is true we can scale our inputs and use the divide primitives,
|
||||
** with some post-adjustment
|
||||
*/
|
||||
R3 = R1 >> 1; /* Pre-scaled divisor for primitive case */
|
||||
R2 = R0 >> 16;
|
||||
|
||||
R2 = R3 - R2; /* shifted divisor < upper 16 bits of dividend */
|
||||
CC &= CARRY;
|
||||
IF CC JUMP .Lshift_and_correct;
|
||||
|
||||
/* Fall through to the identities */
|
||||
|
||||
/* METHOD 2: identities and manual calculation
|
||||
We are not able to use the divide primites, but may still catch some special
|
||||
cases.
|
||||
*/
|
||||
.Lidents:
|
||||
/* Test for common identities. Value to be returned is placed in R2. */
|
||||
CC = R0 == 0; /* 0/Y => 0 */
|
||||
IF CC JUMP .Lreturn_r0;
|
||||
CC = R0 == R1; /* X==Y => 1 */
|
||||
IF CC JUMP .Lreturn_ident;
|
||||
CC = R1 == 1; /* X/1 => X */
|
||||
IF CC JUMP .Lreturn_ident;
|
||||
|
||||
R2.L = ONES R1;
|
||||
R2 = R2.L (Z);
|
||||
CC = R2 == 1;
|
||||
IF CC JUMP .Lpower_of_two;
|
||||
|
||||
[--SP] = (R7:5); /* Push registers R5-R7 */
|
||||
|
||||
/* Idents don't match. Go for the full operation. */
|
||||
|
||||
|
||||
R6 = 2; /* assume we'll shift two */
|
||||
R3 = 1;
|
||||
|
||||
P2 = R1;
|
||||
/* If either R0 or R1 have sign set, */
|
||||
/* divide them by two, and note it's */
|
||||
/* been done. */
|
||||
CC = R1 < 0;
|
||||
R2 = R1 >> 1;
|
||||
IF CC R1 = R2; /* Possibly-shifted R1 */
|
||||
IF !CC R6 = R3; /* R1 doesn't, so at most 1 shifted */
|
||||
|
||||
P0 = 0;
|
||||
R3 = -R1;
|
||||
[--SP] = R3;
|
||||
R2 = R0 >> 1;
|
||||
R2 = R0 >> 1;
|
||||
CC = R0 < 0;
|
||||
IF CC P0 = R6; /* Number of values divided */
|
||||
IF !CC R2 = R0; /* Shifted R0 */
|
||||
|
||||
/* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
|
||||
|
||||
/* r2 holds Copy dividend */
|
||||
R3 = 0; /* Clear partial remainder */
|
||||
R7 = 0; /* Initialise quotient bit */
|
||||
|
||||
P1 = 32; /* Set loop counter */
|
||||
LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
|
||||
.Lulst: R6 = R2 >> 31; /* R6 = sign bit of R2, for carry */
|
||||
R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
|
||||
R3 = R3 << 1 || R5 = [SP];
|
||||
R3 = R3 | R6; /* Include any carry */
|
||||
CC = R7 < 0; /* Check quotient(AQ) */
|
||||
/* If AQ==0, we'll sub divisor */
|
||||
IF CC R5 = R1; /* and if AQ==1, we'll add it. */
|
||||
R3 = R3 + R5; /* Add/sub divsor to partial remainder */
|
||||
R7 = R3 ^ R1; /* Generate next quotient bit */
|
||||
|
||||
R5 = R7 >> 31; /* Get AQ */
|
||||
BITTGL(R5, 0); /* Invert it, to get what we'll shift */
|
||||
.Lulend: R2 = R2 + R5; /* and "shift" it in. */
|
||||
|
||||
CC = P0 == 0; /* Check how many inputs we shifted */
|
||||
IF CC JUMP .Lno_mult; /* if none... */
|
||||
R6 = R2 << 1;
|
||||
CC = P0 == 1;
|
||||
IF CC R2 = R6; /* if 1, Q = Q*2 */
|
||||
IF !CC R1 = P2; /* if 2, restore stored divisor */
|
||||
|
||||
R3 = R2; /* Copy of R2 */
|
||||
R3 *= R1; /* Q * divisor */
|
||||
R5 = R0 - R3; /* Z = (dividend - Q * divisor) */
|
||||
CC = R1 <= R5 (IU); /* Check if divisor <= Z? */
|
||||
R6 = CC; /* if yes, R6 = 1 */
|
||||
R2 = R2 + R6; /* if yes, add one to quotient(Q) */
|
||||
.Lno_mult:
|
||||
SP += 4;
|
||||
(R7:5) = [SP++]; /* Pop registers R5-R7 */
|
||||
R0 = R2; /* Store quotient */
|
||||
RTS;
|
||||
|
||||
.Lreturn_ident:
|
||||
CC = R0 < R1 (IU); /* If X < Y, always return 0 */
|
||||
R2 = 0;
|
||||
IF CC JUMP .Ltrue_return_ident;
|
||||
R2 = -1 (X); /* X/0 => 0xFFFFFFFF */
|
||||
CC = R1 == 0;
|
||||
IF CC JUMP .Ltrue_return_ident;
|
||||
R2 = -R2; /* R2 now 1 */
|
||||
CC = R0 == R1; /* X==Y => 1 */
|
||||
IF CC JUMP .Ltrue_return_ident;
|
||||
R2 = R0; /* X/1 => X */
|
||||
/*FALLTHRU*/
|
||||
|
||||
.Ltrue_return_ident:
|
||||
R0 = R2;
|
||||
.Lreturn_r0:
|
||||
RTS;
|
||||
|
||||
.Lpower_of_two:
|
||||
/* Y has a single bit set, which means it's a power of two.
|
||||
** That means we can perform the division just by shifting
|
||||
** X to the right the appropriate number of bits
|
||||
*/
|
||||
|
||||
/* signbits returns the number of sign bits, minus one.
|
||||
** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
|
||||
** to shift right n-signbits spaces. It also means 0x80000000
|
||||
** is a special case, because that *also* gives a signbits of 0
|
||||
*/
|
||||
|
||||
R2 = R0 >> 31;
|
||||
CC = R1 < 0;
|
||||
IF CC JUMP .Ltrue_return_ident;
|
||||
|
||||
R1.l = SIGNBITS R1;
|
||||
R1 = R1.L (Z);
|
||||
R1 += -30;
|
||||
R0 = LSHIFT R0 by R1.L;
|
||||
RTS;
|
||||
|
||||
/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
|
||||
Two scaling operations are required to use the divide primitives with a
|
||||
divisor > 0x7FFFF.
|
||||
Firstly (as in method 1) we need to shift the dividend 1 to the left for
|
||||
integer division.
|
||||
Secondly we need to shift both the divisor and dividend 1 to the right so
|
||||
both are in range for the primitives.
|
||||
The left/right shift of the dividend does nothing so we can skip it.
|
||||
*/
|
||||
.Lshift_and_correct:
|
||||
R2 = R0;
|
||||
// R3 is already R1 >> 1
|
||||
CC=!CC;
|
||||
AQ = CC; /* Clear AQ, got here with CC = 0 */
|
||||
DIVQ(R2, R3); // 1
|
||||
DIVQ(R2, R3); // 2
|
||||
DIVQ(R2, R3); // 3
|
||||
DIVQ(R2, R3); // 4
|
||||
DIVQ(R2, R3); // 5
|
||||
DIVQ(R2, R3); // 6
|
||||
DIVQ(R2, R3); // 7
|
||||
DIVQ(R2, R3); // 8
|
||||
DIVQ(R2, R3); // 9
|
||||
DIVQ(R2, R3); // 10
|
||||
DIVQ(R2, R3); // 11
|
||||
DIVQ(R2, R3); // 12
|
||||
DIVQ(R2, R3); // 13
|
||||
DIVQ(R2, R3); // 14
|
||||
DIVQ(R2, R3); // 15
|
||||
DIVQ(R2, R3); // 16
|
||||
|
||||
/* According to the Instruction Set Reference:
|
||||
To divide by a divisor > 0x7FFF,
|
||||
1. prescale and perform divide to obtain quotient (Q) (done above),
|
||||
2. multiply quotient by unscaled divisor (result M)
|
||||
3. subtract the product from the divident to get an error (E = X - M)
|
||||
4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
|
||||
*/
|
||||
R3 = R2.L (Z); /* Q = X' / Y' */
|
||||
R2 = R3; /* Preserve Q */
|
||||
R2 *= R1; /* M = Q * Y */
|
||||
R2 = R0 - R2; /* E = X - M */
|
||||
R0 = R3; /* Copy Q into result reg */
|
||||
|
||||
/* Correction: If result of the multiply is negative, we overflowed
|
||||
and need to correct the result by subtracting 1 from the result.*/
|
||||
R3 = 0xFFFF (Z);
|
||||
R2 = R2 >> 16; /* E >> 16 */
|
||||
CC = R2 == R3;
|
||||
R3 = 1 ;
|
||||
R1 = R0 - R3;
|
||||
IF CC R0 = R1;
|
||||
RTS;
|
66
arch/blackfin/lib/umodsi3.S
Normal file
66
arch/blackfin/lib/umodsi3.S
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* File: arch/blackfin/lib/umodsi3.S
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: libgcc1 routines for Blackfin 5xx
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.extern ___udivsi3;
|
||||
.globl ___umodsi3
|
||||
___umodsi3:
|
||||
|
||||
CC=R0==0;
|
||||
IF CC JUMP .LRETURN_R0; /* Return 0, if NR == 0 */
|
||||
CC= R1==0;
|
||||
IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 0 */
|
||||
CC=R0==R1;
|
||||
IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if NR == DR */
|
||||
CC = R1 == 1;
|
||||
IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 1 */
|
||||
CC = R0<R1 (IU);
|
||||
IF CC JUMP .LRETURN_R0; /* Return dividend (R0),IF NR<DR */
|
||||
|
||||
[--SP] = (R7:6); /* Push registers and */
|
||||
[--SP] = RETS; /* Return address */
|
||||
R7 = R0; /* Copy of R0 */
|
||||
R6 = R1;
|
||||
SP += -12; /* Should always provide this space */
|
||||
CALL ___udivsi3; /* Compute unsigned quotient using ___udiv32()*/
|
||||
SP += 12;
|
||||
R0 *= R6; /* Quotient * divisor */
|
||||
R0 = R7 - R0; /* Dividend - (quotient * divisor) */
|
||||
RETS = [SP++]; /* Pop return address */
|
||||
( R7:6) = [SP++]; /* And registers */
|
||||
RTS; /* Return remainder */
|
||||
.LRETURN_ZERO_VAL:
|
||||
R0 = 0;
|
||||
.LRETURN_R0:
|
||||
RTS;
|
23
arch/blackfin/lib/umulsi3_highpart.S
Normal file
23
arch/blackfin/lib/umulsi3_highpart.S
Normal file
|
@ -0,0 +1,23 @@
|
|||
.align 2
|
||||
.global ___umulsi3_highpart;
|
||||
.type ___umulsi3_highpart, STT_FUNC;
|
||||
|
||||
#ifdef CONFIG_ARITHMETIC_OPS_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
___umulsi3_highpart:
|
||||
R2 = R1.H * R0.H, R3 = R1.L * R0.H (FU);
|
||||
R0 = R1.L * R0.L, R1 = R1.H * R0.L (FU);
|
||||
R0 >>= 16;
|
||||
/* Unsigned multiplication has the nice property that we can
|
||||
ignore carry on this first addition. */
|
||||
R0 = R0 + R3;
|
||||
R0 = R0 + R1;
|
||||
cc = ac0;
|
||||
R1 = cc;
|
||||
R1 = PACK(R1.l,R0.h);
|
||||
R0 = R1 + R2;
|
||||
RTS;
|
92
arch/blackfin/mach-bf533/Kconfig
Normal file
92
arch/blackfin/mach-bf533/Kconfig
Normal file
|
@ -0,0 +1,92 @@
|
|||
if (BF533 || BF532 || BF531)
|
||||
|
||||
menu "BF533/2/1 Specific Configuration"
|
||||
|
||||
comment "Interrupt Priority Assignment"
|
||||
menu "Priority"
|
||||
|
||||
config UART_ERROR
|
||||
int "UART ERROR"
|
||||
default 7
|
||||
config SPORT0_ERROR
|
||||
int "SPORT0 ERROR"
|
||||
default 7
|
||||
config SPI_ERROR
|
||||
int "SPI ERROR"
|
||||
default 7
|
||||
config SPORT1_ERROR
|
||||
int "SPORT1 ERROR"
|
||||
default 7
|
||||
config PPI_ERROR
|
||||
int "PPI ERROR"
|
||||
default 7
|
||||
config DMA_ERROR
|
||||
int "DMA ERROR"
|
||||
default 7
|
||||
config PLLWAKE_ERROR
|
||||
int "PLL WAKEUP ERROR"
|
||||
default 7
|
||||
|
||||
config RTC_ERROR
|
||||
int "RTC ERROR"
|
||||
default 8
|
||||
config DMA0_PPI
|
||||
int "DMA0 PPI"
|
||||
default 8
|
||||
|
||||
config DMA1_SPORT0RX
|
||||
int "DMA1 (SPORT0 RX)"
|
||||
default 9
|
||||
config DMA2_SPORT0TX
|
||||
int "DMA2 (SPORT0 TX)"
|
||||
default 9
|
||||
config DMA3_SPORT1RX
|
||||
int "DMA3 (SPORT1 RX)"
|
||||
default 9
|
||||
config DMA4_SPORT1TX
|
||||
int "DMA4 (SPORT1 TX)"
|
||||
default 9
|
||||
config DMA5_SPI
|
||||
int "DMA5 (SPI)"
|
||||
default 10
|
||||
config DMA6_UARTRX
|
||||
int "DMA6 (UART0 RX)"
|
||||
default 10
|
||||
config DMA7_UARTTX
|
||||
int "DMA7 (UART0 TX)"
|
||||
default 10
|
||||
config TIMER0
|
||||
int "TIMER0"
|
||||
default 11
|
||||
config TIMER1
|
||||
int "TIMER1"
|
||||
default 11
|
||||
config TIMER2
|
||||
int "TIMER2"
|
||||
default 11
|
||||
config PFA
|
||||
int "PF Interrupt A"
|
||||
default 12
|
||||
config PFB
|
||||
int "PF Interrupt B"
|
||||
default 12
|
||||
config MEMDMA0
|
||||
int "MEMORY DMA0"
|
||||
default 13
|
||||
config MEMDMA1
|
||||
int "MEMORY DMA1"
|
||||
default 13
|
||||
config WDTIMER
|
||||
int "WATCH DOG TIMER"
|
||||
default 13
|
||||
|
||||
help
|
||||
Enter the priority numbers between 7-13 ONLY. Others are Reserved.
|
||||
This applies to all the above. It is not recommended to assign the
|
||||
highest priority number 7 to UART or any other device.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
9
arch/blackfin/mach-bf533/Makefile
Normal file
9
arch/blackfin/mach-bf533/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf533/Makefile
|
||||
#
|
||||
|
||||
extra-y := head.o
|
||||
|
||||
obj-y := ints-priority.o
|
||||
|
||||
obj-$(CONFIG_CPU_FREQ_BF533) += cpu.o
|
8
arch/blackfin/mach-bf533/boards/Makefile
Normal file
8
arch/blackfin/mach-bf533/boards/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf533/boards/Makefile
|
||||
#
|
||||
|
||||
obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
|
||||
obj-$(CONFIG_BFIN533_STAMP) += stamp.o
|
||||
obj-$(CONFIG_BFIN533_EZKIT) += ezkit.o
|
||||
obj-$(CONFIG_BFIN533_BLUETECHNIX_CM) += cm_bf533.o
|
267
arch/blackfin/mach-bf533/boards/cm_bf533.c
Normal file
267
arch/blackfin/mach-bf533/boards/cm_bf533.c
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/boards/cm_bf533.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au> Copright 2005
|
||||
*
|
||||
* Created: 2005
|
||||
* Description: Board description file
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/usb_isp1362.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "Bluetechnix CM BF533";
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 2, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.start = 0x20200300,
|
||||
.end = 0x20200300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF0,
|
||||
.end = IRQ_PF0,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
static struct platform_device bfin_sport0_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device bfin_sport1_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20308000,
|
||||
.end = 0x20308000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20308004,
|
||||
.end = 0x20308004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF4,
|
||||
.end = IRQ_PF4,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *cm_bf533_devices[] __initdata = {
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
&bfin_sport0_uart_device,
|
||||
&bfin_sport1_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cm_bf533_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(cm_bf533_init);
|
224
arch/blackfin/mach-bf533/boards/ezkit.c
Normal file
224
arch/blackfin/mach-bf533/boards/ezkit.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/ezkit.c
|
||||
* Based on: Orginal Work
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created: 2005
|
||||
* Description:
|
||||
*
|
||||
* Modified: Robin Getz <rgetz@blackfin.uclinux.org> - Named the boards
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/usb_isp1362.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "ADDS-BF533-EZKIT";
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* USB-LAN EzExtender board
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x20310300,
|
||||
.end = 0x20310300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF9,
|
||||
.end = IRQ_PF9,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *ezkit_devices[] __initdata = {
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ezkit_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(ezkit_init);
|
95
arch/blackfin/mach-bf533/boards/generic_board.c
Normal file
95
arch/blackfin/mach-bf533/boards/generic_board.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/generic_board.c
|
||||
* Based on: arch/blackfin/mach-bf533/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created: 2005
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "UNKNOWN BOARD";
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.start = 0x20300300,
|
||||
.end = 0x20300300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTB,
|
||||
.end = IRQ_PROG_INTB,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},{
|
||||
/*
|
||||
* denotes the flag pin and is used directly if
|
||||
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
|
||||
*/
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *generic_board_devices[] __initdata = {
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init generic_board_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
return platform_add_devices(generic_board_devices, ARRAY_SIZE(generic_board_devices));
|
||||
}
|
||||
|
||||
arch_initcall(generic_board_init);
|
321
arch/blackfin/mach-bf533/boards/stamp.c
Normal file
321
arch/blackfin/mach-bf533/boards/stamp.c
Normal file
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/stamp.c
|
||||
* Based on: arch/blackfin/mach-bf533/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created: 2005
|
||||
* Description: Board Info File for the BF533-STAMP
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
#include <linux/usb_isp1362.h>
|
||||
#endif
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "ADDS-BF533-STAMP";
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x20300300,
|
||||
.end = 0x20300300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
static struct resource net2272_bfin_resources[] = {
|
||||
{
|
||||
.start = 0x20300000,
|
||||
.end = 0x20300000 + 0x100,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF10,
|
||||
.end = IRQ_PF10,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device net2272_bfin_device = {
|
||||
.name = "net2272",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(net2272_bfin_resources),
|
||||
.resource = net2272_bfin_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PBX)
|
||||
static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
|
||||
.ctl_reg = 0x4, /* send zero */
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 8,
|
||||
.cs_change_per_word = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
|
||||
static struct bfin5xx_spi_chip ad5304_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 31250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PBX)
|
||||
{
|
||||
.modalias = "fxs-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 3,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "fxo-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 2,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
|
||||
{
|
||||
.modalias = "ad5304_spi",
|
||||
.max_speed_hz = 1000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 2,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &ad5304_chip_info,
|
||||
.mode = SPI_MODE_2,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
static struct platform_device bfin_fb_device = {
|
||||
.name = "bf537-fb",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
static struct platform_device bfin_sport0_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device bfin_sport1_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *stamp_devices[] __initdata = {
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
&net2272_bfin_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
&bfin_sport0_uart_device,
|
||||
&bfin_sport1_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init stamp_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(stamp_init);
|
161
arch/blackfin/mach-bf533/cpu.c
Normal file
161
arch/blackfin/mach-bf533/cpu.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/cpu.c
|
||||
* Based on:
|
||||
* Author: michael.kang@analog.com
|
||||
*
|
||||
* Created:
|
||||
* Description: clock scaling for the bf533
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/bfin-global.h>
|
||||
|
||||
/* CONFIG_CLKIN_HZ=11059200 */
|
||||
#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */
|
||||
#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */
|
||||
#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */
|
||||
#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */
|
||||
#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */
|
||||
#define VCO(x) VCO##x
|
||||
|
||||
#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
|
||||
/* frequency */
|
||||
static struct cpufreq_frequency_table bf533_freq_table[] = {
|
||||
FREQ(1),
|
||||
FREQ(3),
|
||||
{VCO4, VCO4 / 2}, {VCO4, VCO4},
|
||||
FREQ(5),
|
||||
{0, CPUFREQ_TABLE_END},
|
||||
};
|
||||
|
||||
/*
|
||||
* dpmc_fops->ioctl()
|
||||
* static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
*/
|
||||
static int bf533_getfreq(unsigned int cpu)
|
||||
{
|
||||
unsigned long cclk_mhz, vco_mhz;
|
||||
|
||||
/* The driver only support single cpu */
|
||||
if (cpu == 0)
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
|
||||
else
|
||||
cclk_mhz = -1;
|
||||
return cclk_mhz;
|
||||
}
|
||||
|
||||
static int bf533_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq, unsigned int relation)
|
||||
{
|
||||
unsigned long cclk_mhz;
|
||||
unsigned long vco_mhz;
|
||||
unsigned long flags;
|
||||
unsigned int index, vco_index;
|
||||
int i;
|
||||
|
||||
struct cpufreq_freqs freqs;
|
||||
if (cpufreq_frequency_table_target
|
||||
(policy, bf533_freq_table, target_freq, relation, &index))
|
||||
return -EINVAL;
|
||||
cclk_mhz = bf533_freq_table[index].frequency;
|
||||
vco_mhz = bf533_freq_table[index].index;
|
||||
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
|
||||
freqs.old = bf533_getfreq(0);
|
||||
freqs.new = cclk_mhz;
|
||||
freqs.cpu = 0;
|
||||
|
||||
pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
|
||||
cclk_mhz, vco_mhz, index, target_freq, freqs.old);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
local_irq_save(flags);
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
|
||||
local_irq_restore(flags);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
vco_mhz = get_vco();
|
||||
cclk_mhz = get_cclk();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
|
||||
* this platform, anyway.
|
||||
*/
|
||||
static int bf533_verify_speed(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_frequency_table_verify(policy, &bf533_freq_table);
|
||||
}
|
||||
|
||||
static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
return -EINVAL;
|
||||
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
/*Now ,only support one cpu */
|
||||
policy->cur = bf533_getfreq(0);
|
||||
cpufreq_frequency_table_get_attr(bf533_freq_table, policy->cpu);
|
||||
return cpufreq_frequency_table_cpuinfo(policy, bf533_freq_table);
|
||||
}
|
||||
|
||||
static struct freq_attr *bf533_freq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver bf533_driver = {
|
||||
.verify = bf533_verify_speed,
|
||||
.target = bf533_target,
|
||||
.get = bf533_getfreq,
|
||||
.init = __bf533_cpu_init,
|
||||
.name = "bf533",
|
||||
.owner = THIS_MODULE,
|
||||
.attr = bf533_freq_attr,
|
||||
};
|
||||
|
||||
static int __init bf533_cpu_init(void)
|
||||
{
|
||||
return cpufreq_register_driver(&bf533_driver);
|
||||
}
|
||||
|
||||
static void __exit bf533_cpu_exit(void)
|
||||
{
|
||||
cpufreq_unregister_driver(&bf533_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Mickael Kang");
|
||||
MODULE_DESCRIPTION("cpufreq driver for BF533 CPU");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(bf533_cpu_init);
|
||||
module_exit(bf533_cpu_exit);
|
774
arch/blackfin/mach-bf533/head.S
Normal file
774
arch/blackfin/mach-bf533/head.S
Normal file
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/head.S
|
||||
* Based on:
|
||||
* Author: Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
|
||||
*
|
||||
* Created: 1998
|
||||
* Description: bf533 startup file
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
#include <asm/mach/mem_init.h>
|
||||
#endif
|
||||
#if CONFIG_DEBUG_KERNEL_START
|
||||
#include <asm/mach-common/def_LPBlackfin.h>
|
||||
#endif
|
||||
|
||||
.global __rambase
|
||||
.global __ramstart
|
||||
.global __ramend
|
||||
.extern ___bss_stop
|
||||
.extern ___bss_start
|
||||
.extern _bf53x_relocate_l1_mem
|
||||
|
||||
#define INITIAL_STACK 0xFFB01000
|
||||
|
||||
.text
|
||||
|
||||
ENTRY(__start)
|
||||
ENTRY(__stext)
|
||||
/* R0: argument of command line string, passed from uboot, save it */
|
||||
R7 = R0;
|
||||
/* Set the SYSCFG register */
|
||||
R0 = 0x36;
|
||||
/*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
|
||||
SYSCFG = R0;
|
||||
R0 = 0;
|
||||
|
||||
/*Clear Out All the data and pointer Registers*/
|
||||
R1 = R0;
|
||||
R2 = R0;
|
||||
R3 = R0;
|
||||
R4 = R0;
|
||||
R5 = R0;
|
||||
R6 = R0;
|
||||
|
||||
P0 = R0;
|
||||
P1 = R0;
|
||||
P2 = R0;
|
||||
P3 = R0;
|
||||
P4 = R0;
|
||||
P5 = R0;
|
||||
|
||||
LC0 = r0;
|
||||
LC1 = r0;
|
||||
L0 = r0;
|
||||
L1 = r0;
|
||||
L2 = r0;
|
||||
L3 = r0;
|
||||
|
||||
/* Clear Out All the DAG Registers*/
|
||||
B0 = r0;
|
||||
B1 = r0;
|
||||
B2 = r0;
|
||||
B3 = r0;
|
||||
|
||||
I0 = r0;
|
||||
I1 = r0;
|
||||
I2 = r0;
|
||||
I3 = r0;
|
||||
|
||||
M0 = r0;
|
||||
M1 = r0;
|
||||
M2 = r0;
|
||||
M3 = r0;
|
||||
|
||||
#if CONFIG_DEBUG_KERNEL_START
|
||||
|
||||
/*
|
||||
* Set up a temporary Event Vector Table, so if something bad happens before
|
||||
* the kernel is fully started, it doesn't vector off into the bootloaders
|
||||
* table
|
||||
*/
|
||||
P0.l = lo(EVT2);
|
||||
P0.h = hi(EVT2);
|
||||
P1.l = lo(EVT15);
|
||||
P1.h = hi(EVT15);
|
||||
P2.l = debug_kernel_start_trap;
|
||||
P2.h = debug_kernel_start_trap;
|
||||
|
||||
RTS = P2;
|
||||
RTI = P2;
|
||||
RTX = P2;
|
||||
RTN = P2;
|
||||
RTE = P2;
|
||||
|
||||
.Lfill_temp_vector_table:
|
||||
[P0++] = P2; /* Core Event Vector Table */
|
||||
CC = P0 == P1;
|
||||
if !CC JUMP .Lfill_temp_vector_table
|
||||
P0 = r0;
|
||||
P1 = r0;
|
||||
P2 = r0;
|
||||
|
||||
#endif
|
||||
|
||||
p0.h = hi(FIO_MASKA_C);
|
||||
p0.l = lo(FIO_MASKA_C);
|
||||
r0 = 0xFFFF(Z);
|
||||
w[p0] = r0.L; /* Disable all interrupts */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(FIO_MASKB_C);
|
||||
p0.l = lo(FIO_MASKB_C);
|
||||
r0 = 0xFFFF(Z);
|
||||
w[p0] = r0.L; /* Disable all interrupts */
|
||||
ssync;
|
||||
|
||||
/* Turn off the icache */
|
||||
p0.l = (IMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (IMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENICPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Turn off the dcache */
|
||||
p0.l = (DMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (DMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENDCPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Initialise UART */
|
||||
p0.h = hi(UART_LCR);
|
||||
p0.l = lo(UART_LCR);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable DLL writes */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLL);
|
||||
p0.l = lo(UART_DLL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLH);
|
||||
p0.l = lo(UART_DLH);
|
||||
r0 = 0x00(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable UART clock */
|
||||
ssync;
|
||||
|
||||
/* Initialize stack pointer */
|
||||
sp.l = lo(INITIAL_STACK);
|
||||
sp.h = hi(INITIAL_STACK);
|
||||
fp = sp;
|
||||
usp = sp;
|
||||
|
||||
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
|
||||
call _bf53x_relocate_l1_mem;
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
call _start_dma_code;
|
||||
#endif
|
||||
|
||||
/* Code for initializing Async memory banks */
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL1);
|
||||
p2.l = lo(EBIU_AMBCTL1);
|
||||
r0.h = hi(AMBCTL1VAL);
|
||||
r0.l = lo(AMBCTL1VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL0);
|
||||
p2.l = lo(EBIU_AMBCTL0);
|
||||
r0.h = hi(AMBCTL0VAL);
|
||||
r0.l = lo(AMBCTL0VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMGCTL);
|
||||
p2.l = lo(EBIU_AMGCTL);
|
||||
r0 = AMGCTLVAL;
|
||||
w[p2] = r0;
|
||||
ssync;
|
||||
|
||||
/* This section keeps the processor in supervisor mode
|
||||
* during kernel boot. Switches to user mode at end of boot.
|
||||
* See page 3-9 of Hardware Reference manual for documentation.
|
||||
*/
|
||||
|
||||
/* EVT15 = _real_start */
|
||||
|
||||
p0.l = lo(EVT15);
|
||||
p0.h = hi(EVT15);
|
||||
p1.l = _real_start;
|
||||
p1.h = _real_start;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
p0.l = lo(IMASK);
|
||||
p0.h = hi(IMASK);
|
||||
p1.l = IMASK_IVG15;
|
||||
p1.h = 0x0;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
raise 15;
|
||||
p0.l = .LWAIT_HERE;
|
||||
p0.h = .LWAIT_HERE;
|
||||
reti = p0;
|
||||
#if defined(ANOMALY_05000281)
|
||||
nop; nop; nop;
|
||||
#endif
|
||||
rti;
|
||||
|
||||
.LWAIT_HERE:
|
||||
jump .LWAIT_HERE;
|
||||
|
||||
ENTRY(_real_start)
|
||||
[ -- sp ] = reti;
|
||||
p0.l = lo(WDOG_CTL);
|
||||
p0.h = hi(WDOG_CTL);
|
||||
r0 = 0xAD6(z);
|
||||
w[p0] = r0; /* watchdog off for now */
|
||||
ssync;
|
||||
|
||||
/* Code update for BSS size == 0
|
||||
* Zero out the bss region.
|
||||
*/
|
||||
|
||||
p1.l = ___bss_start;
|
||||
p1.h = ___bss_start;
|
||||
p2.l = ___bss_stop;
|
||||
p2.h = ___bss_stop;
|
||||
r0 = 0;
|
||||
p2 -= p1;
|
||||
lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
|
||||
.L_clear_bss:
|
||||
B[p1++] = r0;
|
||||
|
||||
/* In case there is a NULL pointer reference
|
||||
* Zero out region before stext
|
||||
*/
|
||||
|
||||
p1.l = 0x0;
|
||||
p1.h = 0x0;
|
||||
r0.l = __stext;
|
||||
r0.h = __stext;
|
||||
r0 = r0 >> 1;
|
||||
p2 = r0;
|
||||
r0 = 0;
|
||||
lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
|
||||
.L_clear_zero:
|
||||
W[p1++] = r0;
|
||||
|
||||
/* pass the uboot arguments to the global value command line */
|
||||
R0 = R7;
|
||||
call _cmdline_init;
|
||||
|
||||
p1.l = __rambase;
|
||||
p1.h = __rambase;
|
||||
r0.l = __sdata;
|
||||
r0.h = __sdata;
|
||||
[p1] = r0;
|
||||
|
||||
p1.l = __ramstart;
|
||||
p1.h = __ramstart;
|
||||
p3.l = ___bss_stop;
|
||||
p3.h = ___bss_stop;
|
||||
|
||||
r1 = p3;
|
||||
[p1] = r1;
|
||||
|
||||
/*
|
||||
* load the current thread pointer and stack
|
||||
*/
|
||||
r1.l = _init_thread_union;
|
||||
r1.h = _init_thread_union;
|
||||
|
||||
r2.l = 0x2000;
|
||||
r2.h = 0x0000;
|
||||
r1 = r1 + r2;
|
||||
sp = r1;
|
||||
usp = sp;
|
||||
fp = sp;
|
||||
call _start_kernel;
|
||||
.L_exit:
|
||||
jump.s .L_exit;
|
||||
|
||||
.section .l1.text
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
ENTRY(_start_dma_code)
|
||||
p0.h = hi(SIC_IWR);
|
||||
p0.l = lo(SIC_IWR);
|
||||
r0.l = 0x1;
|
||||
r0.h = 0x0;
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/*
|
||||
* Set PLL_CTL
|
||||
* - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
|
||||
* - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
|
||||
* - [7] = output delay (add 200ps of delay to mem signals)
|
||||
* - [6] = input delay (add 200ps of input delay to mem signals)
|
||||
* - [5] = PDWN : 1=All Clocks off
|
||||
* - [3] = STOPCK : 1=Core Clock off
|
||||
* - [1] = PLL_OFF : 1=Disable Power to PLL
|
||||
* - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
|
||||
* all other bits set to zero
|
||||
*/
|
||||
|
||||
p0.h = hi(PLL_LOCKCNT);
|
||||
p0.l = lo(PLL_LOCKCNT);
|
||||
r0 = 0x300(Z);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITSET (R0, 24);
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
|
||||
r0 = r0 << 9; /* Shift it over, */
|
||||
r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
|
||||
r0 = r1 | r0;
|
||||
r1 = PLL_BYPASS; /* Bypass the PLL? */
|
||||
r1 = r1 << 8; /* Shift it over */
|
||||
r0 = r1 | r0; /* add them all together */
|
||||
|
||||
p0.h = hi(PLL_CTL);
|
||||
p0.l = lo(PLL_CTL); /* Load the address */
|
||||
cli r2; /* Disable interrupts */
|
||||
ssync;
|
||||
w[p0] = r0.l; /* Set the value */
|
||||
idle; /* Wait for the PLL to stablize */
|
||||
sti r2; /* Enable interrupts */
|
||||
|
||||
.Lcheck_again:
|
||||
p0.h = hi(PLL_STAT);
|
||||
p0.l = lo(PLL_STAT);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,5);
|
||||
if ! CC jump .Lcheck_again;
|
||||
|
||||
/* Configure SCLK & CCLK Dividers */
|
||||
r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
|
||||
p0.h = hi(PLL_DIV);
|
||||
p0.l = lo(PLL_DIV);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = lo(EBIU_SDRRC);
|
||||
p0.h = hi(EBIU_SDRRC);
|
||||
r0 = mem_SDRRC;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = (EBIU_SDBCTL & 0xFFFF);
|
||||
p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
|
||||
r0 = mem_SDBCTL;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITCLR (R0, 24);
|
||||
p0.h = hi(EBIU_SDSTAT);
|
||||
p0.l = lo(EBIU_SDSTAT);
|
||||
r2.l = w[p0];
|
||||
cc = bittst(r2,3);
|
||||
if !cc jump .Lskip;
|
||||
NOP;
|
||||
BITSET (R0, 23);
|
||||
.Lskip:
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
R0.L = lo(mem_SDGCTL);
|
||||
R0.H = hi(mem_SDGCTL);
|
||||
R1 = [p2];
|
||||
R1 = R1 | R0;
|
||||
[P2] = R1;
|
||||
SSYNC;
|
||||
|
||||
p0.h = hi(SIC_IWR);
|
||||
p0.l = lo(SIC_IWR);
|
||||
r0.l = lo(IWR_ENABLE_ALL)
|
||||
r0.h = hi(IWR_ENABLE_ALL)
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
RTS;
|
||||
#endif /* CONFIG_BFIN_KERNEL_CLOCK */
|
||||
|
||||
ENTRY(_bfin_reset)
|
||||
/* No more interrupts to be handled*/
|
||||
CLI R6;
|
||||
SSYNC;
|
||||
|
||||
#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
|
||||
p0.h = hi(FIO_INEN);
|
||||
p0.l = lo(FIO_INEN);
|
||||
r0.l = ~(1 << CONFIG_ENET_FLASH_PIN);
|
||||
w[p0] = r0.l;
|
||||
|
||||
p0.h = hi(FIO_DIR);
|
||||
p0.l = lo(FIO_DIR);
|
||||
r0.l = (1 << CONFIG_ENET_FLASH_PIN);
|
||||
w[p0] = r0.l;
|
||||
|
||||
p0.h = hi(FIO_FLAG_C);
|
||||
p0.l = lo(FIO_FLAG_C);
|
||||
r0.l = (1 << CONFIG_ENET_FLASH_PIN);
|
||||
w[p0] = r0.l;
|
||||
#endif
|
||||
|
||||
/* Clear the bits 13-15 in SWRST if they werent cleared */
|
||||
p0.h = hi(SWRST);
|
||||
p0.l = lo(SWRST);
|
||||
csync;
|
||||
r0.l = w[p0];
|
||||
|
||||
/* Clear the IMASK register */
|
||||
p0.h = hi(IMASK);
|
||||
p0.l = lo(IMASK);
|
||||
r0 = 0x0;
|
||||
[p0] = r0;
|
||||
|
||||
/* Clear the ILAT register */
|
||||
p0.h = hi(ILAT);
|
||||
p0.l = lo(ILAT);
|
||||
r0 = [p0];
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/* Disable the WDOG TIMER */
|
||||
p0.h = hi(WDOG_CTL);
|
||||
p0.l = lo(WDOG_CTL);
|
||||
r0.l = 0xAD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Clear the sticky bit incase it is already set */
|
||||
p0.h = hi(WDOG_CTL);
|
||||
p0.l = lo(WDOG_CTL);
|
||||
r0.l = 0x8AD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Program the count value */
|
||||
R0.l = 0x100;
|
||||
R0.h = 0x0;
|
||||
P0.h = hi(WDOG_CNT);
|
||||
P0.l = lo(WDOG_CNT);
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
/* Program WDOG_STAT if necessary */
|
||||
P0.h = hi(WDOG_CTL);
|
||||
P0.l = lo(WDOG_CTL);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,1);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
CC = BITTST(R0,2);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
JUMP .LSKIP_WRITE;
|
||||
|
||||
.LWRITESTAT:
|
||||
/* When watch dog timer is enabled, a write to STAT will load the contents of CNT to STAT */
|
||||
R0 = 0x0000(z);
|
||||
P0.h = hi(WDOG_STAT);
|
||||
P0.l = lo(WDOG_STAT)
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
.LSKIP_WRITE:
|
||||
/* Enable the reset event */
|
||||
P0.h = hi(WDOG_CTL);
|
||||
P0.l = lo(WDOG_CTL);
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,1);
|
||||
BITCLR(R0,2);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
NOP;
|
||||
|
||||
/* Enable the wdog counter */
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,4);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
IDLE;
|
||||
|
||||
RTS;
|
||||
|
||||
#if CONFIG_DEBUG_KERNEL_START
|
||||
debug_kernel_start_trap:
|
||||
/* Set up a temp stack in L1 - SDRAM might not be working */
|
||||
P0.L = lo(L1_DATA_A_START + 0x100);
|
||||
P0.H = hi(L1_DATA_A_START + 0x100);
|
||||
SP = P0;
|
||||
|
||||
/* Make sure the Clocks are the way I think they should be */
|
||||
r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
|
||||
r0 = r0 << 9; /* Shift it over, */
|
||||
r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
|
||||
r0 = r1 | r0;
|
||||
r1 = PLL_BYPASS; /* Bypass the PLL? */
|
||||
r1 = r1 << 8; /* Shift it over */
|
||||
r0 = r1 | r0; /* add them all together */
|
||||
|
||||
p0.h = hi(PLL_CTL);
|
||||
p0.l = lo(PLL_CTL); /* Load the address */
|
||||
cli r2; /* Disable interrupts */
|
||||
ssync;
|
||||
w[p0] = r0.l; /* Set the value */
|
||||
idle; /* Wait for the PLL to stablize */
|
||||
sti r2; /* Enable interrupts */
|
||||
|
||||
.Lcheck_again1:
|
||||
p0.h = hi(PLL_STAT);
|
||||
p0.l = lo(PLL_STAT);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,5);
|
||||
if ! CC jump .Lcheck_again1;
|
||||
|
||||
/* Configure SCLK & CCLK Dividers */
|
||||
r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
|
||||
p0.h = hi(PLL_DIV);
|
||||
p0.l = lo(PLL_DIV);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
/* Make sure UART is enabled - you can never be sure */
|
||||
|
||||
/*
|
||||
* Setup for console. Argument comes from the menuconfig
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BAUD_9600
|
||||
#define CONSOLE_BAUD_RATE 9600
|
||||
#elif CONFIG_BAUD_19200
|
||||
#define CONSOLE_BAUD_RATE 19200
|
||||
#elif CONFIG_BAUD_38400
|
||||
#define CONSOLE_BAUD_RATE 38400
|
||||
#elif CONFIG_BAUD_57600
|
||||
#define CONSOLE_BAUD_RATE 57600
|
||||
#elif CONFIG_BAUD_115200
|
||||
#define CONSOLE_BAUD_RATE 115200
|
||||
#endif
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x00(Z);
|
||||
w[p0] = r0.L; /* To Turn off UART clocks */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_LCR);
|
||||
p0.l = lo(UART_LCR);
|
||||
r0 = 0x83(Z);
|
||||
w[p0] = r0.L; /* To enable DLL writes */
|
||||
ssync;
|
||||
|
||||
R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16));
|
||||
|
||||
p0.h = hi(UART_DLL);
|
||||
p0.l = lo(UART_DLL);
|
||||
r0 = 0xFF(Z);
|
||||
r0 = R1 & R0;
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLH);
|
||||
p0.l = lo(UART_DLH);
|
||||
r1 >>= 8 ;
|
||||
w[p0] = r1.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable UART clock */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_LCR);
|
||||
p0.l = lo(UART_LCR);
|
||||
r0 = 0x03(Z);
|
||||
w[p0] = r0.L; /* To Turn on UART */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x01(Z);
|
||||
w[p0] = r0.L; /* To Turn on UART Clocks */
|
||||
ssync;
|
||||
|
||||
P0.h = hi(UART_THR);
|
||||
P0.l = lo(UART_THR);
|
||||
P1.h = hi(UART_LSR);
|
||||
P1.l = lo(UART_LSR);
|
||||
|
||||
R0.L = 'K';
|
||||
call .Lwait_char;
|
||||
R0.L='e';
|
||||
call .Lwait_char;
|
||||
R0.L='r';
|
||||
call .Lwait_char;
|
||||
R0.L='n'
|
||||
call .Lwait_char;
|
||||
R0.L='e'
|
||||
call .Lwait_char;
|
||||
R0.L='l';
|
||||
call .Lwait_char;
|
||||
R0.L=' ';
|
||||
call .Lwait_char;
|
||||
R0.L='c';
|
||||
call .Lwait_char;
|
||||
R0.L='r';
|
||||
call .Lwait_char;
|
||||
R0.L='a';
|
||||
call .Lwait_char;
|
||||
R0.L='s';
|
||||
call .Lwait_char;
|
||||
R0.L='h';
|
||||
call .Lwait_char;
|
||||
R0.L='\r';
|
||||
call .Lwait_char;
|
||||
R0.L='\n';
|
||||
call .Lwait_char;
|
||||
|
||||
R0.L='S';
|
||||
call .Lwait_char;
|
||||
R0.L='E';
|
||||
call .Lwait_char;
|
||||
R0.L='Q'
|
||||
call .Lwait_char;
|
||||
R0.L='S'
|
||||
call .Lwait_char;
|
||||
R0.L='T';
|
||||
call .Lwait_char;
|
||||
R0.L='A';
|
||||
call .Lwait_char;
|
||||
R0.L='T';
|
||||
call .Lwait_char;
|
||||
R0.L='=';
|
||||
call .Lwait_char;
|
||||
R2 = SEQSTAT;
|
||||
call .Ldump_reg;
|
||||
|
||||
R0.L=' ';
|
||||
call .Lwait_char;
|
||||
R0.L='R';
|
||||
call .Lwait_char;
|
||||
R0.L='E'
|
||||
call .Lwait_char;
|
||||
R0.L='T'
|
||||
call .Lwait_char;
|
||||
R0.L='X';
|
||||
call .Lwait_char;
|
||||
R0.L='=';
|
||||
call .Lwait_char;
|
||||
R2 = RETX;
|
||||
call .Ldump_reg;
|
||||
|
||||
R0.L='\r';
|
||||
call .Lwait_char;
|
||||
R0.L='\n';
|
||||
call .Lwait_char;
|
||||
|
||||
.Ldebug_kernel_start_trap_done:
|
||||
JUMP .Ldebug_kernel_start_trap_done;
|
||||
.Ldump_reg:
|
||||
R3 = 32;
|
||||
R4 = 0x0F;
|
||||
R5 = ':'; /* one past 9 */
|
||||
|
||||
.Ldump_reg2:
|
||||
R0 = R2;
|
||||
R3 += -4;
|
||||
R0 >>>= R3;
|
||||
R0 = R0 & R4;
|
||||
R0 += 0x30;
|
||||
CC = R0 <= R5;
|
||||
if CC JUMP .Ldump_reg1;
|
||||
R0 += 7;
|
||||
|
||||
.Ldump_reg1:
|
||||
R1.l = W[P1];
|
||||
CC = BITTST(R1, 5);
|
||||
if !CC JUMP .Ldump_reg1;
|
||||
W[P0] = r0;
|
||||
|
||||
CC = R3 == 0;
|
||||
if !CC JUMP .Ldump_reg2
|
||||
RTS;
|
||||
|
||||
.Lwait_char:
|
||||
R1.l = W[P1];
|
||||
CC = BITTST(R1, 5);
|
||||
if !CC JUMP .Lwait_char;
|
||||
W[P0] = r0;
|
||||
RTS;
|
||||
|
||||
#endif /* CONFIG_DEBUG_KERNEL_START */
|
||||
|
||||
.data
|
||||
|
||||
/*
|
||||
* Set up the usable of RAM stuff. Size of RAM is determined then
|
||||
* an initial stack set up at the end.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
__rambase:
|
||||
.long 0
|
||||
__ramstart:
|
||||
.long 0
|
||||
__ramend:
|
||||
.long 0
|
65
arch/blackfin/mach-bf533/ints-priority.c
Normal file
65
arch/blackfin/mach-bf533/ints-priority.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/ints-priority.c
|
||||
* Based on:
|
||||
* Author: Michael Hennerich
|
||||
*
|
||||
* Created: ?
|
||||
* Description: Set up the interupt priorities
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
void program_IAR(void)
|
||||
{
|
||||
/* Program the IAR0 Register with the configured priority */
|
||||
bfin_write_SIC_IAR0(((CONFIG_PLLWAKE_ERROR - 7) << PLLWAKE_ERROR_POS) |
|
||||
((CONFIG_DMA_ERROR - 7) << DMA_ERROR_POS) |
|
||||
((CONFIG_PPI_ERROR - 7) << PPI_ERROR_POS) |
|
||||
((CONFIG_SPORT0_ERROR - 7) << SPORT0_ERROR_POS) |
|
||||
((CONFIG_SPI_ERROR - 7) << SPI_ERROR_POS) |
|
||||
((CONFIG_SPORT1_ERROR - 7) << SPORT1_ERROR_POS) |
|
||||
((CONFIG_UART_ERROR - 7) << UART_ERROR_POS) |
|
||||
((CONFIG_RTC_ERROR - 7) << RTC_ERROR_POS));
|
||||
|
||||
bfin_write_SIC_IAR1(((CONFIG_DMA0_PPI - 7) << DMA0_PPI_POS) |
|
||||
((CONFIG_DMA1_SPORT0RX - 7) << DMA1_SPORT0RX_POS) |
|
||||
((CONFIG_DMA2_SPORT0TX - 7) << DMA2_SPORT0TX_POS) |
|
||||
((CONFIG_DMA3_SPORT1RX - 7) << DMA3_SPORT1RX_POS) |
|
||||
((CONFIG_DMA4_SPORT1TX - 7) << DMA4_SPORT1TX_POS) |
|
||||
((CONFIG_DMA5_SPI - 7) << DMA5_SPI_POS) |
|
||||
((CONFIG_DMA6_UARTRX - 7) << DMA6_UARTRX_POS) |
|
||||
((CONFIG_DMA7_UARTTX - 7) << DMA7_UARTTX_POS));
|
||||
|
||||
bfin_write_SIC_IAR2(((CONFIG_TIMER0 - 7) << TIMER0_POS) |
|
||||
((CONFIG_TIMER1 - 7) << TIMER1_POS) |
|
||||
((CONFIG_TIMER2 - 7) << TIMER2_POS) |
|
||||
((CONFIG_PFA - 7) << PFA_POS) |
|
||||
((CONFIG_PFB - 7) << PFB_POS) |
|
||||
((CONFIG_MEMDMA0 - 7) << MEMDMA0_POS) |
|
||||
((CONFIG_MEMDMA1 - 7) << MEMDMA1_POS) |
|
||||
((CONFIG_WDTIMER - 7) << WDTIMER_POS));
|
||||
|
||||
SSYNC();
|
||||
}
|
141
arch/blackfin/mach-bf537/Kconfig
Normal file
141
arch/blackfin/mach-bf537/Kconfig
Normal file
|
@ -0,0 +1,141 @@
|
|||
if (BF537 || BF534 || BF536)
|
||||
|
||||
menu "BF537 Specific Configuration"
|
||||
|
||||
comment "PORT F/G Selection"
|
||||
choice
|
||||
prompt "Select BF537/6/4 default GPIO PFx PORTx"
|
||||
help
|
||||
Quick Hack for BF537/6/4 default GPIO PFx PORTF.
|
||||
|
||||
config BF537_PORT_F
|
||||
bool "Select BF537/6/4 default GPIO PFx PORTF"
|
||||
depends on (BF537 || BF536 || BF534)
|
||||
help
|
||||
Quick Hack for BF537/6/4 default GPIO PFx PORTF.
|
||||
|
||||
config BF537_PORT_G
|
||||
bool "Select BF537/6/4 default GPIO PFx PORTG"
|
||||
depends on (BF537 || BF536 || BF534)
|
||||
help
|
||||
Quick Hack for BF537/6/4 default GPIO PFx PORTG.
|
||||
|
||||
config BF537_PORT_H
|
||||
bool "Select BF537/6/4 default GPIO PFx PORTH"
|
||||
depends on (BF537 || BF536 || BF534)
|
||||
help
|
||||
Quick Hack for BF537/6/4 default GPIO PFx PORTH
|
||||
Use only when Blackfin EMAC support is not required.
|
||||
|
||||
endchoice
|
||||
|
||||
comment "Interrupt Priority Assignment"
|
||||
menu "Priority"
|
||||
|
||||
config IRQ_PLL_WAKEUP
|
||||
int "IRQ_PLL_WAKEUP"
|
||||
default 7
|
||||
config IRQ_DMA_ERROR
|
||||
int "IRQ_DMA_ERROR Generic"
|
||||
default 7
|
||||
config IRQ_ERROR
|
||||
int "IRQ_ERROR: CAN MAC SPORT0 SPORT1 SPI UART0 UART1"
|
||||
default 7
|
||||
config IRQ_RTC
|
||||
int "IRQ_RTC"
|
||||
default 8
|
||||
config IRQ_PPI
|
||||
int "IRQ_PPI"
|
||||
default 8
|
||||
config IRQ_SPORT0_RX
|
||||
int "IRQ_SPORT0_RX"
|
||||
default 9
|
||||
config IRQ_SPORT0_TX
|
||||
int "IRQ_SPORT0_TX"
|
||||
default 9
|
||||
config IRQ_SPORT1_RX
|
||||
int "IRQ_SPORT1_RX"
|
||||
default 9
|
||||
config IRQ_SPORT1_TX
|
||||
int "IRQ_SPORT1_TX"
|
||||
default 9
|
||||
config IRQ_TWI
|
||||
int "IRQ_TWI"
|
||||
default 10
|
||||
config IRQ_SPI
|
||||
int "IRQ_SPI"
|
||||
default 10
|
||||
config IRQ_UART0_RX
|
||||
int "IRQ_UART0_RX"
|
||||
default 10
|
||||
config IRQ_UART0_TX
|
||||
int "IRQ_UART0_TX"
|
||||
default 10
|
||||
config IRQ_UART1_RX
|
||||
int "IRQ_UART1_RX"
|
||||
default 10
|
||||
config IRQ_UART1_TX
|
||||
int "IRQ_UART1_TX"
|
||||
default 10
|
||||
config IRQ_CAN_RX
|
||||
int "IRQ_CAN_RX"
|
||||
default 11
|
||||
config IRQ_CAN_TX
|
||||
int "IRQ_CAN_TX"
|
||||
default 11
|
||||
config IRQ_MAC_RX
|
||||
int "IRQ_MAC_RX"
|
||||
default 11
|
||||
config IRQ_MAC_TX
|
||||
int "IRQ_MAC_TX"
|
||||
default 11
|
||||
config IRQ_TMR0
|
||||
int "IRQ_TMR0"
|
||||
default 12
|
||||
config IRQ_TMR1
|
||||
int "IRQ_TMR1"
|
||||
default 12
|
||||
config IRQ_TMR2
|
||||
int "IRQ_TMR2"
|
||||
default 12
|
||||
config IRQ_TMR3
|
||||
int "IRQ_TMR3"
|
||||
default 12
|
||||
config IRQ_TMR4
|
||||
int "IRQ_TMR4"
|
||||
default 12
|
||||
config IRQ_TMR5
|
||||
int "IRQ_TMR5"
|
||||
default 12
|
||||
config IRQ_TMR6
|
||||
int "IRQ_TMR6"
|
||||
default 12
|
||||
config IRQ_TMR7
|
||||
int "IRQ_TMR7"
|
||||
default 12
|
||||
config IRQ_PROG_INTA
|
||||
int "IRQ_PROG_INTA"
|
||||
default 12
|
||||
config IRQ_PORTG_INTB
|
||||
int "IRQ_PORTG_INTB"
|
||||
default 12
|
||||
config IRQ_MEM_DMA0
|
||||
int "IRQ_MEM_DMA0"
|
||||
default 13
|
||||
config IRQ_MEM_DMA1
|
||||
int "IRQ_MEM_DMA1"
|
||||
default 13
|
||||
config IRQ_WATCH
|
||||
int "IRQ_WATCH"
|
||||
default 13
|
||||
|
||||
help
|
||||
Enter the priority numbers between 7-13 ONLY. Others are Reserved.
|
||||
This applies to all the above. It is not recommended to assign the
|
||||
highest priority number 7 to UART or any other device.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
9
arch/blackfin/mach-bf537/Makefile
Normal file
9
arch/blackfin/mach-bf537/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf537/Makefile
|
||||
#
|
||||
|
||||
extra-y := head.o
|
||||
|
||||
obj-y := ints-priority.o
|
||||
|
||||
obj-$(CONFIG_CPU_FREQ) += cpu.o
|
9
arch/blackfin/mach-bf537/boards/Makefile
Normal file
9
arch/blackfin/mach-bf537/boards/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf537/boards/Makefile
|
||||
#
|
||||
|
||||
obj-y += eth_mac.o
|
||||
obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
|
||||
obj-$(CONFIG_BFIN537_STAMP) += stamp.o led.o
|
||||
obj-$(CONFIG_BFIN537_BLUETECHNIX_CM) += cm_bf537.o
|
||||
obj-$(CONFIG_PNAV10) += pnav10.o
|
364
arch/blackfin/mach-bf537/boards/cm_bf537.c
Normal file
364
arch/blackfin/mach-bf537/boards/cm_bf537.c
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/boards/cm_bf537.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created: 2005
|
||||
* Description: Board description file
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/usb_isp1362.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "Bluetechnix CM BF537";
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_mmc_chip_info = {
|
||||
.enable_dma = 1,
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
{
|
||||
.modalias = "ad9960-spi",
|
||||
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &ad9960_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
{
|
||||
.modalias = "spi_mmc_dummy",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 7,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "spi_mmc",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SPI_MMC_CS_CHAN,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.start = 0x20200300,
|
||||
.end = 0x20200300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF14,
|
||||
.end = IRQ_PF14,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20308000,
|
||||
.end = 0x20308000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20308004,
|
||||
.end = 0x20308004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PG15,
|
||||
.end = IRQ_PG15,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
static struct resource net2272_bfin_resources[] = {
|
||||
{
|
||||
.start = 0x20200000,
|
||||
.end = 0x20200000 + 0x100,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device net2272_bfin_device = {
|
||||
.name = "net2272",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(net2272_bfin_resources),
|
||||
.resource = net2272_bfin_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0xFFC02000,
|
||||
.end = 0xFFC020FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
static struct platform_device bfin_sport0_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device bfin_sport1_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
static struct platform_device bfin_mac_device = {
|
||||
.name = "bfin_mac",
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *cm_bf537_devices[] __initdata = {
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
&bfin_sport0_uart_device,
|
||||
&bfin_sport1_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
&bfin_mac_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
&net2272_bfin_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init cm_bf537_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(cm_bf537_init);
|
51
arch/blackfin/mach-bf537/boards/eth_mac.c
Normal file
51
arch/blackfin/mach-bf537/boards/eth_mac.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* arch/blackfin/mach-bf537/board/eth_mac.c
|
||||
*
|
||||
* Copyright (C) 2007 Analog Devices, Inc.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
#if defined(CONFIG_GENERIC_BOARD) \
|
||||
|| defined(CONFIG_BFIN537_STAMP)
|
||||
|
||||
/*
|
||||
* Currently the MAC address is saved in Flash by U-Boot
|
||||
*/
|
||||
#define FLASH_MAC 0x203f0000
|
||||
|
||||
void get_bf537_ether_addr(char *addr)
|
||||
{
|
||||
unsigned int flash_mac = (unsigned int) FLASH_MAC;
|
||||
*(u32 *)(&(addr[0])) = bfin_read32(flash_mac);
|
||||
flash_mac += 4;
|
||||
*(u16 *)(&(addr[4])) = bfin_read16(flash_mac);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Provide MAC address function for other specific board setting
|
||||
*/
|
||||
void get_bf537_ether_addr(char *addr)
|
||||
{
|
||||
printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n",__FILE__);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL(get_bf537_ether_addr);
|
445
arch/blackfin/mach-bf537/boards/generic_board.c
Normal file
445
arch/blackfin/mach-bf537/boards/generic_board.c
Normal file
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/boards/generic_board.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/usb_isp1362.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <linux/usb_sl811.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "UNKNOWN BOARD";
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
static struct resource bfin_pcmcia_cf_resources[] = {
|
||||
{
|
||||
.start = 0x20310000, /* IO PORT */
|
||||
.end = 0x20312000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20311000, /* Attribute Memeory */
|
||||
.end = 0x20311FFF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTA,
|
||||
.end = IRQ_PROG_INTA,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
|
||||
},{
|
||||
.start = IRQ_PF4,
|
||||
.end = IRQ_PF4,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
|
||||
},{
|
||||
.start = 6, /* Card Detect PF6 */
|
||||
.end = 6,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_pcmcia_cf_device = {
|
||||
.name = "bfin_cf_pcmcia",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
|
||||
.resource = bfin_pcmcia_cf_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x20300300,
|
||||
.end = 0x20300300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTB,
|
||||
.end = IRQ_PROG_INTB,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},{
|
||||
/*
|
||||
* denotes the flag pin and is used directly if
|
||||
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
|
||||
*/
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
static struct resource sl811_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20340000,
|
||||
.end = 0x20340000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20340004,
|
||||
.end = 0x20340004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTA,
|
||||
.end = IRQ_PROG_INTA,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},{
|
||||
.start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
|
||||
.end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
void sl811_port_power(struct device *dev, int is_on)
|
||||
{
|
||||
unsigned short mask = (1<<CONFIG_USB_SL811_BFIN_GPIO_VBUS);
|
||||
|
||||
bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
|
||||
bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
|
||||
|
||||
if (is_on)
|
||||
bfin_write_FIO_FLAG_S(mask);
|
||||
else
|
||||
bfin_write_FIO_FLAG_C(mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct sl811_platform_data sl811_priv = {
|
||||
.potpg = 10,
|
||||
.power = 250, /* == 500mA */
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
.port_power = &sl811_port_power,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_device sl811_hcd_device = {
|
||||
.name = "sl811-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &sl811_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(sl811_hcd_resources),
|
||||
.resource = sl811_hcd_resources,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20360000,
|
||||
.end = 0x20360000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20360004,
|
||||
.end = 0x20360004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTA,
|
||||
.end = IRQ_PROG_INTA,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},{
|
||||
.start = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
|
||||
.end = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
static struct platform_device bfin_mac_device = {
|
||||
.name = "bfin_mac",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
static struct resource net2272_bfin_resources[] = {
|
||||
{
|
||||
.start = 0x20300000,
|
||||
.end = 0x20300000 + 0x100,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device net2272_bfin_device = {
|
||||
.name = "net2272",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(net2272_bfin_resources),
|
||||
.resource = net2272_bfin_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) \
|
||||
|| defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
{
|
||||
.modalias = "ad9960-spi",
|
||||
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &ad9960_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
static struct platform_device bfin_fb_device = {
|
||||
.name = "bf537-fb",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0xFFC02000,
|
||||
.end = 0xFFC020FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *stamp_devices[] __initdata = {
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
&bfin_pcmcia_cf_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
&sl811_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
&bfin_mac_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
&net2272_bfin_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
&bfin_fb_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init stamp_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(stamp_init);
|
183
arch/blackfin/mach-bf537/boards/led.S
Normal file
183
arch/blackfin/mach-bf537/boards/led.S
Normal file
|
@ -0,0 +1,183 @@
|
|||
/****************************************************
|
||||
* LED1 ---- PF6 LED2 ---- PF7 *
|
||||
* LED3 ---- PF8 LED4 ---- PF9 *
|
||||
* LED5 ---- PF10 LED6 ---- PF11 *
|
||||
****************************************************/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
/* All functions in this file save the registers they uses.
|
||||
So there is no need to save any registers before calling them. */
|
||||
|
||||
.text;
|
||||
|
||||
/* Initialize LEDs. */
|
||||
|
||||
ENTRY(_led_init)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R0;
|
||||
[--SP] = R1;
|
||||
[--SP] = R2;
|
||||
R1 = PF6|PF7|PF8|PF9|PF10|PF11 (Z);
|
||||
R2 = ~R1;
|
||||
|
||||
P0.H = hi(PORTF_FER);
|
||||
P0.L = lo(PORTF_FER);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 & R2;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
P0.H = hi(PORTFIO_DIR);
|
||||
P0.L = lo(PORTFIO_DIR);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 | R1;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
P0.H = hi(PORTFIO_INEN);
|
||||
P0.L = lo(PORTFIO_INEN);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 & R2;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
R2 = [SP++];
|
||||
R1 = [SP++];
|
||||
R0 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_init, .-_led_init
|
||||
|
||||
/* Set one LED on. Leave other LEDs unchanged.
|
||||
It expects the LED number passed through R0. */
|
||||
|
||||
ENTRY(_led_on)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R1;
|
||||
CALL _led_init;
|
||||
R1 = 1;
|
||||
R0 += 5;
|
||||
R1 <<= R0;
|
||||
P0.H = hi(PORTFIO);
|
||||
P0.L = lo(PORTFIO);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 | R1;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
R1 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_on, .-_led_on
|
||||
|
||||
/* Set one LED off. Leave other LEDs unchanged. */
|
||||
|
||||
ENTRY(_led_off)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R1;
|
||||
CALL _led_init;
|
||||
R1 = 1;
|
||||
R0 += 5;
|
||||
R1 <<= R0;
|
||||
R1 = ~R1;
|
||||
P0.H = hi(PORTFIO);
|
||||
P0.L = lo(PORTFIO);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 & R1;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
R1 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_off, .-_led_off
|
||||
|
||||
/* Toggle one LED. Leave other LEDs unchanged. */
|
||||
|
||||
ENTRY(_led_toggle)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R1;
|
||||
CALL _led_init;
|
||||
R1 = 1;
|
||||
R0 += 5;
|
||||
R1 <<= R0;
|
||||
P0.H = hi(PORTFIO);
|
||||
P0.L = lo(PORTFIO);
|
||||
R0 = W[P0](Z);
|
||||
SSYNC;
|
||||
R0 = R0 ^ R1;
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
R1 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_toggle, .-_led_toggle
|
||||
|
||||
/* Display the number using LEDs in binary format. */
|
||||
|
||||
ENTRY(_led_disp_num)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R1;
|
||||
[--SP] = R2;
|
||||
CALL _led_init;
|
||||
R1 = 0x3f(X);
|
||||
R0 = R0 & R1;
|
||||
R2 = 6(X);
|
||||
R0 <<= R2;
|
||||
R1 <<= R2;
|
||||
P0.H = hi(PORTFIO);
|
||||
P0.L = lo(PORTFIO);
|
||||
R2 = W[P0](Z);
|
||||
SSYNC;
|
||||
R1 = ~R1;
|
||||
R2 = R2 & R1;
|
||||
R2 = R2 | R0;
|
||||
W[P0] = R2.L;
|
||||
SSYNC;
|
||||
R2 = [SP++];
|
||||
R1 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_disp_num, .-_led_disp_num
|
||||
|
||||
/* Toggle the number using LEDs in binary format. */
|
||||
|
||||
ENTRY(_led_toggle_num)
|
||||
LINK 12;
|
||||
[--SP] = P0;
|
||||
[--SP] = R1;
|
||||
[--SP] = R2;
|
||||
CALL _led_init;
|
||||
R1 = 0x3f(X);
|
||||
R0 = R0 & R1;
|
||||
R1 = 6(X);
|
||||
R0 <<= R1;
|
||||
P0.H = hi(PORTFIO);
|
||||
P0.L = lo(PORTFIO);
|
||||
R1 = W[P0](Z);
|
||||
SSYNC;
|
||||
R1 = R1 ^ R0;
|
||||
W[P0] = R1.L;
|
||||
SSYNC;
|
||||
R2 = [SP++];
|
||||
R1 = [SP++];
|
||||
P0 = [SP++];
|
||||
UNLINK;
|
||||
RTS;
|
||||
.size _led_toggle_num, .-_led_toggle_num
|
||||
|
523
arch/blackfin/mach-bf537/boards/pnav10.c
Normal file
523
arch/blackfin/mach-bf537/boards/pnav10.c
Normal file
|
@ -0,0 +1,523 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/boards/stamp.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
#include <linux/usb_isp1362.h>
|
||||
#endif
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <linux/usb_sl811.h>
|
||||
|
||||
#include <linux/spi/ad7877.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "PNAV-1.0";
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
static struct resource bfin_pcmcia_cf_resources[] = {
|
||||
{
|
||||
.start = 0x20310000, /* IO PORT */
|
||||
.end = 0x20312000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20311000, /* Attribute Memeory */
|
||||
.end = 0x20311FFF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF4,
|
||||
.end = IRQ_PF4,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
|
||||
},{
|
||||
.start = 6, /* Card Detect PF6 */
|
||||
.end = 6,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_pcmcia_cf_device = {
|
||||
.name = "bfin_cf_pcmcia",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
|
||||
.resource = bfin_pcmcia_cf_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x20300300,
|
||||
.end = 0x20300300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
static struct resource sl811_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20340000,
|
||||
.end = 0x20340000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20340004,
|
||||
.end = 0x20340004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = CONFIG_USB_SL811_BFIN_IRQ,
|
||||
.end = CONFIG_USB_SL811_BFIN_IRQ,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
void sl811_port_power(struct device *dev, int is_on)
|
||||
{
|
||||
unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
|
||||
|
||||
bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
|
||||
bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
|
||||
|
||||
if (is_on)
|
||||
bfin_write_FIO_FLAG_S(mask);
|
||||
else
|
||||
bfin_write_FIO_FLAG_C(mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct sl811_platform_data sl811_priv = {
|
||||
.potpg = 10,
|
||||
.power = 250, /* == 500mA */
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
.port_power = &sl811_port_power,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_device sl811_hcd_device = {
|
||||
.name = "sl811-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &sl811_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(sl811_hcd_resources),
|
||||
.resource = sl811_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20360000,
|
||||
.end = 0x20360000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20360004,
|
||||
.end = 0x20360004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
|
||||
.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
static struct platform_device bfin_mac_device = {
|
||||
.name = "bfin_mac",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
static struct resource net2272_bfin_resources[] = {
|
||||
{
|
||||
.start = 0x20300000,
|
||||
.end = 0x20300000 + 0x100,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device net2272_bfin_device = {
|
||||
.name = "net2272",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(net2272_bfin_resources),
|
||||
.resource = net2272_bfin_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) \
|
||||
|| defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) \
|
||||
|| defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_mmc_chip_info = {
|
||||
.enable_dma = 1,
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PBX)
|
||||
static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
|
||||
.ctl_reg = 0x4, /* send zero */
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 8,
|
||||
.cs_change_per_word = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
|
||||
.cs_change_per_word = 1,
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
|
||||
static const struct ad7877_platform_data bfin_ad7877_ts_info = {
|
||||
.model = 7877,
|
||||
.vref_delay_usecs = 50, /* internal, no capacitor */
|
||||
.x_plate_ohms = 419,
|
||||
.y_plate_ohms = 486,
|
||||
.pressure_max = 1000,
|
||||
.pressure_min = 0,
|
||||
.stopacq_polarity = 1,
|
||||
.first_conversion_delay = 3,
|
||||
.acquisition_time = 1,
|
||||
.averaging = 1,
|
||||
.pen_down_acc_interval = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) \
|
||||
|| defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) \
|
||||
|| defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
{
|
||||
.modalias = "ad9960-spi",
|
||||
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &ad9960_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
{
|
||||
.modalias = "spi_mmc_dummy",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 7,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "spi_mmc",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SPI_MMC_CS_CHAN,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_PBX)
|
||||
{
|
||||
.modalias = "fxs-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 3,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "fxo-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 2,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
|
||||
{
|
||||
.modalias = "ad7877",
|
||||
.platform_data = &bfin_ad7877_ts_info,
|
||||
.irq = IRQ_PF2,
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 5,
|
||||
.controller_data = &spi_ad7877_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
static struct platform_device bfin_fb_device = {
|
||||
.name = "bf537-fb",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0xFFC02000,
|
||||
.end = 0xFFC020FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_device *stamp_devices[] __initdata = {
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
&bfin_pcmcia_cf_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
&sl811_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
&bfin_mac_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
&net2272_bfin_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
&bfin_fb_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init stamp_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info,
|
||||
ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(stamp_init);
|
615
arch/blackfin/mach-bf537/boards/stamp.c
Normal file
615
arch/blackfin/mach-bf537/boards/stamp.c
Normal file
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/boards/stamp.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
#include <linux/usb_isp1362.h>
|
||||
#endif
|
||||
#include <asm/irq.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
#include <linux/usb_sl811.h>
|
||||
|
||||
#include <linux/spi/ad7877.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "ADDS-BF537-STAMP";
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
|
||||
#define ISP1761_BASE 0x203C0000
|
||||
#define ISP1761_IRQ IRQ_PF7
|
||||
|
||||
#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
|
||||
static struct resource bfin_isp1761_resources[] = {
|
||||
[0] = {
|
||||
.name = "isp1761-regs",
|
||||
.start = ISP1761_BASE + 0x00000000,
|
||||
.end = ISP1761_BASE + 0x000fffff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = ISP1761_IRQ,
|
||||
.end = ISP1761_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_isp1761_device = {
|
||||
.name = "isp1761",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(bfin_isp1761_resources),
|
||||
.resource = bfin_isp1761_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *bfin_isp1761_devices[] = {
|
||||
&bfin_isp1761_device,
|
||||
};
|
||||
|
||||
int __init bfin_isp1761_init(void)
|
||||
{
|
||||
unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices);
|
||||
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
|
||||
|
||||
return platform_add_devices(bfin_isp1761_devices, num_devices);
|
||||
}
|
||||
|
||||
void __exit bfin_isp1761_exit(void)
|
||||
{
|
||||
platform_device_unregister(&bfin_isp1761_device);
|
||||
}
|
||||
|
||||
arch_initcall(bfin_isp1761_init);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
static struct resource bfin_pcmcia_cf_resources[] = {
|
||||
{
|
||||
.start = 0x20310000, /* IO PORT */
|
||||
.end = 0x20312000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20311000, /* Attribute Memeory */
|
||||
.end = 0x20311FFF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF4,
|
||||
.end = IRQ_PF4,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
|
||||
},{
|
||||
.start = 6, /* Card Detect PF6 */
|
||||
.end = 6,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_pcmcia_cf_device = {
|
||||
.name = "bfin_cf_pcmcia",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
|
||||
.resource = bfin_pcmcia_cf_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
static struct platform_device rtc_device = {
|
||||
.name = "rtc-bfin",
|
||||
.id = -1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x20300300,
|
||||
.end = 0x20300300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
static struct resource sl811_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20340000,
|
||||
.end = 0x20340000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20340004,
|
||||
.end = 0x20340004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = CONFIG_USB_SL811_BFIN_IRQ,
|
||||
.end = CONFIG_USB_SL811_BFIN_IRQ,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
void sl811_port_power(struct device *dev, int is_on)
|
||||
{
|
||||
unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
|
||||
|
||||
bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
|
||||
bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
|
||||
|
||||
if (is_on)
|
||||
bfin_write_FIO_FLAG_S(mask);
|
||||
else
|
||||
bfin_write_FIO_FLAG_C(mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct sl811_platform_data sl811_priv = {
|
||||
.potpg = 10,
|
||||
.power = 250, /* == 500mA */
|
||||
#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
|
||||
.port_power = &sl811_port_power,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_device sl811_hcd_device = {
|
||||
.name = "sl811-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &sl811_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(sl811_hcd_resources),
|
||||
.resource = sl811_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x20360000,
|
||||
.end = 0x20360000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x20360004,
|
||||
.end = 0x20360004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
|
||||
.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
static struct platform_device bfin_mac_device = {
|
||||
.name = "bfin_mac",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
static struct resource net2272_bfin_resources[] = {
|
||||
{
|
||||
.start = 0x20300000,
|
||||
.end = 0x20300000 + 0x100,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF7,
|
||||
.end = IRQ_PF7,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device net2272_bfin_device = {
|
||||
.name = "net2272",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(net2272_bfin_resources),
|
||||
.resource = net2272_bfin_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI peripherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) \
|
||||
|| defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) \
|
||||
|| defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_mmc_chip_info = {
|
||||
.enable_dma = 1,
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PBX)
|
||||
static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
|
||||
.ctl_reg = 0x4, /* send zero */
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 8,
|
||||
.cs_change_per_word = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
|
||||
static struct bfin5xx_spi_chip ad5304_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
|
||||
// .cs_change_per_word = 1,
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
|
||||
static const struct ad7877_platform_data bfin_ad7877_ts_info = {
|
||||
.model = 7877,
|
||||
.vref_delay_usecs = 50, /* internal, no capacitor */
|
||||
.x_plate_ohms = 419,
|
||||
.y_plate_ohms = 486,
|
||||
.pressure_max = 1000,
|
||||
.pressure_min = 0,
|
||||
.stopacq_polarity = 1,
|
||||
.first_conversion_delay = 3,
|
||||
.acquisition_time = 1,
|
||||
.averaging = 1,
|
||||
.pen_down_acc_interval = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) \
|
||||
|| defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) \
|
||||
|| defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
{
|
||||
.modalias = "ad9960-spi",
|
||||
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &ad9960_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
{
|
||||
.modalias = "spi_mmc_dummy",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 0,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "spi_mmc",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SPI_MMC_CS_CHAN,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_PBX)
|
||||
{
|
||||
.modalias = "fxs-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 3,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
{
|
||||
.modalias = "fxo-spi",
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 2,
|
||||
.controller_data= &spi_si3xxx_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
|
||||
{
|
||||
.modalias = "ad5304_spi",
|
||||
.max_speed_hz = 1250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 2,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &ad5304_chip_info,
|
||||
.mode = SPI_MODE_2,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
|
||||
{
|
||||
.modalias = "ad7877",
|
||||
.platform_data = &bfin_ad7877_ts_info,
|
||||
.irq = IRQ_PF6,
|
||||
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &spi_ad7877_chip_info,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
static struct platform_device bfin_fb_device = {
|
||||
.name = "bf537-fb",
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0xFFC02000,
|
||||
.end = 0xFFC020FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
|
||||
static struct platform_device i2c_bfin_twi_device = {
|
||||
.name = "i2c-bfin-twi",
|
||||
.id = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
static struct platform_device bfin_sport0_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device bfin_sport1_uart_device = {
|
||||
.name = "bfin-sport-uart",
|
||||
.id = 1,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *stamp_devices[] __initdata = {
|
||||
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
|
||||
&bfin_pcmcia_cf_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
|
||||
&rtc_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
|
||||
&sl811_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
|
||||
&bfin_mac_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
|
||||
&net2272_bfin_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
|
||||
&bfin_fb_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
|
||||
&i2c_bfin_twi_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
|
||||
&bfin_sport0_uart_device,
|
||||
&bfin_sport1_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init stamp_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info,
|
||||
ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(stamp_init);
|
161
arch/blackfin/mach-bf537/cpu.c
Normal file
161
arch/blackfin/mach-bf537/cpu.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/cpu.c
|
||||
* Based on:
|
||||
* Author: michael.kang@analog.com
|
||||
*
|
||||
* Created:
|
||||
* Description: clock scaling for the bf537
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/bfin-global.h>
|
||||
|
||||
/* CONFIG_CLKIN_HZ=11059200 */
|
||||
#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */
|
||||
#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */
|
||||
#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */
|
||||
#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */
|
||||
#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */
|
||||
#define VCO(x) VCO##x
|
||||
|
||||
#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
|
||||
/* frequency */
|
||||
static struct cpufreq_frequency_table bf537_freq_table[] = {
|
||||
FREQ(1),
|
||||
FREQ(3),
|
||||
{VCO4, VCO4 / 2}, {VCO4, VCO4},
|
||||
FREQ(5),
|
||||
{0, CPUFREQ_TABLE_END},
|
||||
};
|
||||
|
||||
/*
|
||||
* dpmc_fops->ioctl()
|
||||
* static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
*/
|
||||
static int bf537_getfreq(unsigned int cpu)
|
||||
{
|
||||
unsigned long cclk_mhz, vco_mhz;
|
||||
|
||||
/* The driver only support single cpu */
|
||||
if (cpu == 0)
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
|
||||
else
|
||||
cclk_mhz = -1;
|
||||
return cclk_mhz;
|
||||
}
|
||||
|
||||
static int bf537_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq, unsigned int relation)
|
||||
{
|
||||
unsigned long cclk_mhz;
|
||||
unsigned long vco_mhz;
|
||||
unsigned long flags;
|
||||
unsigned int index, vco_index;
|
||||
int i;
|
||||
|
||||
struct cpufreq_freqs freqs;
|
||||
if (cpufreq_frequency_table_target
|
||||
(policy, bf537_freq_table, target_freq, relation, &index))
|
||||
return -EINVAL;
|
||||
cclk_mhz = bf537_freq_table[index].frequency;
|
||||
vco_mhz = bf537_freq_table[index].index;
|
||||
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
|
||||
freqs.old = bf537_getfreq(0);
|
||||
freqs.new = cclk_mhz;
|
||||
freqs.cpu = 0;
|
||||
|
||||
pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
|
||||
cclk_mhz, vco_mhz, index, target_freq, freqs.old);
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
local_irq_save(flags);
|
||||
dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
|
||||
local_irq_restore(flags);
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
vco_mhz = get_vco();
|
||||
cclk_mhz = get_cclk();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
|
||||
* this platform, anyway.
|
||||
*/
|
||||
static int bf537_verify_speed(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_frequency_table_verify(policy, &bf537_freq_table);
|
||||
}
|
||||
|
||||
static int __init __bf537_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
return -EINVAL;
|
||||
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
|
||||
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
|
||||
/*Now ,only support one cpu */
|
||||
policy->cur = bf537_getfreq(0);
|
||||
cpufreq_frequency_table_get_attr(bf537_freq_table, policy->cpu);
|
||||
return cpufreq_frequency_table_cpuinfo(policy, bf537_freq_table);
|
||||
}
|
||||
|
||||
static struct freq_attr *bf537_freq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver bf537_driver = {
|
||||
.verify = bf537_verify_speed,
|
||||
.target = bf537_target,
|
||||
.get = bf537_getfreq,
|
||||
.init = __bf537_cpu_init,
|
||||
.name = "bf537",
|
||||
.owner = THIS_MODULE,
|
||||
.attr = bf537_freq_attr,
|
||||
};
|
||||
|
||||
static int __init bf537_cpu_init(void)
|
||||
{
|
||||
return cpufreq_register_driver(&bf537_driver);
|
||||
}
|
||||
|
||||
static void __exit bf537_cpu_exit(void)
|
||||
{
|
||||
cpufreq_unregister_driver(&bf537_driver);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Mickael Kang");
|
||||
MODULE_DESCRIPTION("cpufreq driver for BF537 CPU");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(bf537_cpu_init);
|
||||
module_exit(bf537_cpu_exit);
|
602
arch/blackfin/mach-bf537/head.S
Normal file
602
arch/blackfin/mach-bf537/head.S
Normal file
|
@ -0,0 +1,602 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/head.S
|
||||
* Based on: arch/blackfin/mach-bf533/head.S
|
||||
* Author: Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
|
||||
*
|
||||
* Created: 1998
|
||||
* Description: Startup code for Blackfin BF537
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
#include <asm/mach/mem_init.h>
|
||||
#endif
|
||||
|
||||
.global __rambase
|
||||
.global __ramstart
|
||||
.global __ramend
|
||||
.extern ___bss_stop
|
||||
.extern ___bss_start
|
||||
.extern _bf53x_relocate_l1_mem
|
||||
|
||||
#define INITIAL_STACK 0xFFB01000
|
||||
|
||||
.text
|
||||
|
||||
ENTRY(__start)
|
||||
ENTRY(__stext)
|
||||
/* R0: argument of command line string, passed from uboot, save it */
|
||||
R7 = R0;
|
||||
/* Set the SYSCFG register */
|
||||
R0 = 0x36;
|
||||
SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
|
||||
R0 = 0;
|
||||
|
||||
/* Clear Out All the data and pointer Registers*/
|
||||
R1 = R0;
|
||||
R2 = R0;
|
||||
R3 = R0;
|
||||
R4 = R0;
|
||||
R5 = R0;
|
||||
R6 = R0;
|
||||
|
||||
P0 = R0;
|
||||
P1 = R0;
|
||||
P2 = R0;
|
||||
P3 = R0;
|
||||
P4 = R0;
|
||||
P5 = R0;
|
||||
|
||||
LC0 = r0;
|
||||
LC1 = r0;
|
||||
L0 = r0;
|
||||
L1 = r0;
|
||||
L2 = r0;
|
||||
L3 = r0;
|
||||
|
||||
/* Clear Out All the DAG Registers*/
|
||||
B0 = r0;
|
||||
B1 = r0;
|
||||
B2 = r0;
|
||||
B3 = r0;
|
||||
|
||||
I0 = r0;
|
||||
I1 = r0;
|
||||
I2 = r0;
|
||||
I3 = r0;
|
||||
|
||||
M0 = r0;
|
||||
M1 = r0;
|
||||
M2 = r0;
|
||||
M3 = r0;
|
||||
|
||||
/* Turn off the icache */
|
||||
p0.l = (IMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (IMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENICPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Turn off the dcache */
|
||||
p0.l = (DMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (DMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENDCPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Initialise General-Purpose I/O Modules on BF537 */
|
||||
/* Rev 0.0 Anomaly 05000212 - PORTx_FER,
|
||||
* PORT_MUX Registers Do Not accept "writes" correctly:
|
||||
*/
|
||||
p0.h = hi(BFIN_PORT_MUX);
|
||||
p0.l = lo(BFIN_PORT_MUX);
|
||||
#ifdef ANOMALY_05000212
|
||||
R0.L = W[P0]; /* Read */
|
||||
SSYNC;
|
||||
#endif
|
||||
R0 = (PGDE_UART | PFTE_UART)(Z);
|
||||
#ifdef ANOMALY_05000212
|
||||
W[P0] = R0.L; /* Write */
|
||||
SSYNC;
|
||||
#endif
|
||||
W[P0] = R0.L; /* Enable both UARTS */
|
||||
SSYNC;
|
||||
|
||||
p0.h = hi(PORTF_FER);
|
||||
p0.l = lo(PORTF_FER);
|
||||
#ifdef ANOMALY_05000212
|
||||
R0.L = W[P0]; /* Read */
|
||||
SSYNC;
|
||||
#endif
|
||||
R0 = 0x000F(Z);
|
||||
#ifdef ANOMALY_05000212
|
||||
W[P0] = R0.L; /* Write */
|
||||
SSYNC;
|
||||
#endif
|
||||
/* Enable peripheral function of PORTF for UART0 and UART1 */
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
#if !defined(CONFIG_BF534)
|
||||
p0.h = hi(EMAC_SYSTAT);
|
||||
p0.l = lo(EMAC_SYSTAT);
|
||||
R0.h = 0xFFFF; /* Clear EMAC Interrupt Status bits */
|
||||
R0.l = 0xFFFF;
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BF537_PORT_H
|
||||
p0.h = hi(PORTH_FER);
|
||||
p0.l = lo(PORTH_FER);
|
||||
R0.L = W[P0]; /* Read */
|
||||
SSYNC;
|
||||
R0 = 0x0000;
|
||||
W[P0] = R0.L; /* Write */
|
||||
SSYNC;
|
||||
W[P0] = R0.L; /* Disable peripheral function of PORTH */
|
||||
SSYNC;
|
||||
#endif
|
||||
|
||||
/*Initialise UART*/
|
||||
p0.h = hi(UART_LCR);
|
||||
p0.l = lo(UART_LCR);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable DLL writes */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLL);
|
||||
p0.l = lo(UART_DLL);
|
||||
r0 = 0x00(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLH);
|
||||
p0.l = lo(UART_DLH);
|
||||
r0 = 0x00(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable UART clock */
|
||||
ssync;
|
||||
|
||||
/* Initialize stack pointer */
|
||||
sp.l = lo(INITIAL_STACK);
|
||||
sp.h = hi(INITIAL_STACK);
|
||||
fp = sp;
|
||||
usp = sp;
|
||||
|
||||
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
|
||||
call _bf53x_relocate_l1_mem;
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
call _start_dma_code;
|
||||
#endif
|
||||
/* Code for initializing Async memory banks */
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL1);
|
||||
p2.l = lo(EBIU_AMBCTL1);
|
||||
r0.h = hi(AMBCTL1VAL);
|
||||
r0.l = lo(AMBCTL1VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL0);
|
||||
p2.l = lo(EBIU_AMBCTL0);
|
||||
r0.h = hi(AMBCTL0VAL);
|
||||
r0.l = lo(AMBCTL0VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMGCTL);
|
||||
p2.l = lo(EBIU_AMGCTL);
|
||||
r0 = AMGCTLVAL;
|
||||
w[p2] = r0;
|
||||
ssync;
|
||||
|
||||
/* This section keeps the processor in supervisor mode
|
||||
* during kernel boot. Switches to user mode at end of boot.
|
||||
* See page 3-9 of Hardware Reference manual for documentation.
|
||||
*/
|
||||
|
||||
/* EVT15 = _real_start */
|
||||
|
||||
p0.l = lo(EVT15);
|
||||
p0.h = hi(EVT15);
|
||||
p1.l = _real_start;
|
||||
p1.h = _real_start;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
p0.l = lo(IMASK);
|
||||
p0.h = hi(IMASK);
|
||||
p1.l = IMASK_IVG15;
|
||||
p1.h = 0x0;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
raise 15;
|
||||
p0.l = .LWAIT_HERE;
|
||||
p0.h = .LWAIT_HERE;
|
||||
reti = p0;
|
||||
#if defined(ANOMALY_05000281)
|
||||
nop; nop; nop;
|
||||
#endif
|
||||
rti;
|
||||
|
||||
.LWAIT_HERE:
|
||||
jump .LWAIT_HERE;
|
||||
|
||||
ENTRY(_real_start)
|
||||
[ -- sp ] = reti;
|
||||
p0.l = lo(WDOG_CTL);
|
||||
p0.h = hi(WDOG_CTL);
|
||||
r0 = 0xAD6(z);
|
||||
w[p0] = r0; /* watchdog off for now */
|
||||
ssync;
|
||||
|
||||
/* Code update for BSS size == 0
|
||||
* Zero out the bss region.
|
||||
*/
|
||||
|
||||
p1.l = ___bss_start;
|
||||
p1.h = ___bss_start;
|
||||
p2.l = ___bss_stop;
|
||||
p2.h = ___bss_stop;
|
||||
r0 = 0;
|
||||
p2 -= p1;
|
||||
lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
|
||||
.L_clear_bss:
|
||||
B[p1++] = r0;
|
||||
|
||||
/* In case there is a NULL pointer reference
|
||||
* Zero out region before stext
|
||||
*/
|
||||
|
||||
p1.l = 0x0;
|
||||
p1.h = 0x0;
|
||||
r0.l = __stext;
|
||||
r0.h = __stext;
|
||||
r0 = r0 >> 1;
|
||||
p2 = r0;
|
||||
r0 = 0;
|
||||
lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
|
||||
.L_clear_zero:
|
||||
W[p1++] = r0;
|
||||
|
||||
/* pass the uboot arguments to the global value command line */
|
||||
R0 = R7;
|
||||
call _cmdline_init;
|
||||
|
||||
p1.l = __rambase;
|
||||
p1.h = __rambase;
|
||||
r0.l = __sdata;
|
||||
r0.h = __sdata;
|
||||
[p1] = r0;
|
||||
|
||||
p1.l = __ramstart;
|
||||
p1.h = __ramstart;
|
||||
p3.l = ___bss_stop;
|
||||
p3.h = ___bss_stop;
|
||||
|
||||
r1 = p3;
|
||||
[p1] = r1;
|
||||
|
||||
|
||||
/*
|
||||
* load the current thread pointer and stack
|
||||
*/
|
||||
r1.l = _init_thread_union;
|
||||
r1.h = _init_thread_union;
|
||||
|
||||
r2.l = 0x2000;
|
||||
r2.h = 0x0000;
|
||||
r1 = r1 + r2;
|
||||
sp = r1;
|
||||
usp = sp;
|
||||
fp = sp;
|
||||
call _start_kernel;
|
||||
.L_exit:
|
||||
jump.s .L_exit;
|
||||
|
||||
.section .l1.text
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
ENTRY(_start_dma_code)
|
||||
|
||||
/* Enable PHY CLK buffer output */
|
||||
p0.h = hi(VR_CTL);
|
||||
p0.l = lo(VR_CTL);
|
||||
r0.l = w[p0];
|
||||
bitset(r0, 14);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(SIC_IWR);
|
||||
p0.l = lo(SIC_IWR);
|
||||
r0.l = 0x1;
|
||||
r0.h = 0x0;
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/*
|
||||
* Set PLL_CTL
|
||||
* - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
|
||||
* - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
|
||||
* - [7] = output delay (add 200ps of delay to mem signals)
|
||||
* - [6] = input delay (add 200ps of input delay to mem signals)
|
||||
* - [5] = PDWN : 1=All Clocks off
|
||||
* - [3] = STOPCK : 1=Core Clock off
|
||||
* - [1] = PLL_OFF : 1=Disable Power to PLL
|
||||
* - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
|
||||
* all other bits set to zero
|
||||
*/
|
||||
|
||||
p0.h = hi(PLL_LOCKCNT);
|
||||
p0.l = lo(PLL_LOCKCNT);
|
||||
r0 = 0x300(Z);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITSET (R0, 24);
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
|
||||
r0 = r0 << 9; /* Shift it over, */
|
||||
r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
|
||||
r0 = r1 | r0;
|
||||
r1 = PLL_BYPASS; /* Bypass the PLL? */
|
||||
r1 = r1 << 8; /* Shift it over */
|
||||
r0 = r1 | r0; /* add them all together */
|
||||
|
||||
p0.h = hi(PLL_CTL);
|
||||
p0.l = lo(PLL_CTL); /* Load the address */
|
||||
cli r2; /* Disable interrupts */
|
||||
ssync;
|
||||
w[p0] = r0.l; /* Set the value */
|
||||
idle; /* Wait for the PLL to stablize */
|
||||
sti r2; /* Enable interrupts */
|
||||
|
||||
.Lcheck_again:
|
||||
p0.h = hi(PLL_STAT);
|
||||
p0.l = lo(PLL_STAT);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,5);
|
||||
if ! CC jump .Lcheck_again;
|
||||
|
||||
/* Configure SCLK & CCLK Dividers */
|
||||
r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
|
||||
p0.h = hi(PLL_DIV);
|
||||
p0.l = lo(PLL_DIV);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = lo(EBIU_SDRRC);
|
||||
p0.h = hi(EBIU_SDRRC);
|
||||
r0 = mem_SDRRC;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = (EBIU_SDBCTL & 0xFFFF);
|
||||
p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
|
||||
r0 = mem_SDBCTL;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITCLR (R0, 24);
|
||||
p0.h = hi(EBIU_SDSTAT);
|
||||
p0.l = lo(EBIU_SDSTAT);
|
||||
r2.l = w[p0];
|
||||
cc = bittst(r2,3);
|
||||
if !cc jump .Lskip;
|
||||
NOP;
|
||||
BITSET (R0, 23);
|
||||
.Lskip:
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
R0.L = lo(mem_SDGCTL);
|
||||
R0.H = hi(mem_SDGCTL);
|
||||
R1 = [p2];
|
||||
R1 = R1 | R0;
|
||||
[P2] = R1;
|
||||
SSYNC;
|
||||
|
||||
p0.h = hi(SIC_IWR);
|
||||
p0.l = lo(SIC_IWR);
|
||||
r0.l = lo(IWR_ENABLE_ALL);
|
||||
r0.h = hi(IWR_ENABLE_ALL);
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
RTS;
|
||||
#endif /* CONFIG_BFIN_KERNEL_CLOCK */
|
||||
|
||||
ENTRY(_bfin_reset)
|
||||
/* No more interrupts to be handled*/
|
||||
CLI R6;
|
||||
SSYNC;
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80)
|
||||
/*
|
||||
* The following code fix the SPI flash reboot issue,
|
||||
* /CS signal of the chip which is using PF10 return to GPIO mode
|
||||
*/
|
||||
p0.h = hi(PORTF_FER);
|
||||
p0.l = lo(PORTF_FER);
|
||||
r0.l = 0x0000;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* /CS return to high */
|
||||
p0.h = hi(PORTFIO);
|
||||
p0.l = lo(PORTFIO);
|
||||
r0.l = 0xFFFF;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Delay some time, This is necessary */
|
||||
r1.h = 0;
|
||||
r1.l = 0x400;
|
||||
p1 = r1;
|
||||
lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1;
|
||||
_delay_lab1:
|
||||
r0.h = 0;
|
||||
r0.l = 0x8000;
|
||||
p0 = r0;
|
||||
lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0;
|
||||
_delay_lab0:
|
||||
nop;
|
||||
_delay_lab0_end:
|
||||
nop;
|
||||
_delay_lab1_end:
|
||||
nop;
|
||||
#endif
|
||||
|
||||
/* Clear the bits 13-15 in SWRST if they werent cleared */
|
||||
p0.h = hi(SWRST);
|
||||
p0.l = lo(SWRST);
|
||||
csync;
|
||||
r0.l = w[p0];
|
||||
|
||||
/* Clear the IMASK register */
|
||||
p0.h = hi(IMASK);
|
||||
p0.l = lo(IMASK);
|
||||
r0 = 0x0;
|
||||
[p0] = r0;
|
||||
|
||||
/* Clear the ILAT register */
|
||||
p0.h = hi(ILAT);
|
||||
p0.l = lo(ILAT);
|
||||
r0 = [p0];
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/* Disable the WDOG TIMER */
|
||||
p0.h = hi(WDOG_CTL);
|
||||
p0.l = lo(WDOG_CTL);
|
||||
r0.l = 0xAD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Clear the sticky bit incase it is already set */
|
||||
p0.h = hi(WDOG_CTL);
|
||||
p0.l = lo(WDOG_CTL);
|
||||
r0.l = 0x8AD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Program the count value */
|
||||
R0.l = 0x100;
|
||||
R0.h = 0x0;
|
||||
P0.h = hi(WDOG_CNT);
|
||||
P0.l = lo(WDOG_CNT);
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
/* Program WDOG_STAT if necessary */
|
||||
P0.h = hi(WDOG_CTL);
|
||||
P0.l = lo(WDOG_CTL);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,1);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
CC = BITTST(R0,2);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
JUMP .LSKIP_WRITE;
|
||||
|
||||
.LWRITESTAT:
|
||||
/* When watch dog timer is enabled,
|
||||
* a write to STAT will load the contents of CNT to STAT
|
||||
*/
|
||||
R0 = 0x0000(z);
|
||||
P0.h = hi(WDOG_STAT);
|
||||
P0.l = lo(WDOG_STAT)
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
.LSKIP_WRITE:
|
||||
/* Enable the reset event */
|
||||
P0.h = hi(WDOG_CTL);
|
||||
P0.l = lo(WDOG_CTL);
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,1);
|
||||
BITCLR(R0,2);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
NOP;
|
||||
|
||||
/* Enable the wdog counter */
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,4);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
IDLE;
|
||||
|
||||
RTS;
|
||||
|
||||
.data
|
||||
|
||||
/*
|
||||
* Set up the usable of RAM stuff. Size of RAM is determined then
|
||||
* an initial stack set up at the end.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
__rambase:
|
||||
.long 0
|
||||
__ramstart:
|
||||
.long 0
|
||||
__ramend:
|
||||
.long 0
|
74
arch/blackfin/mach-bf537/ints-priority.c
Normal file
74
arch/blackfin/mach-bf537/ints-priority.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf537/ints-priority.c
|
||||
* Based on: arch/blackfin/mach-bf533/ints-priority.c
|
||||
* Author: Michael Hennerich
|
||||
*
|
||||
* Created:
|
||||
* Description: Set up the interupt priorities
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
void program_IAR(void)
|
||||
{
|
||||
/* Program the IAR0 Register with the configured priority */
|
||||
bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
|
||||
((CONFIG_IRQ_DMA_ERROR - 7) << IRQ_DMA_ERROR_POS) |
|
||||
((CONFIG_IRQ_ERROR - 7) << IRQ_ERROR_POS) |
|
||||
((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS) |
|
||||
((CONFIG_IRQ_PPI - 7) << IRQ_PPI_POS) |
|
||||
((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) |
|
||||
((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) |
|
||||
((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS));
|
||||
|
||||
bfin_write_SIC_IAR1(((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) |
|
||||
((CONFIG_IRQ_TWI - 7) << IRQ_TWI_POS) |
|
||||
((CONFIG_IRQ_SPI - 7) << IRQ_SPI_POS) |
|
||||
((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) |
|
||||
((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS) |
|
||||
((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) |
|
||||
((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) |
|
||||
((CONFIG_IRQ_CAN_RX - 7) << IRQ_CAN_RX_POS));
|
||||
|
||||
bfin_write_SIC_IAR2(((CONFIG_IRQ_CAN_TX - 7) << IRQ_CAN_TX_POS) |
|
||||
((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) |
|
||||
((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) |
|
||||
((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) |
|
||||
((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) |
|
||||
((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) |
|
||||
((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) |
|
||||
((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS));
|
||||
|
||||
bfin_write_SIC_IAR3(((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) |
|
||||
((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) |
|
||||
((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS) |
|
||||
((CONFIG_IRQ_PROG_INTA - 7) << IRQ_PROG_INTA_POS) |
|
||||
((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) |
|
||||
((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) |
|
||||
((CONFIG_IRQ_MEM_DMA1 - 7) << IRQ_MEM_DMA1_POS) |
|
||||
((CONFIG_IRQ_WATCH - 7) << IRQ_WATCH_POS));
|
||||
|
||||
SSYNC();
|
||||
}
|
222
arch/blackfin/mach-bf561/Kconfig
Normal file
222
arch/blackfin/mach-bf561/Kconfig
Normal file
|
@ -0,0 +1,222 @@
|
|||
if BF561
|
||||
|
||||
menu "BF561 Specific Configuration"
|
||||
|
||||
comment "Core B Support"
|
||||
|
||||
menu "Core B Support"
|
||||
|
||||
config BF561_COREB
|
||||
bool "Enable Core B support"
|
||||
default y
|
||||
|
||||
config BF561_COREB_RESET
|
||||
bool "Enable Core B reset support"
|
||||
default n
|
||||
help
|
||||
This requires code in the application that is loaded
|
||||
into Core B. In order to reset, the application needs
|
||||
to install an interrupt handler for Supplemental
|
||||
Interrupt 0, that sets RETI to 0xff600000 and writes
|
||||
bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
|
||||
This causes Core B to stall when Supplemental Interrupt
|
||||
0 is set, and will reset PC to 0xff600000 when
|
||||
COREB_SRAM_INIT is cleared.
|
||||
|
||||
endmenu
|
||||
|
||||
comment "Interrupt Priority Assignment"
|
||||
|
||||
menu "Priority"
|
||||
|
||||
config IRQ_PLL_WAKEUP
|
||||
int "PLL Wakeup Interrupt"
|
||||
default 7
|
||||
config IRQ_DMA1_ERROR
|
||||
int "DMA1 Error (generic)"
|
||||
default 7
|
||||
config IRQ_DMA2_ERROR
|
||||
int "DMA2 Error (generic)"
|
||||
default 7
|
||||
config IRQ_IMDMA_ERROR
|
||||
int "IMDMA Error (generic)"
|
||||
default 7
|
||||
config IRQ_PPI0_ERROR
|
||||
int "PPI0 Error Interrupt"
|
||||
default 7
|
||||
config IRQ_PPI1_ERROR
|
||||
int "PPI1 Error Interrupt"
|
||||
default 7
|
||||
config IRQ_SPORT0_ERROR
|
||||
int "SPORT0 Error Interrupt"
|
||||
default 7
|
||||
config IRQ_SPORT1_ERROR
|
||||
int "SPORT1 Error Interrupt"
|
||||
default 7
|
||||
config IRQ_SPI_ERROR
|
||||
int "SPI Error Interrupt"
|
||||
default 7
|
||||
config IRQ_UART_ERROR
|
||||
int "UART Error Interrupt"
|
||||
default 7
|
||||
config IRQ_RESERVED_ERROR
|
||||
int "Reserved Interrupt"
|
||||
default 7
|
||||
config IRQ_DMA1_0
|
||||
int "DMA1 0 Interrupt(PPI1)"
|
||||
default 8
|
||||
config IRQ_DMA1_1
|
||||
int "DMA1 1 Interrupt(PPI2)"
|
||||
default 8
|
||||
config IRQ_DMA1_2
|
||||
int "DMA1 2 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_3
|
||||
int "DMA1 3 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_4
|
||||
int "DMA1 4 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_5
|
||||
int "DMA1 5 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_6
|
||||
int "DMA1 6 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_7
|
||||
int "DMA1 7 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_8
|
||||
int "DMA1 8 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_9
|
||||
int "DMA1 9 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_10
|
||||
int "DMA1 10 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA1_11
|
||||
int "DMA1 11 Interrupt"
|
||||
default 8
|
||||
config IRQ_DMA2_0
|
||||
int "DMA2 0 (SPORT0 RX)"
|
||||
default 9
|
||||
config IRQ_DMA2_1
|
||||
int "DMA2 1 (SPORT0 TX)"
|
||||
default 9
|
||||
config IRQ_DMA2_2
|
||||
int "DMA2 2 (SPORT1 RX)"
|
||||
default 9
|
||||
config IRQ_DMA2_3
|
||||
int "DMA2 3 (SPORT2 TX)"
|
||||
default 9
|
||||
config IRQ_DMA2_4
|
||||
int "DMA2 4 (SPI)"
|
||||
default 9
|
||||
config IRQ_DMA2_5
|
||||
int "DMA2 5 (UART RX)"
|
||||
default 9
|
||||
config IRQ_DMA2_6
|
||||
int "DMA2 6 (UART TX)"
|
||||
default 9
|
||||
config IRQ_DMA2_7
|
||||
int "DMA2 7 Interrupt"
|
||||
default 9
|
||||
config IRQ_DMA2_8
|
||||
int "DMA2 8 Interrupt"
|
||||
default 9
|
||||
config IRQ_DMA2_9
|
||||
int "DMA2 9 Interrupt"
|
||||
default 9
|
||||
config IRQ_DMA2_10
|
||||
int "DMA2 10 Interrupt"
|
||||
default 9
|
||||
config IRQ_DMA2_11
|
||||
int "DMA2 11 Interrupt"
|
||||
default 9
|
||||
config IRQ_TIMER0
|
||||
int "TIMER 0 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER1
|
||||
int "TIMER 1 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER2
|
||||
int "TIMER 2 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER3
|
||||
int "TIMER 3 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER4
|
||||
int "TIMER 4 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER5
|
||||
int "TIMER 5 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER6
|
||||
int "TIMER 6 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER7
|
||||
int "TIMER 7 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER8
|
||||
int "TIMER 8 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER9
|
||||
int "TIMER 9 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER10
|
||||
int "TIMER 10 Interrupt"
|
||||
default 10
|
||||
config IRQ_TIMER11
|
||||
int "TIMER 11 Interrupt"
|
||||
default 10
|
||||
config IRQ_PROG0_INTA
|
||||
int "Programmable Flags0 A (8)"
|
||||
default 11
|
||||
config IRQ_PROG0_INTB
|
||||
int "Programmable Flags0 B (8)"
|
||||
default 11
|
||||
config IRQ_PROG1_INTA
|
||||
int "Programmable Flags1 A (8)"
|
||||
default 11
|
||||
config IRQ_PROG1_INTB
|
||||
int "Programmable Flags1 B (8)"
|
||||
default 11
|
||||
config IRQ_PROG2_INTA
|
||||
int "Programmable Flags2 A (8)"
|
||||
default 11
|
||||
config IRQ_PROG2_INTB
|
||||
int "Programmable Flags2 B (8)"
|
||||
default 11
|
||||
config IRQ_DMA1_WRRD0
|
||||
int "MDMA1 0 write/read INT"
|
||||
default 8
|
||||
config IRQ_DMA1_WRRD1
|
||||
int "MDMA1 1 write/read INT"
|
||||
default 8
|
||||
config IRQ_DMA2_WRRD0
|
||||
int "MDMA2 0 write/read INT"
|
||||
default 9
|
||||
config IRQ_DMA2_WRRD1
|
||||
int "MDMA2 1 write/read INT"
|
||||
default 9
|
||||
config IRQ_IMDMA_WRRD0
|
||||
int "IMDMA 0 write/read INT"
|
||||
default 12
|
||||
config IRQ_IMDMA_WRRD1
|
||||
int "IMDMA 1 write/read INT"
|
||||
default 12
|
||||
config IRQ_WDTIMER
|
||||
int "Watch Dog Timer"
|
||||
default 13
|
||||
|
||||
help
|
||||
Enter the priority numbers between 7-13 ONLY. Others are Reserved.
|
||||
This applies to all the above. It is not recommended to assign the
|
||||
highest priority number 7 to UART or any other device.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
9
arch/blackfin/mach-bf561/Makefile
Normal file
9
arch/blackfin/mach-bf561/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf561/Makefile
|
||||
#
|
||||
|
||||
extra-y := head.o
|
||||
|
||||
obj-y := ints-priority.o
|
||||
|
||||
obj-$(CONFIG_BF561_COREB) += coreb.o
|
7
arch/blackfin/mach-bf561/boards/Makefile
Normal file
7
arch/blackfin/mach-bf561/boards/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# arch/blackfin/mach-bf561/boards/Makefile
|
||||
#
|
||||
|
||||
obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
|
||||
obj-$(CONFIG_BFIN561_EZKIT) += ezkit.o
|
||||
obj-$(CONFIG_BFIN561_BLUETECHNIX_CM) += cm_bf561.o
|
289
arch/blackfin/mach-bf561/boards/cm_bf561.c
Normal file
289
arch/blackfin/mach-bf561/boards/cm_bf561.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf533/boards/cm_bf561.c
|
||||
* Based on: arch/blackfin/mach-bf533/boards/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au> Copright 2005
|
||||
*
|
||||
* Created: 2006
|
||||
* Description: Board description file
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/usb_isp1362.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "Bluetechnix CM BF561";
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
/* all SPI perpherals info goes here */
|
||||
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
static struct mtd_partition bfin_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "bootloader",
|
||||
.size = 0x00020000,
|
||||
.offset = 0,
|
||||
.mask_flags = MTD_CAP_ROM
|
||||
},{
|
||||
.name = "kernel",
|
||||
.size = 0xe0000,
|
||||
.offset = 0x20000
|
||||
},{
|
||||
.name = "file system",
|
||||
.size = 0x700000,
|
||||
.offset = 0x00100000,
|
||||
}
|
||||
};
|
||||
|
||||
static struct flash_platform_data bfin_spi_flash_data = {
|
||||
.name = "m25p80",
|
||||
.parts = bfin_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
|
||||
.type = "m25p64",
|
||||
};
|
||||
|
||||
/* SPI flash chip (m25p64) */
|
||||
static struct bfin5xx_spi_chip spi_flash_chip_info = {
|
||||
.enable_dma = 0, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
/* SPI ADC chip */
|
||||
static struct bfin5xx_spi_chip spi_adc_chip_info = {
|
||||
.enable_dma = 1, /* use dma transfer with this chip*/
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
static struct bfin5xx_spi_chip spi_mmc_chip_info = {
|
||||
.enable_dma = 1,
|
||||
.bits_per_word = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
|
||||
{
|
||||
/* the modalias must be the same as spi device driver name */
|
||||
.modalias = "m25p80", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
|
||||
.platform_data = &bfin_spi_flash_data,
|
||||
.controller_data = &spi_flash_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
|
||||
{
|
||||
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select. */
|
||||
.platform_data = NULL, /* No spi_driver specific config */
|
||||
.controller_data = &spi_adc_chip_info,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
|
||||
{
|
||||
.modalias = "ad9960-spi",
|
||||
.max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = 1,
|
||||
.controller_data = &ad9960_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
|
||||
{
|
||||
.modalias = "spi_mmc",
|
||||
.max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SPI_MMC_CS_CHAN,
|
||||
.platform_data = NULL,
|
||||
.controller_data = &spi_mmc_chip_info,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
#endif /* spi master and devices */
|
||||
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x28000300,
|
||||
.end = 0x28000300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF0,
|
||||
.end = IRQ_PF0,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
static struct resource isp1362_hcd_resources[] = {
|
||||
{
|
||||
.start = 0x24008000,
|
||||
.end = 0x24008000,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = 0x24008004,
|
||||
.end = 0x24008004,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PF47,
|
||||
.end = IRQ_PF47,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct isp1362_platform_data isp1362_priv = {
|
||||
.sel15Kres = 1,
|
||||
.clknotstop = 0,
|
||||
.oc_enable = 0,
|
||||
.int_act_high = 0,
|
||||
.int_edge_triggered = 0,
|
||||
.remote_wakeup_connected = 0,
|
||||
.no_power_switching = 1,
|
||||
.power_switching_mode = 0,
|
||||
};
|
||||
|
||||
static struct platform_device isp1362_hcd_device = {
|
||||
.name = "isp1362-hcd",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.platform_data = &isp1362_priv,
|
||||
},
|
||||
.num_resources = ARRAY_SIZE(isp1362_hcd_resources),
|
||||
.resource = isp1362_hcd_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *cm_bf561_devices[] __initdata = {
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
|
||||
&isp1362_hcd_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static int __init cm_bf561_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices));
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(cm_bf561_init);
|
147
arch/blackfin/mach-bf561/boards/ezkit.c
Normal file
147
arch/blackfin/mach-bf561/boards/ezkit.c
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf561/ezkit.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/bfin5xx_spi.h>
|
||||
|
||||
/*
|
||||
* Name the Board for the /proc/cpuinfo
|
||||
*/
|
||||
char *bfin_board_name = "ADDS-BF561-EZKIT";
|
||||
|
||||
/*
|
||||
* USB-LAN EzExtender board
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.name = "smc91x-regs",
|
||||
.start = 0x2C010300,
|
||||
.end = 0x2C010300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
|
||||
.start = IRQ_PF9,
|
||||
.end = IRQ_PF9,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
static struct resource bfin_uart_resources[] = {
|
||||
{
|
||||
.start = 0xFFC00400,
|
||||
.end = 0xFFC004FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device bfin_uart_device = {
|
||||
.name = "bfin-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(bfin_uart_resources),
|
||||
.resource = bfin_uart_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPI_BFIN
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
|
||||
.enable_dma = 0,
|
||||
.bits_per_word = 16,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* SPI controller data */
|
||||
static struct bfin5xx_spi_master spi_bfin_master_info = {
|
||||
.num_chipselect = 8,
|
||||
.enable_dma = 1, /* master has the ability to do dma transfer */
|
||||
};
|
||||
|
||||
static struct platform_device spi_bfin_master_device = {
|
||||
.name = "bfin-spi-master",
|
||||
.id = 1, /* Bus number */
|
||||
.dev = {
|
||||
.platform_data = &spi_bfin_master_info, /* Passed to driver */
|
||||
},
|
||||
};
|
||||
|
||||
static struct spi_board_info bfin_spi_board_info[] __initdata = {
|
||||
#if defined(CONFIG_SND_BLACKFIN_AD1836) \
|
||||
|| defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
|
||||
{
|
||||
.modalias = "ad1836-spi",
|
||||
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
|
||||
.bus_num = 1,
|
||||
.chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
|
||||
.controller_data = &ad1836_spi_chip_info,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct platform_device *ezkit_devices[] __initdata = {
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
|
||||
&spi_bfin_master_device,
|
||||
#endif
|
||||
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
|
||||
&bfin_uart_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init ezkit_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
ret = platform_add_devices(ezkit_devices,
|
||||
ARRAY_SIZE(ezkit_devices));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return spi_register_board_info(bfin_spi_board_info,
|
||||
ARRAY_SIZE(bfin_spi_board_info));
|
||||
}
|
||||
|
||||
arch_initcall(ezkit_init);
|
82
arch/blackfin/mach-bf561/boards/generic_board.c
Normal file
82
arch/blackfin/mach-bf561/boards/generic_board.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf561/generic_board.c
|
||||
* Based on: arch/blackfin/mach-bf533/ezkit.c
|
||||
* Author: Aidan Williams <aidan@nicta.com.au>
|
||||
*
|
||||
* Created:
|
||||
* Description:
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2005 National ICT Australia (NICTA)
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
char *bfin_board_name = "UNKNOWN BOARD";
|
||||
|
||||
/*
|
||||
* Driver needs to know address, irq and flag pin.
|
||||
*/
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
static struct resource smc91x_resources[] = {
|
||||
{
|
||||
.start = 0x2C010300,
|
||||
.end = 0x2C010300 + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},{
|
||||
.start = IRQ_PROG_INTB,
|
||||
.end = IRQ_PROG_INTB,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},{
|
||||
/*
|
||||
* denotes the flag pin and is used directly if
|
||||
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
|
||||
*/
|
||||
.start = IRQ_PF9,
|
||||
.end = IRQ_PF9,
|
||||
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device smc91x_device = {
|
||||
.name = "smc91x",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(smc91x_resources),
|
||||
.resource = smc91x_resources,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_device *generic_board_devices[] __initdata = {
|
||||
#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
|
||||
&smc91x_device,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init generic_board_init(void)
|
||||
{
|
||||
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
|
||||
return platform_add_devices(generic_board_devices,
|
||||
ARRAY_SIZE(generic_board_devices));
|
||||
}
|
||||
|
||||
arch_initcall(generic_board_init);
|
402
arch/blackfin/mach-bf561/coreb.c
Normal file
402
arch/blackfin/mach-bf561/coreb.c
Normal file
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf561/coreb.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: Handle CoreB on a BF561
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define MODULE_VER "v0.1"
|
||||
|
||||
static spinlock_t coreb_lock;
|
||||
static wait_queue_head_t coreb_dma_wait;
|
||||
|
||||
#define COREB_IS_OPEN 0x00000001
|
||||
#define COREB_IS_RUNNING 0x00000010
|
||||
|
||||
#define CMD_COREB_INDEX 1
|
||||
#define CMD_COREB_START 2
|
||||
#define CMD_COREB_STOP 3
|
||||
#define CMD_COREB_RESET 4
|
||||
|
||||
#define COREB_MINOR 229
|
||||
|
||||
static unsigned long coreb_status = 0;
|
||||
static unsigned long coreb_base = 0xff600000;
|
||||
static unsigned long coreb_size = 0x4000;
|
||||
int coreb_dma_done;
|
||||
|
||||
static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
|
||||
static ssize_t coreb_read(struct file *file, char *buf, size_t count,
|
||||
loff_t * ppos);
|
||||
static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t * ppos);
|
||||
static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
static int coreb_open(struct inode *inode, struct file *file);
|
||||
static int coreb_release(struct inode *inode, struct file *file);
|
||||
|
||||
static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
clear_dma_irqstat(CH_MEM_STREAM2_DEST);
|
||||
coreb_dma_done = 1;
|
||||
wake_up_interruptible(&coreb_dma_wait);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
unsigned long p = *ppos;
|
||||
ssize_t wrote = 0;
|
||||
|
||||
if (p + count > coreb_size)
|
||||
return -EFAULT;
|
||||
|
||||
while (count > 0) {
|
||||
int len = count;
|
||||
|
||||
if (len > PAGE_SIZE)
|
||||
len = PAGE_SIZE;
|
||||
|
||||
coreb_dma_done = 0;
|
||||
|
||||
/* Source Channel */
|
||||
set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
|
||||
set_dma_x_count(CH_MEM_STREAM2_SRC, len);
|
||||
set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
|
||||
set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
|
||||
/* Destination Channel */
|
||||
set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
|
||||
set_dma_x_count(CH_MEM_STREAM2_DEST, len);
|
||||
set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
|
||||
set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
|
||||
|
||||
enable_dma(CH_MEM_STREAM2_SRC);
|
||||
enable_dma(CH_MEM_STREAM2_DEST);
|
||||
|
||||
wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
|
||||
|
||||
disable_dma(CH_MEM_STREAM2_SRC);
|
||||
disable_dma(CH_MEM_STREAM2_DEST);
|
||||
|
||||
count -= len;
|
||||
wrote += len;
|
||||
buf += len;
|
||||
p += len;
|
||||
}
|
||||
*ppos = p;
|
||||
return wrote;
|
||||
}
|
||||
|
||||
static ssize_t coreb_read(struct file *file, char *buf, size_t count,
|
||||
loff_t * ppos)
|
||||
{
|
||||
unsigned long p = *ppos;
|
||||
ssize_t read = 0;
|
||||
|
||||
if ((p + count) > coreb_size)
|
||||
return -EFAULT;
|
||||
|
||||
while (count > 0) {
|
||||
int len = count;
|
||||
|
||||
if (len > PAGE_SIZE)
|
||||
len = PAGE_SIZE;
|
||||
|
||||
coreb_dma_done = 0;
|
||||
|
||||
/* Source Channel */
|
||||
set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
|
||||
set_dma_x_count(CH_MEM_STREAM2_SRC, len);
|
||||
set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
|
||||
set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
|
||||
/* Destination Channel */
|
||||
set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
|
||||
set_dma_x_count(CH_MEM_STREAM2_DEST, len);
|
||||
set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
|
||||
set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
|
||||
|
||||
enable_dma(CH_MEM_STREAM2_SRC);
|
||||
enable_dma(CH_MEM_STREAM2_DEST);
|
||||
|
||||
wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
|
||||
|
||||
disable_dma(CH_MEM_STREAM2_SRC);
|
||||
disable_dma(CH_MEM_STREAM2_DEST);
|
||||
|
||||
count -= len;
|
||||
read += len;
|
||||
buf += len;
|
||||
p += len;
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
loff_t ret;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
|
||||
switch (origin) {
|
||||
case 0 /* SEEK_SET */ :
|
||||
if (offset < coreb_size) {
|
||||
file->f_pos = offset;
|
||||
ret = file->f_pos;
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case 1 /* SEEK_CUR */ :
|
||||
if ((offset + file->f_pos) < coreb_size) {
|
||||
file->f_pos += offset;
|
||||
ret = file->f_pos;
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coreb_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock_irq(&coreb_lock);
|
||||
|
||||
if (coreb_status & COREB_IS_OPEN)
|
||||
goto out_busy;
|
||||
|
||||
coreb_status |= COREB_IS_OPEN;
|
||||
|
||||
spin_unlock_irq(&coreb_lock);
|
||||
return 0;
|
||||
|
||||
out_busy:
|
||||
spin_unlock_irq(&coreb_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int coreb_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock_irq(&coreb_lock);
|
||||
coreb_status &= ~COREB_IS_OPEN;
|
||||
spin_unlock_irq(&coreb_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coreb_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int retval = 0;
|
||||
int coreb_index = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case CMD_COREB_INDEX:
|
||||
if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irq(&coreb_lock);
|
||||
switch (coreb_index) {
|
||||
case 0:
|
||||
coreb_base = 0xff600000;
|
||||
coreb_size = 0x4000;
|
||||
break;
|
||||
case 1:
|
||||
coreb_base = 0xff610000;
|
||||
coreb_size = 0x4000;
|
||||
break;
|
||||
case 2:
|
||||
coreb_base = 0xff500000;
|
||||
coreb_size = 0x8000;
|
||||
break;
|
||||
case 3:
|
||||
coreb_base = 0xff400000;
|
||||
coreb_size = 0x8000;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irq(&coreb_lock);
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
file->f_pos = 0;
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
break;
|
||||
case CMD_COREB_START:
|
||||
spin_lock_irq(&coreb_lock);
|
||||
if (coreb_status & COREB_IS_RUNNING) {
|
||||
retval = -EBUSY;
|
||||
break;
|
||||
}
|
||||
printk(KERN_INFO "Starting Core B\n");
|
||||
coreb_status |= COREB_IS_RUNNING;
|
||||
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
|
||||
SSYNC();
|
||||
spin_lock_irq(&coreb_lock);
|
||||
break;
|
||||
#if defined(CONFIG_BF561_COREB_RESET)
|
||||
case CMD_COREB_STOP:
|
||||
spin_lock_irq(&coreb_lock);
|
||||
printk(KERN_INFO "Stopping Core B\n");
|
||||
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
|
||||
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
|
||||
coreb_status &= ~COREB_IS_RUNNING;
|
||||
spin_lock_irq(&coreb_lock);
|
||||
break;
|
||||
case CMD_COREB_RESET:
|
||||
printk(KERN_INFO "Resetting Core B\n");
|
||||
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct file_operations coreb_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = coreb_lseek,
|
||||
.read = coreb_read,
|
||||
.write = coreb_write,
|
||||
.ioctl = coreb_ioctl,
|
||||
.open = coreb_open,
|
||||
.release = coreb_release
|
||||
};
|
||||
|
||||
static struct miscdevice coreb_dev = {
|
||||
COREB_MINOR,
|
||||
"coreb",
|
||||
&coreb_fops
|
||||
};
|
||||
|
||||
static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf,
|
||||
"Base Address:\t0x%08lx\n"
|
||||
"Core B is %s\n"
|
||||
"SICA_SYSCR:\t%04x\n"
|
||||
"SICB_SYSCR:\t%04x\n"
|
||||
"\n"
|
||||
"IRQ Status:\tCore A\t\tCore B\n"
|
||||
"ISR0:\t\t%08x\t\t%08x\n"
|
||||
"ISR1:\t\t%08x\t\t%08x\n"
|
||||
"IMASK0:\t\t%08x\t\t%08x\n"
|
||||
"IMASK1:\t\t%08x\t\t%08x\n",
|
||||
coreb_base,
|
||||
coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
|
||||
bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
|
||||
bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
|
||||
bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
|
||||
bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
|
||||
bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
|
||||
|
||||
int __init bf561_coreb_init(void)
|
||||
{
|
||||
init_waitqueue_head(&coreb_dma_wait);
|
||||
|
||||
spin_lock_init(&coreb_lock);
|
||||
/* Request the core memory regions for Core B */
|
||||
if (request_mem_region(0xff600000, 0x4000,
|
||||
"Core B - Instruction SRAM") == NULL)
|
||||
goto exit;
|
||||
|
||||
if (request_mem_region(0xFF610000, 0x4000,
|
||||
"Core B - Instruction SRAM") == NULL)
|
||||
goto release_instruction_a_sram;
|
||||
|
||||
if (request_mem_region(0xFF500000, 0x8000,
|
||||
"Core B - Data Bank B SRAM") == NULL)
|
||||
goto release_instruction_b_sram;
|
||||
|
||||
if (request_mem_region(0xff400000, 0x8000,
|
||||
"Core B - Data Bank A SRAM") == NULL)
|
||||
goto release_data_b_sram;
|
||||
|
||||
if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
|
||||
goto release_data_a_sram;
|
||||
|
||||
if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
|
||||
goto release_dma_dest;
|
||||
|
||||
set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
|
||||
|
||||
misc_register(&coreb_dev);
|
||||
|
||||
if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
|
||||
goto release_dma_src;
|
||||
|
||||
printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
|
||||
return 0;
|
||||
|
||||
release_dma_src:
|
||||
free_dma(CH_MEM_STREAM2_SRC);
|
||||
release_dma_dest:
|
||||
free_dma(CH_MEM_STREAM2_DEST);
|
||||
release_data_a_sram:
|
||||
release_mem_region(0xff400000, 0x8000);
|
||||
release_data_b_sram:
|
||||
release_mem_region(0xff500000, 0x8000);
|
||||
release_instruction_b_sram:
|
||||
release_mem_region(0xff610000, 0x4000);
|
||||
release_instruction_a_sram:
|
||||
release_mem_region(0xff600000, 0x4000);
|
||||
exit:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void __exit bf561_coreb_exit(void)
|
||||
{
|
||||
device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
|
||||
misc_deregister(&coreb_dev);
|
||||
|
||||
release_mem_region(0xff610000, 0x4000);
|
||||
release_mem_region(0xff600000, 0x4000);
|
||||
release_mem_region(0xff500000, 0x8000);
|
||||
release_mem_region(0xff400000, 0x8000);
|
||||
|
||||
free_dma(CH_MEM_STREAM2_DEST);
|
||||
free_dma(CH_MEM_STREAM2_SRC);
|
||||
}
|
||||
|
||||
module_init(bf561_coreb_init);
|
||||
module_exit(bf561_coreb_exit);
|
||||
|
||||
MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
|
||||
MODULE_DESCRIPTION("BF561 Core B Support");
|
512
arch/blackfin/mach-bf561/head.S
Normal file
512
arch/blackfin/mach-bf561/head.S
Normal file
|
@ -0,0 +1,512 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf561/head.S
|
||||
* Based on: arch/blackfin/mach-bf533/head.S
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: BF561 startup file
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
#include <asm/mach/mem_init.h>
|
||||
#endif
|
||||
|
||||
.global __rambase
|
||||
.global __ramstart
|
||||
.global __ramend
|
||||
.extern ___bss_stop
|
||||
.extern ___bss_start
|
||||
.extern _bf53x_relocate_l1_mem
|
||||
|
||||
#define INITIAL_STACK 0xFFB01000
|
||||
|
||||
.text
|
||||
|
||||
ENTRY(__start)
|
||||
ENTRY(__stext)
|
||||
/* R0: argument of command line string, passed from uboot, save it */
|
||||
R7 = R0;
|
||||
/* Set the SYSCFG register */
|
||||
R0 = 0x36;
|
||||
SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
|
||||
R0 = 0;
|
||||
|
||||
/*Clear Out All the data and pointer Registers*/
|
||||
R1 = R0;
|
||||
R2 = R0;
|
||||
R3 = R0;
|
||||
R4 = R0;
|
||||
R5 = R0;
|
||||
R6 = R0;
|
||||
|
||||
P0 = R0;
|
||||
P1 = R0;
|
||||
P2 = R0;
|
||||
P3 = R0;
|
||||
P4 = R0;
|
||||
P5 = R0;
|
||||
|
||||
LC0 = r0;
|
||||
LC1 = r0;
|
||||
L0 = r0;
|
||||
L1 = r0;
|
||||
L2 = r0;
|
||||
L3 = r0;
|
||||
|
||||
/* Clear Out All the DAG Registers*/
|
||||
B0 = r0;
|
||||
B1 = r0;
|
||||
B2 = r0;
|
||||
B3 = r0;
|
||||
|
||||
I0 = r0;
|
||||
I1 = r0;
|
||||
I2 = r0;
|
||||
I3 = r0;
|
||||
|
||||
M0 = r0;
|
||||
M1 = r0;
|
||||
M2 = r0;
|
||||
M3 = r0;
|
||||
|
||||
/* Turn off the icache */
|
||||
p0.l = (IMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (IMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENICPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Turn off the dcache */
|
||||
p0.l = (DMEM_CONTROL & 0xFFFF);
|
||||
p0.h = (DMEM_CONTROL >> 16);
|
||||
R1 = [p0];
|
||||
R0 = ~ENDCPLB;
|
||||
R0 = R0 & R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
#ifdef ANOMALY_05000125
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
#endif
|
||||
[p0] = R0;
|
||||
SSYNC;
|
||||
#ifdef ANOMALY_05000125
|
||||
STI R2;
|
||||
#endif
|
||||
|
||||
/* Initialise UART*/
|
||||
p0.h = hi(UART_LCR);
|
||||
p0.l = lo(UART_LCR);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable DLL writes */
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLL);
|
||||
p0.l = lo(UART_DLL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_DLH);
|
||||
p0.l = lo(UART_DLH);
|
||||
r0 = 0x00(Z);
|
||||
w[p0] = r0.L;
|
||||
ssync;
|
||||
|
||||
p0.h = hi(UART_GCTL);
|
||||
p0.l = lo(UART_GCTL);
|
||||
r0 = 0x0(Z);
|
||||
w[p0] = r0.L; /* To enable UART clock */
|
||||
ssync;
|
||||
|
||||
/* Initialize stack pointer */
|
||||
sp.l = lo(INITIAL_STACK);
|
||||
sp.h = hi(INITIAL_STACK);
|
||||
fp = sp;
|
||||
usp = sp;
|
||||
|
||||
/* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
|
||||
call _bf53x_relocate_l1_mem;
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
call _start_dma_code;
|
||||
#endif
|
||||
|
||||
/* Code for initializing Async memory banks */
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL1);
|
||||
p2.l = lo(EBIU_AMBCTL1);
|
||||
r0.h = hi(AMBCTL1VAL);
|
||||
r0.l = lo(AMBCTL1VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMBCTL0);
|
||||
p2.l = lo(EBIU_AMBCTL0);
|
||||
r0.h = hi(AMBCTL0VAL);
|
||||
r0.l = lo(AMBCTL0VAL);
|
||||
[p2] = r0;
|
||||
ssync;
|
||||
|
||||
p2.h = hi(EBIU_AMGCTL);
|
||||
p2.l = lo(EBIU_AMGCTL);
|
||||
r0 = AMGCTLVAL;
|
||||
w[p2] = r0;
|
||||
ssync;
|
||||
|
||||
/* This section keeps the processor in supervisor mode
|
||||
* during kernel boot. Switches to user mode at end of boot.
|
||||
* See page 3-9 of Hardware Reference manual for documentation.
|
||||
*/
|
||||
|
||||
/* EVT15 = _real_start */
|
||||
|
||||
p0.l = lo(EVT15);
|
||||
p0.h = hi(EVT15);
|
||||
p1.l = _real_start;
|
||||
p1.h = _real_start;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
p0.l = lo(IMASK);
|
||||
p0.h = hi(IMASK);
|
||||
p1.l = IMASK_IVG15;
|
||||
p1.h = 0x0;
|
||||
[p0] = p1;
|
||||
csync;
|
||||
|
||||
raise 15;
|
||||
p0.l = .LWAIT_HERE;
|
||||
p0.h = .LWAIT_HERE;
|
||||
reti = p0;
|
||||
#if defined(ANOMALY_05000281)
|
||||
nop; nop; nop;
|
||||
#endif
|
||||
rti;
|
||||
|
||||
.LWAIT_HERE:
|
||||
jump .LWAIT_HERE;
|
||||
|
||||
ENTRY(_real_start)
|
||||
[ -- sp ] = reti;
|
||||
p0.l = lo(WDOGA_CTL);
|
||||
p0.h = hi(WDOGA_CTL);
|
||||
r0 = 0xAD6(z);
|
||||
w[p0] = r0; /* watchdog off for now */
|
||||
ssync;
|
||||
|
||||
/* Code update for BSS size == 0
|
||||
* Zero out the bss region.
|
||||
*/
|
||||
|
||||
p1.l = ___bss_start;
|
||||
p1.h = ___bss_start;
|
||||
p2.l = ___bss_stop;
|
||||
p2.h = ___bss_stop;
|
||||
r0 = 0;
|
||||
p2 -= p1;
|
||||
lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
|
||||
.L_clear_bss:
|
||||
B[p1++] = r0;
|
||||
|
||||
/* In case there is a NULL pointer reference
|
||||
* Zero out region before stext
|
||||
*/
|
||||
|
||||
p1.l = 0x0;
|
||||
p1.h = 0x0;
|
||||
r0.l = __stext;
|
||||
r0.h = __stext;
|
||||
r0 = r0 >> 1;
|
||||
p2 = r0;
|
||||
r0 = 0;
|
||||
lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
|
||||
.L_clear_zero:
|
||||
W[p1++] = r0;
|
||||
|
||||
/* pass the uboot arguments to the global value command line */
|
||||
R0 = R7;
|
||||
call _cmdline_init;
|
||||
|
||||
p1.l = __rambase;
|
||||
p1.h = __rambase;
|
||||
r0.l = __sdata;
|
||||
r0.h = __sdata;
|
||||
[p1] = r0;
|
||||
|
||||
p1.l = __ramstart;
|
||||
p1.h = __ramstart;
|
||||
p3.l = ___bss_stop;
|
||||
p3.h = ___bss_stop;
|
||||
|
||||
r1 = p3;
|
||||
[p1] = r1;
|
||||
|
||||
/*
|
||||
* load the current thread pointer and stack
|
||||
*/
|
||||
r1.l = _init_thread_union;
|
||||
r1.h = _init_thread_union;
|
||||
|
||||
r2.l = 0x2000;
|
||||
r2.h = 0x0000;
|
||||
r1 = r1 + r2;
|
||||
sp = r1;
|
||||
usp = sp;
|
||||
fp = sp;
|
||||
call _start_kernel;
|
||||
.L_exit:
|
||||
jump.s .L_exit;
|
||||
|
||||
.section .l1.text
|
||||
#if CONFIG_BFIN_KERNEL_CLOCK
|
||||
ENTRY(_start_dma_code)
|
||||
p0.h = hi(SICA_IWR0);
|
||||
p0.l = lo(SICA_IWR0);
|
||||
r0.l = 0x1;
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/*
|
||||
* Set PLL_CTL
|
||||
* - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
|
||||
* - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
|
||||
* - [7] = output delay (add 200ps of delay to mem signals)
|
||||
* - [6] = input delay (add 200ps of input delay to mem signals)
|
||||
* - [5] = PDWN : 1=All Clocks off
|
||||
* - [3] = STOPCK : 1=Core Clock off
|
||||
* - [1] = PLL_OFF : 1=Disable Power to PLL
|
||||
* - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
|
||||
* all other bits set to zero
|
||||
*/
|
||||
|
||||
p0.h = hi(PLL_LOCKCNT);
|
||||
p0.l = lo(PLL_LOCKCNT);
|
||||
r0 = 0x300(Z);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITSET (R0, 24);
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
|
||||
r0 = r0 << 9; /* Shift it over, */
|
||||
r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
|
||||
r0 = r1 | r0;
|
||||
r1 = PLL_BYPASS; /* Bypass the PLL? */
|
||||
r1 = r1 << 8; /* Shift it over */
|
||||
r0 = r1 | r0; /* add them all together */
|
||||
|
||||
p0.h = hi(PLL_CTL);
|
||||
p0.l = lo(PLL_CTL); /* Load the address */
|
||||
cli r2; /* Disable interrupts */
|
||||
ssync;
|
||||
w[p0] = r0.l; /* Set the value */
|
||||
idle; /* Wait for the PLL to stablize */
|
||||
sti r2; /* Enable interrupts */
|
||||
|
||||
.Lcheck_again:
|
||||
p0.h = hi(PLL_STAT);
|
||||
p0.l = lo(PLL_STAT);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,5);
|
||||
if ! CC jump .Lcheck_again;
|
||||
|
||||
/* Configure SCLK & CCLK Dividers */
|
||||
r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
|
||||
p0.h = hi(PLL_DIV);
|
||||
p0.l = lo(PLL_DIV);
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = lo(EBIU_SDRRC);
|
||||
p0.h = hi(EBIU_SDRRC);
|
||||
r0 = mem_SDRRC;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
p0.l = (EBIU_SDBCTL & 0xFFFF);
|
||||
p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
|
||||
r0 = mem_SDBCTL;
|
||||
w[p0] = r0.l;
|
||||
ssync;
|
||||
|
||||
P2.H = hi(EBIU_SDGCTL);
|
||||
P2.L = lo(EBIU_SDGCTL);
|
||||
R0 = [P2];
|
||||
BITCLR (R0, 24);
|
||||
p0.h = hi(EBIU_SDSTAT);
|
||||
p0.l = lo(EBIU_SDSTAT);
|
||||
r2.l = w[p0];
|
||||
cc = bittst(r2,3);
|
||||
if !cc jump .Lskip;
|
||||
NOP;
|
||||
BITSET (R0, 23);
|
||||
.Lskip:
|
||||
[P2] = R0;
|
||||
SSYNC;
|
||||
|
||||
R0.L = lo(mem_SDGCTL);
|
||||
R0.H = hi(mem_SDGCTL);
|
||||
R1 = [p2];
|
||||
R1 = R1 | R0;
|
||||
[P2] = R1;
|
||||
SSYNC;
|
||||
|
||||
RTS;
|
||||
#endif /* CONFIG_BFIN_KERNEL_CLOCK */
|
||||
|
||||
ENTRY(_bfin_reset)
|
||||
/* No more interrupts to be handled*/
|
||||
CLI R6;
|
||||
SSYNC;
|
||||
|
||||
#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
|
||||
p0.h = hi(FIO_INEN);
|
||||
p0.l = lo(FIO_INEN);
|
||||
r0.l = ~(PF1 | PF0);
|
||||
w[p0] = r0.l;
|
||||
|
||||
p0.h = hi(FIO_DIR);
|
||||
p0.l = lo(FIO_DIR);
|
||||
r0.l = (PF1 | PF0);
|
||||
w[p0] = r0.l;
|
||||
|
||||
p0.h = hi(FIO_FLAG_C);
|
||||
p0.l = lo(FIO_FLAG_C);
|
||||
r0.l = (PF1 | PF0);
|
||||
w[p0] = r0.l;
|
||||
#endif
|
||||
|
||||
/* Clear the bits 13-15 in SWRST if they werent cleared */
|
||||
p0.h = hi(SICA_SWRST);
|
||||
p0.l = lo(SICA_SWRST);
|
||||
csync;
|
||||
r0.l = w[p0];
|
||||
|
||||
/* Clear the IMASK register */
|
||||
p0.h = hi(IMASK);
|
||||
p0.l = lo(IMASK);
|
||||
r0 = 0x0;
|
||||
[p0] = r0;
|
||||
|
||||
/* Clear the ILAT register */
|
||||
p0.h = hi(ILAT);
|
||||
p0.l = lo(ILAT);
|
||||
r0 = [p0];
|
||||
[p0] = r0;
|
||||
SSYNC;
|
||||
|
||||
/* Disable the WDOG TIMER */
|
||||
p0.h = hi(WDOGA_CTL);
|
||||
p0.l = lo(WDOGA_CTL);
|
||||
r0.l = 0xAD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Clear the sticky bit incase it is already set */
|
||||
p0.h = hi(WDOGA_CTL);
|
||||
p0.l = lo(WDOGA_CTL);
|
||||
r0.l = 0x8AD6;
|
||||
w[p0] = r0.l;
|
||||
SSYNC;
|
||||
|
||||
/* Program the count value */
|
||||
R0.l = 0x100;
|
||||
R0.h = 0x0;
|
||||
P0.h = hi(WDOGA_CNT);
|
||||
P0.l = lo(WDOGA_CNT);
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
/* Program WDOG_STAT if necessary */
|
||||
P0.h = hi(WDOGA_CTL);
|
||||
P0.l = lo(WDOGA_CTL);
|
||||
R0 = W[P0](Z);
|
||||
CC = BITTST(R0,1);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
CC = BITTST(R0,2);
|
||||
if !CC JUMP .LWRITESTAT;
|
||||
JUMP .LSKIP_WRITE;
|
||||
|
||||
.LWRITESTAT:
|
||||
/* When watch dog timer is enabled,
|
||||
* a write to STAT will load the contents of CNT to STAT
|
||||
*/
|
||||
R0 = 0x0000(z);
|
||||
P0.h = hi(WDOGA_STAT);
|
||||
P0.l = lo(WDOGA_STAT)
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
.LSKIP_WRITE:
|
||||
/* Enable the reset event */
|
||||
P0.h = hi(WDOGA_CTL);
|
||||
P0.l = lo(WDOGA_CTL);
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,1);
|
||||
BITCLR(R0,2);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
NOP;
|
||||
|
||||
/* Enable the wdog counter */
|
||||
R0 = W[P0](Z);
|
||||
BITCLR(R0,4);
|
||||
W[P0] = R0.L;
|
||||
SSYNC;
|
||||
|
||||
IDLE;
|
||||
|
||||
RTS;
|
||||
|
||||
.data
|
||||
|
||||
/*
|
||||
* Set up the usable of RAM stuff. Size of RAM is determined then
|
||||
* an initial stack set up at the end.
|
||||
*/
|
||||
|
||||
.align 4
|
||||
__rambase:
|
||||
.long 0
|
||||
__ramstart:
|
||||
.long 0
|
||||
__ramend:
|
||||
.long 0
|
108
arch/blackfin/mach-bf561/ints-priority.c
Normal file
108
arch/blackfin/mach-bf561/ints-priority.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-bf561/ints-priority.c
|
||||
* Based on: arch/blackfin/mach-bf537/ints-priority.c
|
||||
* Author: Michael Hennerich
|
||||
*
|
||||
* Created:
|
||||
* Description: Set up the interupt priorities
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
void program_IAR(void)
|
||||
{
|
||||
/* Program the IAR0 Register with the configured priority */
|
||||
bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
|
||||
((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) |
|
||||
((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) |
|
||||
((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) |
|
||||
((CONFIG_IRQ_PPI0_ERROR - 7) << IRQ_PPI0_ERROR_POS) |
|
||||
((CONFIG_IRQ_PPI1_ERROR - 7) << IRQ_PPI1_ERROR_POS) |
|
||||
((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
|
||||
((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS));
|
||||
|
||||
bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
|
||||
((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) |
|
||||
((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) |
|
||||
((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) |
|
||||
((CONFIG_IRQ_DMA1_1 - 7) << IRQ_DMA1_1_POS) |
|
||||
((CONFIG_IRQ_DMA1_2 - 7) << IRQ_DMA1_2_POS) |
|
||||
((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) |
|
||||
((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS));
|
||||
|
||||
bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
|
||||
((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) |
|
||||
((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) |
|
||||
((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) |
|
||||
((CONFIG_IRQ_DMA1_9 - 7) << IRQ_DMA1_9_POS) |
|
||||
((CONFIG_IRQ_DMA1_10 - 7) << IRQ_DMA1_10_POS) |
|
||||
((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) |
|
||||
((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS));
|
||||
|
||||
bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
|
||||
((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) |
|
||||
((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) |
|
||||
((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) |
|
||||
((CONFIG_IRQ_DMA2_5 - 7) << IRQ_DMA2_5_POS) |
|
||||
((CONFIG_IRQ_DMA2_6 - 7) << IRQ_DMA2_6_POS) |
|
||||
((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) |
|
||||
((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS));
|
||||
|
||||
bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
|
||||
((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) |
|
||||
((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) |
|
||||
((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
|
||||
((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) |
|
||||
((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) |
|
||||
((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
|
||||
((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS));
|
||||
|
||||
bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
|
||||
((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
|
||||
((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
|
||||
((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
|
||||
((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) |
|
||||
((CONFIG_IRQ_TIMER10 - 7) << IRQ_TIMER10_POS) |
|
||||
((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) |
|
||||
((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS));
|
||||
|
||||
bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
|
||||
((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) |
|
||||
((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) |
|
||||
((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) |
|
||||
((CONFIG_IRQ_PROG2_INTB - 7) << IRQ_PROG2_INTB_POS) |
|
||||
((CONFIG_IRQ_DMA1_WRRD0 - 7) << IRQ_DMA1_WRRD0_POS) |
|
||||
((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) |
|
||||
((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS));
|
||||
|
||||
bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
|
||||
((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) |
|
||||
((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) |
|
||||
((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) |
|
||||
(0 << IRQ_RESERVED_1_POS) | (0 << IRQ_RESERVED_2_POS) |
|
||||
(0 << IRQ_SUPPLE_0_POS) | (0 << IRQ_SUPPLE_1_POS));
|
||||
|
||||
SSYNC();
|
||||
}
|
12
arch/blackfin/mach-common/Makefile
Normal file
12
arch/blackfin/mach-common/Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# arch/blackfin/mach-common/Makefile
|
||||
#
|
||||
|
||||
obj-y := \
|
||||
cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
|
||||
interrupt.o lock.o dpmc.o irqpanic.o
|
||||
|
||||
obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
|
||||
obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o
|
||||
obj-$(CONFIG_BFIN_DUAL_CORE) += ints-priority-dc.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
253
arch/blackfin/mach-common/cache.S
Normal file
253
arch/blackfin/mach-common/cache.S
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/cache.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created:
|
||||
* Description: cache control support
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
.text
|
||||
.align 2
|
||||
ENTRY(_cache_invalidate)
|
||||
|
||||
/*
|
||||
* Icache or DcacheA or DcacheB Invalidation
|
||||
* or any combination thereof
|
||||
* R0 has bits
|
||||
* CPLB_ENABLE_ICACHE_P,CPLB_ENABLE_DCACHE_P,CPLB_ENABLE_DCACHE2_P
|
||||
* set as required
|
||||
*/
|
||||
[--SP] = R7;
|
||||
|
||||
R7 = R0;
|
||||
CC = BITTST(R7,CPLB_ENABLE_ICACHE_P);
|
||||
IF !CC JUMP .Lno_icache;
|
||||
[--SP] = RETS;
|
||||
CALL _icache_invalidate;
|
||||
RETS = [SP++];
|
||||
.Lno_icache:
|
||||
CC = BITTST(R7,CPLB_ENABLE_DCACHE_P);
|
||||
IF !CC JUMP .Lno_dcache_a;
|
||||
R0 = 0; /* specifies bank A */
|
||||
[--SP] = RETS;
|
||||
CALL _dcache_invalidate;
|
||||
RETS = [SP++];
|
||||
.Lno_dcache_a:
|
||||
CC = BITTST(R7,CPLB_ENABLE_DCACHE2_P);
|
||||
IF !CC JUMP .Lno_dcache_b;
|
||||
R0 = 0;
|
||||
BITSET(R0, 23); /* specifies bank B */
|
||||
[--SP] = RETS;
|
||||
CALL _dcache_invalidate;
|
||||
RETS = [SP++];
|
||||
.Lno_dcache_b:
|
||||
R7 = [SP++];
|
||||
RTS;
|
||||
|
||||
/* Invalidate the Entire Instruction cache by
|
||||
* disabling IMC bit
|
||||
*/
|
||||
ENTRY(_icache_invalidate)
|
||||
ENTRY(_invalidate_entire_icache)
|
||||
[--SP] = ( R7:5);
|
||||
|
||||
P0.L = (IMEM_CONTROL & 0xFFFF);
|
||||
P0.H = (IMEM_CONTROL >> 16);
|
||||
R7 = [P0];
|
||||
|
||||
/* Clear the IMC bit , All valid bits in the instruction
|
||||
* cache are set to the invalid state
|
||||
*/
|
||||
BITCLR(R7,IMC_P);
|
||||
CLI R6;
|
||||
SSYNC; /* SSYNC required before invalidating cache. */
|
||||
.align 8;
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
STI R6;
|
||||
|
||||
/* Configures the instruction cache agian */
|
||||
R6 = (IMC | ENICPLB);
|
||||
R7 = R7 | R6;
|
||||
|
||||
CLI R6;
|
||||
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
STI R6;
|
||||
|
||||
( R7:5) = [SP++];
|
||||
RTS;
|
||||
|
||||
/*
|
||||
* blackfin_cache_flush_range(start, end)
|
||||
* Invalidate all cache lines assocoiated with this
|
||||
* area of memory.
|
||||
*
|
||||
* start: Start address
|
||||
* end: End address
|
||||
*/
|
||||
ENTRY(_blackfin_icache_flush_range)
|
||||
R2 = -L1_CACHE_BYTES;
|
||||
R2 = R0 & R2;
|
||||
P0 = R2;
|
||||
P1 = R1;
|
||||
CSYNC;
|
||||
IFLUSH [P0];
|
||||
1:
|
||||
IFLUSH [P0++];
|
||||
CC = P0 < P1 (iu);
|
||||
IF CC JUMP 1b (bp);
|
||||
IFLUSH [P0];
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
/*
|
||||
* blackfin_icache_dcache_flush_range(start, end)
|
||||
* FLUSH all cache lines assocoiated with this
|
||||
* area of memory.
|
||||
*
|
||||
* start: Start address
|
||||
* end: End address
|
||||
*/
|
||||
|
||||
ENTRY(_blackfin_icache_dcache_flush_range)
|
||||
R2 = -L1_CACHE_BYTES;
|
||||
R2 = R0 & R2;
|
||||
P0 = R2;
|
||||
P1 = R1;
|
||||
CSYNC;
|
||||
IFLUSH [P0];
|
||||
1:
|
||||
FLUSH [P0];
|
||||
IFLUSH [P0++];
|
||||
CC = P0 < P1 (iu);
|
||||
IF CC JUMP 1b (bp);
|
||||
IFLUSH [P0];
|
||||
FLUSH [P0];
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
/* Throw away all D-cached data in specified region without any obligation to
|
||||
* write them back. However, we must clean the D-cached entries around the
|
||||
* boundaries of the start and/or end address is not cache aligned.
|
||||
*
|
||||
* Start: start address,
|
||||
* end : end address.
|
||||
*/
|
||||
|
||||
ENTRY(_blackfin_dcache_invalidate_range)
|
||||
R2 = -L1_CACHE_BYTES;
|
||||
R2 = R0 & R2;
|
||||
P0 = R2;
|
||||
P1 = R1;
|
||||
CSYNC;
|
||||
FLUSHINV[P0];
|
||||
1:
|
||||
FLUSHINV[P0++];
|
||||
CC = P0 < P1 (iu);
|
||||
IF CC JUMP 1b (bp);
|
||||
|
||||
/* If the data crosses a cache line, then we'll be pointing to
|
||||
* the last cache line, but won't have flushed/invalidated it yet,
|
||||
* so do one more.
|
||||
*/
|
||||
FLUSHINV[P0];
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
/* Invalidate the Entire Data cache by
|
||||
* clearing DMC[1:0] bits
|
||||
*/
|
||||
ENTRY(_invalidate_entire_dcache)
|
||||
ENTRY(_dcache_invalidate)
|
||||
[--SP] = ( R7:6);
|
||||
|
||||
P0.L = (DMEM_CONTROL & 0xFFFF);
|
||||
P0.H = (DMEM_CONTROL >> 16);
|
||||
R7 = [P0];
|
||||
|
||||
/* Clear the DMC[1:0] bits, All valid bits in the data
|
||||
* cache are set to the invalid state
|
||||
*/
|
||||
BITCLR(R7,DMC0_P);
|
||||
BITCLR(R7,DMC1_P);
|
||||
CLI R6;
|
||||
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
STI R6;
|
||||
|
||||
/* Configures the data cache again */
|
||||
|
||||
R6 = DMEM_CNTR;
|
||||
R7 = R7 | R6;
|
||||
|
||||
CLI R6;
|
||||
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
STI R6;
|
||||
|
||||
( R7:6) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_blackfin_dcache_flush_range)
|
||||
R2 = -L1_CACHE_BYTES;
|
||||
R2 = R0 & R2;
|
||||
P0 = R2;
|
||||
P1 = R1;
|
||||
CSYNC;
|
||||
FLUSH[P0];
|
||||
1:
|
||||
FLUSH[P0++];
|
||||
CC = P0 < P1 (iu);
|
||||
IF CC JUMP 1b (bp);
|
||||
|
||||
/* If the data crosses a cache line, then we'll be pointing to
|
||||
* the last cache line, but won't have flushed it yet, so do
|
||||
* one more.
|
||||
*/
|
||||
FLUSH[P0];
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
ENTRY(_blackfin_dflush_page)
|
||||
P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
|
||||
P0 = R0;
|
||||
CSYNC;
|
||||
FLUSH[P0];
|
||||
LSETUP (.Lfl1, .Lfl1) LC0 = P1;
|
||||
.Lfl1: FLUSH [P0++];
|
||||
SSYNC;
|
||||
RTS;
|
137
arch/blackfin/mach-common/cacheinit.S
Normal file
137
arch/blackfin/mach-common/cacheinit.S
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/cacheinit.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created: ?
|
||||
* Description: cache initialization
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* This function sets up the data and instruction cache. The
|
||||
* tables like icplb table, dcplb table and Page Descriptor table
|
||||
* are defined in cplbtab.h. You can configure those tables for
|
||||
* your suitable requirements
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
.text
|
||||
|
||||
#if defined(CONFIG_BLKFIN_CACHE)
|
||||
ENTRY(_bfin_icache_init)
|
||||
|
||||
/* Initialize Instruction CPLBS */
|
||||
|
||||
I0.L = (ICPLB_ADDR0 & 0xFFFF);
|
||||
I0.H = (ICPLB_ADDR0 >> 16);
|
||||
|
||||
I1.L = (ICPLB_DATA0 & 0xFFFF);
|
||||
I1.H = (ICPLB_DATA0 >> 16);
|
||||
|
||||
I2.L = _icplb_table;
|
||||
I2.H = _icplb_table;
|
||||
|
||||
r1 = -1; /* end point comparison */
|
||||
r3 = 15; /* max counter */
|
||||
|
||||
/* read entries from table */
|
||||
|
||||
.Lread_iaddr:
|
||||
R0 = [I2++];
|
||||
CC = R0 == R1;
|
||||
IF CC JUMP .Lidone;
|
||||
[I0++] = R0;
|
||||
|
||||
.Lread_idata:
|
||||
R2 = [I2++];
|
||||
[I1++] = R2;
|
||||
R3 = R3 + R1;
|
||||
CC = R3 == R1;
|
||||
IF !CC JUMP .Lread_iaddr;
|
||||
|
||||
.Lidone:
|
||||
/* Enable Instruction Cache */
|
||||
P0.l = (IMEM_CONTROL & 0xFFFF);
|
||||
P0.h = (IMEM_CONTROL >> 16);
|
||||
R1 = [P0];
|
||||
R0 = (IMC | ENICPLB);
|
||||
R0 = R0 | R1;
|
||||
|
||||
/* Anomaly 05000125 */
|
||||
CLI R2;
|
||||
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
STI R2;
|
||||
RTS;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BLKFIN_DCACHE)
|
||||
ENTRY(_bfin_dcache_init)
|
||||
|
||||
/* Initialize Data CPLBS */
|
||||
|
||||
I0.L = (DCPLB_ADDR0 & 0xFFFF);
|
||||
I0.H = (DCPLB_ADDR0 >> 16);
|
||||
|
||||
I1.L = (DCPLB_DATA0 & 0xFFFF);
|
||||
I1.H = (DCPLB_DATA0 >> 16);
|
||||
|
||||
I2.L = _dcplb_table;
|
||||
I2.H = _dcplb_table;
|
||||
|
||||
R1 = -1; /* end point comparison */
|
||||
R3 = 15; /* max counter */
|
||||
|
||||
/* read entries from table */
|
||||
.Lread_daddr:
|
||||
R0 = [I2++];
|
||||
cc = R0 == R1;
|
||||
IF CC JUMP .Lddone;
|
||||
[I0++] = R0;
|
||||
|
||||
.Lread_ddata:
|
||||
R2 = [I2++];
|
||||
[I1++] = R2;
|
||||
R3 = R3 + R1;
|
||||
CC = R3 == R1;
|
||||
IF !CC JUMP .Lread_daddr;
|
||||
.Lddone:
|
||||
P0.L = (DMEM_CONTROL & 0xFFFF);
|
||||
P0.H = (DMEM_CONTROL >> 16);
|
||||
R1 = [P0];
|
||||
|
||||
R0 = DMEM_CNTR;
|
||||
|
||||
R0 = R0 | R1;
|
||||
/* Anomaly 05000125 */
|
||||
CLI R2;
|
||||
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
STI R2;
|
||||
RTS;
|
||||
#endif
|
130
arch/blackfin/mach-common/cplbhdlr.S
Normal file
130
arch/blackfin/mach-common/cplbhdlr.S
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/cplbhdlr.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created: ?
|
||||
* Description: CPLB exception handler
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/entry.h>
|
||||
|
||||
#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.type _cplb_mgr, STT_FUNC;
|
||||
.type _panic_cplb_error, STT_FUNC;
|
||||
|
||||
.align 2
|
||||
|
||||
.global __cplb_hdr;
|
||||
.type __cplb_hdr, STT_FUNC;
|
||||
ENTRY(__cplb_hdr)
|
||||
R2 = SEQSTAT;
|
||||
|
||||
/* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
|
||||
R2 <<= 26;
|
||||
R2 >>= 26;
|
||||
|
||||
R1 = 0x23; /* Data access CPLB protection violation */
|
||||
CC = R2 == R1;
|
||||
IF !CC JUMP .Lnot_data_write;
|
||||
R0 = 2; /* is a write to data space*/
|
||||
JUMP .Lis_icplb_miss;
|
||||
|
||||
.Lnot_data_write:
|
||||
R1 = 0x2C; /* CPLB miss on an instruction fetch */
|
||||
CC = R2 == R1;
|
||||
R0 = 0; /* is_data_miss == False*/
|
||||
IF CC JUMP .Lis_icplb_miss;
|
||||
|
||||
R1 = 0x26;
|
||||
CC = R2 == R1;
|
||||
IF !CC JUMP .Lunknown;
|
||||
|
||||
R0 = 1; /* is_data_miss == True*/
|
||||
|
||||
.Lis_icplb_miss:
|
||||
|
||||
#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE)
|
||||
# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE)
|
||||
R1 = CPLB_ENABLE_ICACHE;
|
||||
# endif
|
||||
# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
|
||||
R1 = CPLB_ENABLE_DCACHE;
|
||||
# endif
|
||||
# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
|
||||
R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
|
||||
# endif
|
||||
#else
|
||||
R1 = 0;
|
||||
#endif
|
||||
|
||||
[--SP] = RETS;
|
||||
CALL _cplb_mgr;
|
||||
RETS = [SP++];
|
||||
CC = R0 == 0;
|
||||
IF !CC JUMP .Lnot_replaced;
|
||||
RTS;
|
||||
|
||||
/*
|
||||
* Diagnostic exception handlers
|
||||
*/
|
||||
.Lunknown:
|
||||
R0 = CPLB_UNKNOWN_ERR;
|
||||
JUMP .Lcplb_error;
|
||||
|
||||
.Lnot_replaced:
|
||||
CC = R0 == CPLB_NO_UNLOCKED;
|
||||
IF !CC JUMP .Lnext_check;
|
||||
R0 = CPLB_NO_UNLOCKED;
|
||||
JUMP .Lcplb_error;
|
||||
|
||||
.Lnext_check:
|
||||
CC = R0 == CPLB_NO_ADDR_MATCH;
|
||||
IF !CC JUMP .Lnext_check2;
|
||||
R0 = CPLB_NO_ADDR_MATCH;
|
||||
JUMP .Lcplb_error;
|
||||
|
||||
.Lnext_check2:
|
||||
CC = R0 == CPLB_PROT_VIOL;
|
||||
IF !CC JUMP .Lstrange_return_from_cplb_mgr;
|
||||
R0 = CPLB_PROT_VIOL;
|
||||
JUMP .Lcplb_error;
|
||||
|
||||
.Lstrange_return_from_cplb_mgr:
|
||||
IDLE;
|
||||
CSYNC;
|
||||
JUMP .Lstrange_return_from_cplb_mgr;
|
||||
|
||||
.Lcplb_error:
|
||||
R1 = sp;
|
||||
SP += -12;
|
||||
call _panic_cplb_error;
|
||||
SP += 12;
|
||||
JUMP _handle_bad_cplb;
|
211
arch/blackfin/mach-common/cplbinfo.c
Normal file
211
arch/blackfin/mach-common/cplbinfo.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/cplbinfo.c
|
||||
* Based on:
|
||||
* Author: Sonic Zhang <sonic.zhang@analog.com>
|
||||
*
|
||||
* Created: Jan. 2005
|
||||
* Description: Display CPLB status
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <asm/current.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
#define CPLB_I 1
|
||||
#define CPLB_D 2
|
||||
|
||||
#define SYNC_SYS SSYNC()
|
||||
#define SYNC_CORE CSYNC()
|
||||
|
||||
#define CPLB_BIT_PAGESIZE 0x30000
|
||||
|
||||
static int page_size_table[4] = {
|
||||
0x00000400, /* 1K */
|
||||
0x00001000, /* 4K */
|
||||
0x00100000, /* 1M */
|
||||
0x00400000 /* 4M */
|
||||
};
|
||||
|
||||
static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
|
||||
|
||||
static int cplb_find_entry(unsigned long *cplb_addr,
|
||||
unsigned long *cplb_data, unsigned long addr,
|
||||
unsigned long data)
|
||||
{
|
||||
int ii;
|
||||
|
||||
for (ii = 0; ii < 16; ii++)
|
||||
if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
|
||||
page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
|
||||
&& (cplb_data[ii] == data))
|
||||
return ii;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *cplb_print_entry(char *buf, int type)
|
||||
{
|
||||
unsigned long *p_addr = dpdt_table;
|
||||
unsigned long *p_data = dpdt_table + 1;
|
||||
unsigned long *p_icount = dpdt_swapcount_table;
|
||||
unsigned long *p_ocount = dpdt_swapcount_table + 1;
|
||||
unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
|
||||
unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
|
||||
int entry = 0, used_cplb = 0;
|
||||
|
||||
if (type == CPLB_I) {
|
||||
buf += sprintf(buf, "Instrction CPLB entry:\n");
|
||||
p_addr = ipdt_table;
|
||||
p_data = ipdt_table + 1;
|
||||
p_icount = ipdt_swapcount_table;
|
||||
p_ocount = ipdt_swapcount_table + 1;
|
||||
cplb_addr = (unsigned long *)ICPLB_ADDR0;
|
||||
cplb_data = (unsigned long *)ICPLB_DATA0;
|
||||
} else
|
||||
buf += sprintf(buf, "Data CPLB entry:\n");
|
||||
|
||||
buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\
|
||||
\tiCount\toCount\n");
|
||||
|
||||
while (*p_addr != 0xffffffff) {
|
||||
entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
|
||||
if (entry >= 0)
|
||||
used_cplb |= 1 << entry;
|
||||
|
||||
buf +=
|
||||
sprintf(buf,
|
||||
"0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
|
||||
*p_addr, *p_data,
|
||||
page_size_string_table[(*p_data & 0x30000) >> 16],
|
||||
(*p_data & CPLB_VALID) ? 'Y' : 'N',
|
||||
(*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
|
||||
*p_ocount);
|
||||
|
||||
p_addr += 2;
|
||||
p_data += 2;
|
||||
p_icount += 2;
|
||||
p_ocount += 2;
|
||||
}
|
||||
|
||||
if (used_cplb != 0xffff) {
|
||||
buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
|
||||
|
||||
for (entry = 0; entry < 16; entry++)
|
||||
if (0 == ((1 << entry) & used_cplb)) {
|
||||
int flags = cplb_data[entry];
|
||||
buf +=
|
||||
sprintf(buf,
|
||||
"%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
|
||||
entry, cplb_addr[entry], flags,
|
||||
page_size_string_table[(flags &
|
||||
0x30000) >>
|
||||
16],
|
||||
(flags & CPLB_VALID) ? 'Y' : 'N',
|
||||
(flags & CPLB_LOCK) ? 'Y' : 'N');
|
||||
}
|
||||
}
|
||||
|
||||
buf += sprintf(buf, "\n");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int cplbinfo_proc_output(char *buf)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = buf;
|
||||
|
||||
p += sprintf(p,
|
||||
"------------------ CPLB Information ------------------\n\n");
|
||||
|
||||
if (bfin_read_IMEM_CONTROL() & ENICPLB)
|
||||
p = cplb_print_entry(p, CPLB_I);
|
||||
else
|
||||
p += sprintf(p, "Instruction CPLB is disabled.\n\n");
|
||||
|
||||
if (bfin_read_DMEM_CONTROL() & ENDCPLB)
|
||||
p = cplb_print_entry(p, CPLB_D);
|
||||
else
|
||||
p += sprintf(p, "Data CPLB is disabled.\n");
|
||||
|
||||
return p - buf;
|
||||
}
|
||||
|
||||
static int cplbinfo_read_proc(char *page, char **start, off_t off,
|
||||
int count, int *eof, void *data)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = cplbinfo_proc_output(page);
|
||||
if (len <= off + count)
|
||||
*eof = 1;
|
||||
*start = page + off;
|
||||
len -= off;
|
||||
if (len > count)
|
||||
len = count;
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
|
||||
unsigned long count, void *data)
|
||||
{
|
||||
printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
|
||||
memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
|
||||
memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int __init cplbinfo_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
if ((entry = create_proc_entry("cplbinfo", 0, NULL)) == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
entry->read_proc = cplbinfo_read_proc;
|
||||
entry->write_proc = cplbinfo_write_proc;
|
||||
entry->data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit cplbinfo_exit(void)
|
||||
{
|
||||
remove_proc_entry("cplbinfo", NULL);
|
||||
}
|
||||
|
||||
module_init(cplbinfo_init);
|
||||
module_exit(cplbinfo_exit);
|
607
arch/blackfin/mach-common/cplbmgr.S
Normal file
607
arch/blackfin/mach-common/cplbmgr.S
Normal file
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/cplbmgtr.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created: ?
|
||||
* Description: CPLB replacement routine for CPLB mismatch
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
|
||||
* is_data_miss==2 => Mark as Dirty, write to the clean data page
|
||||
* is_data_miss==1 => Replace a data CPLB.
|
||||
* is_data_miss==0 => Replace an instruction CPLB.
|
||||
*
|
||||
* Returns:
|
||||
* CPLB_RELOADED => Successfully updated CPLB table.
|
||||
* CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted.
|
||||
* This indicates that the CPLBs in the configuration
|
||||
* tablei are badly configured, as this should never
|
||||
* occur.
|
||||
* CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the
|
||||
* exception, is not covered by any of the CPLBs in
|
||||
* the configuration table. The application is
|
||||
* presumably misbehaving.
|
||||
* CPLB_PROT_VIOL => The address being accessed, that triggered the
|
||||
* exception, was not a first-write to a clean Write
|
||||
* Back Data page, and so presumably is a genuine
|
||||
* violation of the page's protection attributes.
|
||||
* The application is misbehaving.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/cplb.h>
|
||||
|
||||
#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 2;
|
||||
ENTRY(_cplb_mgr)
|
||||
|
||||
[--SP]=( R7:4,P5:3 );
|
||||
|
||||
CC = R0 == 2;
|
||||
IF CC JUMP .Ldcplb_write;
|
||||
|
||||
CC = R0 == 0;
|
||||
IF !CC JUMP .Ldcplb_miss_compare;
|
||||
|
||||
/* ICPLB Miss Exception. We need to choose one of the
|
||||
* currently-installed CPLBs, and replace it with one
|
||||
* from the configuration table.
|
||||
*/
|
||||
|
||||
P4.L = (ICPLB_FAULT_ADDR & 0xFFFF);
|
||||
P4.H = (ICPLB_FAULT_ADDR >> 16);
|
||||
|
||||
P1 = 16;
|
||||
P5.L = _page_size_table;
|
||||
P5.H = _page_size_table;
|
||||
|
||||
P0.L = (ICPLB_DATA0 & 0xFFFF);
|
||||
P0.H = (ICPLB_DATA0 >> 16);
|
||||
R4 = [P4]; /* Get faulting address*/
|
||||
R6 = 64; /* Advance past the fault address, which*/
|
||||
R6 = R6 + R4; /* we'll use if we find a match*/
|
||||
R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/
|
||||
|
||||
R5 = 0;
|
||||
.Lisearch:
|
||||
|
||||
R1 = [P0-0x100]; /* Address for this CPLB */
|
||||
|
||||
R0 = [P0++]; /* Info for this CPLB*/
|
||||
CC = BITTST(R0,0); /* Is the CPLB valid?*/
|
||||
IF !CC JUMP .Lnomatch; /* Skip it, if not.*/
|
||||
CC = R4 < R1(IU); /* If fault address less than page start*/
|
||||
IF CC JUMP .Lnomatch; /* then skip this one.*/
|
||||
R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/
|
||||
P1 = R2;
|
||||
P1 = P5 + (P1<<2); /* index into page-size table*/
|
||||
R2 = [P1]; /* Get the page size*/
|
||||
R1 = R1 + R2; /* and add to page start, to get page end*/
|
||||
CC = R4 < R1(IU); /* and see whether fault addr is in page.*/
|
||||
IF !CC R4 = R6; /* If so, advance the address and finish loop.*/
|
||||
IF !CC JUMP .Lisearch_done;
|
||||
.Lnomatch:
|
||||
/* Go around again*/
|
||||
R5 += 1;
|
||||
CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/
|
||||
IF !CC JUMP .Lisearch;
|
||||
|
||||
.Lisearch_done:
|
||||
I0 = R4; /* Fault address we'll search for*/
|
||||
|
||||
/* set up pointers */
|
||||
P0.L = (ICPLB_DATA0 & 0xFFFF);
|
||||
P0.H = (ICPLB_DATA0 >> 16);
|
||||
|
||||
/* The replacement procedure for ICPLBs */
|
||||
|
||||
P4.L = (IMEM_CONTROL & 0xFFFF);
|
||||
P4.H = (IMEM_CONTROL >> 16);
|
||||
|
||||
/* disable cplbs */
|
||||
R5 = [P4]; /* Control Register*/
|
||||
BITCLR(R5,ENICPLB_P);
|
||||
CLI R1;
|
||||
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P4] = R5;
|
||||
SSYNC;
|
||||
STI R1;
|
||||
|
||||
R1 = -1; /* end point comparison */
|
||||
R3 = 16; /* counter */
|
||||
|
||||
/* Search through CPLBs for first non-locked entry */
|
||||
/* Overwrite it by moving everyone else up by 1 */
|
||||
.Licheck_lock:
|
||||
R0 = [P0++];
|
||||
R3 = R3 + R1;
|
||||
CC = R3 == R1;
|
||||
IF CC JUMP .Lall_locked;
|
||||
CC = BITTST(R0, 0); /* an invalid entry is good */
|
||||
IF !CC JUMP .Lifound_victim;
|
||||
CC = BITTST(R0,1); /* but a locked entry isn't */
|
||||
IF CC JUMP .Licheck_lock;
|
||||
|
||||
.Lifound_victim:
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
R7 = [P0 - 0x104];
|
||||
P2.L = _ipdt_table;
|
||||
P2.H = _ipdt_table;
|
||||
P3.L = _ipdt_swapcount_table;
|
||||
P3.H = _ipdt_swapcount_table;
|
||||
P3 += -4;
|
||||
.Licount:
|
||||
R2 = [P2]; /* address from config table */
|
||||
P2 += 8;
|
||||
P3 += 8;
|
||||
CC = R2==-1;
|
||||
IF CC JUMP .Licount_done;
|
||||
CC = R7==R2;
|
||||
IF !CC JUMP .Licount;
|
||||
R7 = [P3];
|
||||
R7 += 1;
|
||||
[P3] = R7;
|
||||
CSYNC;
|
||||
.Licount_done:
|
||||
#endif
|
||||
LC0=R3;
|
||||
LSETUP(.Lis_move,.Lie_move) LC0;
|
||||
.Lis_move:
|
||||
R0 = [P0];
|
||||
[P0 - 4] = R0;
|
||||
R0 = [P0 - 0x100];
|
||||
[P0-0x104] = R0;
|
||||
.Lie_move:P0+=4;
|
||||
|
||||
/* We've made space in the ICPLB table, so that ICPLB15
|
||||
* is now free to be overwritten. Next, we have to determine
|
||||
* which CPLB we need to install, from the configuration
|
||||
* table. This is a matter of getting the start-of-page
|
||||
* addresses and page-lengths from the config table, and
|
||||
* determining whether the fault address falls within that
|
||||
* range.
|
||||
*/
|
||||
|
||||
P2.L = _ipdt_table;
|
||||
P2.H = _ipdt_table;
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
P3.L = _ipdt_swapcount_table;
|
||||
P3.H = _ipdt_swapcount_table;
|
||||
P3 += -8;
|
||||
#endif
|
||||
P0.L = _page_size_table;
|
||||
P0.H = _page_size_table;
|
||||
|
||||
/* Retrieve our fault address (which may have been advanced
|
||||
* because the faulting instruction crossed a page boundary).
|
||||
*/
|
||||
|
||||
R0 = I0;
|
||||
|
||||
/* An extraction pattern, to get the page-size bits from
|
||||
* the CPLB data entry. Bits 16-17, so two bits at posn 16.
|
||||
*/
|
||||
|
||||
R1 = ((16<<8)|2);
|
||||
.Linext: R4 = [P2++]; /* address from config table */
|
||||
R2 = [P2++]; /* data from config table */
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
P3 += 8;
|
||||
#endif
|
||||
|
||||
CC = R4 == -1; /* End of config table*/
|
||||
IF CC JUMP .Lno_page_in_table;
|
||||
|
||||
/* See if failed address > start address */
|
||||
CC = R4 <= R0(IU);
|
||||
IF !CC JUMP .Linext;
|
||||
|
||||
/* extract page size (17:16)*/
|
||||
R3 = EXTRACT(R2, R1.L) (Z);
|
||||
|
||||
/* add page size to addr to get range */
|
||||
|
||||
P5 = R3;
|
||||
P5 = P0 + (P5 << 2); /* scaled, for int access*/
|
||||
R3 = [P5];
|
||||
R3 = R3 + R4;
|
||||
|
||||
/* See if failed address < (start address + page size) */
|
||||
CC = R0 < R3(IU);
|
||||
IF !CC JUMP .Linext;
|
||||
|
||||
/* We've found a CPLB in the config table that covers
|
||||
* the faulting address, so install this CPLB into the
|
||||
* last entry of the table.
|
||||
*/
|
||||
|
||||
P1.L = (ICPLB_DATA15 & 0xFFFF); /* ICPLB_DATA15 */
|
||||
P1.H = (ICPLB_DATA15 >> 16);
|
||||
[P1] = R2;
|
||||
[P1-0x100] = R4;
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
R3 = [P3];
|
||||
R3 += 1;
|
||||
[P3] = R3;
|
||||
#endif
|
||||
|
||||
/* P4 points to IMEM_CONTROL, and R5 contains its old
|
||||
* value, after we disabled ICPLBS. Re-enable them.
|
||||
*/
|
||||
|
||||
BITSET(R5,ENICPLB_P);
|
||||
CLI R2;
|
||||
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P4] = R5;
|
||||
SSYNC;
|
||||
STI R2;
|
||||
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_RELOADED;
|
||||
RTS;
|
||||
|
||||
/* FAILED CASES*/
|
||||
.Lno_page_in_table:
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_NO_ADDR_MATCH;
|
||||
RTS;
|
||||
.Lall_locked:
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_NO_UNLOCKED;
|
||||
RTS;
|
||||
.Lprot_violation:
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_PROT_VIOL;
|
||||
RTS;
|
||||
|
||||
.Ldcplb_write:
|
||||
|
||||
/* if a DCPLB is marked as write-back (CPLB_WT==0), and
|
||||
* it is clean (CPLB_DIRTY==0), then a write to the
|
||||
* CPLB's page triggers a protection violation. We have to
|
||||
* mark the CPLB as dirty, to indicate that there are
|
||||
* pending writes associated with the CPLB.
|
||||
*/
|
||||
|
||||
P4.L = (DCPLB_STATUS & 0xFFFF);
|
||||
P4.H = (DCPLB_STATUS >> 16);
|
||||
P3.L = (DCPLB_DATA0 & 0xFFFF);
|
||||
P3.H = (DCPLB_DATA0 >> 16);
|
||||
R5 = [P4];
|
||||
|
||||
/* A protection violation can be caused by more than just writes
|
||||
* to a clean WB page, so we have to ensure that:
|
||||
* - It's a write
|
||||
* - to a clean WB page
|
||||
* - and is allowed in the mode the access occurred.
|
||||
*/
|
||||
|
||||
CC = BITTST(R5, 16); /* ensure it was a write*/
|
||||
IF !CC JUMP .Lprot_violation;
|
||||
|
||||
/* to check the rest, we have to retrieve the DCPLB.*/
|
||||
|
||||
/* The low half of DCPLB_STATUS is a bit mask*/
|
||||
|
||||
R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
|
||||
R3 = 30; /* so we can use this to determine the offset*/
|
||||
R2.L = SIGNBITS R2;
|
||||
R2 = R2.L (Z); /* into the DCPLB table.*/
|
||||
R3 = R3 - R2;
|
||||
P4 = R3;
|
||||
P3 = P3 + (P4<<2);
|
||||
R3 = [P3]; /* Retrieve the CPLB*/
|
||||
|
||||
/* Now we can check whether it's a clean WB page*/
|
||||
|
||||
CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
|
||||
IF CC JUMP .Lprot_violation;
|
||||
CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
|
||||
IF CC JUMP .Lprot_violation;
|
||||
|
||||
/* Check whether the write is allowed in the mode that was active.*/
|
||||
|
||||
R2 = 1<<3; /* checking write in user mode*/
|
||||
CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
|
||||
R5 = CC;
|
||||
R2 <<= R5; /* if was super, check write in super mode*/
|
||||
R2 = R3 & R2;
|
||||
CC = R2 == 0;
|
||||
IF CC JUMP .Lprot_violation;
|
||||
|
||||
/* It's a genuine write-to-clean-page.*/
|
||||
|
||||
BITSET(R3, 7); /* mark as dirty*/
|
||||
[P3] = R3; /* and write back.*/
|
||||
NOP;
|
||||
CSYNC;
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_RELOADED;
|
||||
RTS;
|
||||
|
||||
.Ldcplb_miss_compare:
|
||||
|
||||
/* Data CPLB Miss event. We need to choose a CPLB to
|
||||
* evict, and then locate a new CPLB to install from the
|
||||
* config table, that covers the faulting address.
|
||||
*/
|
||||
|
||||
P1.L = (DCPLB_DATA15 & 0xFFFF);
|
||||
P1.H = (DCPLB_DATA15 >> 16);
|
||||
|
||||
P4.L = (DCPLB_FAULT_ADDR & 0xFFFF);
|
||||
P4.H = (DCPLB_FAULT_ADDR >> 16);
|
||||
R4 = [P4];
|
||||
I0 = R4;
|
||||
|
||||
/* The replacement procedure for DCPLBs*/
|
||||
|
||||
R6 = R1; /* Save for later*/
|
||||
|
||||
/* Turn off CPLBs while we work.*/
|
||||
P4.L = (DMEM_CONTROL & 0xFFFF);
|
||||
P4.H = (DMEM_CONTROL >> 16);
|
||||
R5 = [P4];
|
||||
BITCLR(R5,ENDCPLB_P);
|
||||
CLI R0;
|
||||
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P4] = R5;
|
||||
SSYNC;
|
||||
STI R0;
|
||||
|
||||
/* Start looking for a CPLB to evict. Our order of preference
|
||||
* is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
|
||||
* are no good.
|
||||
*/
|
||||
|
||||
I1.L = (DCPLB_DATA0 & 0xFFFF);
|
||||
I1.H = (DCPLB_DATA0 >> 16);
|
||||
P1 = 2;
|
||||
P2 = 16;
|
||||
I2.L = _dcplb_preference;
|
||||
I2.H = _dcplb_preference;
|
||||
LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
|
||||
.Lsdsearch1:
|
||||
R0 = [I2++]; /* Get the bits we're interested in*/
|
||||
P0 = I1; /* Go back to start of table*/
|
||||
LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
|
||||
.Lsdsearch2:
|
||||
R1 = [P0++]; /* Fetch each installed CPLB in turn*/
|
||||
R2 = R1 & R0; /* and test for interesting bits.*/
|
||||
CC = R2 == 0; /* If none are set, it'll do.*/
|
||||
IF !CC JUMP .Lskip_stack_check;
|
||||
|
||||
R2 = [P0 - 0x104]; /* R2 - PageStart */
|
||||
P3.L = _page_size_table; /* retrieve end address */
|
||||
P3.H = _page_size_table; /* retrieve end address */
|
||||
R3 = 0x1002; /* 16th - position, 2 bits -length */
|
||||
#ifdef ANOMALY_05000209
|
||||
nop; /* Anomaly 05000209 */
|
||||
#endif
|
||||
R7 = EXTRACT(R1,R3.l);
|
||||
R7 = R7 << 2; /* Page size index offset */
|
||||
P5 = R7;
|
||||
P3 = P3 + P5;
|
||||
R7 = [P3]; /* page size in bytes */
|
||||
|
||||
R7 = R2 + R7; /* R7 - PageEnd */
|
||||
R4 = SP; /* Test SP is in range */
|
||||
|
||||
CC = R7 < R4; /* if PageEnd < SP */
|
||||
IF CC JUMP .Ldfound_victim;
|
||||
R3 = 0x284; /* stack length from start of trap till
|
||||
* the point.
|
||||
* 20 stack locations for future modifications
|
||||
*/
|
||||
R4 = R4 + R3;
|
||||
CC = R4 < R2; /* if SP + stacklen < PageStart */
|
||||
IF CC JUMP .Ldfound_victim;
|
||||
.Lskip_stack_check:
|
||||
|
||||
.Ledsearch2: NOP;
|
||||
.Ledsearch1: NOP;
|
||||
|
||||
/* If we got here, we didn't find a DCPLB we considered
|
||||
* replacable, which means all of them were locked.
|
||||
*/
|
||||
|
||||
JUMP .Lall_locked;
|
||||
.Ldfound_victim:
|
||||
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
R7 = [P0 - 0x104];
|
||||
P2.L = _dpdt_table;
|
||||
P2.H = _dpdt_table;
|
||||
P3.L = _dpdt_swapcount_table;
|
||||
P3.H = _dpdt_swapcount_table;
|
||||
P3 += -4;
|
||||
.Ldicount:
|
||||
R2 = [P2];
|
||||
P2 += 8;
|
||||
P3 += 8;
|
||||
CC = R2==-1;
|
||||
IF CC JUMP .Ldicount_done;
|
||||
CC = R7==R2;
|
||||
IF !CC JUMP .Ldicount;
|
||||
R7 = [P3];
|
||||
R7 += 1;
|
||||
[P3] = R7;
|
||||
.Ldicount_done:
|
||||
#endif
|
||||
|
||||
/* Clean down the hardware loops*/
|
||||
R2 = 0;
|
||||
LC1 = R2;
|
||||
LC0 = R2;
|
||||
|
||||
/* There's a suitable victim in [P0-4] (because we've
|
||||
* advanced already).
|
||||
*/
|
||||
|
||||
.LDdoverwrite:
|
||||
|
||||
/* [P0-4] is a suitable victim CPLB, so we want to
|
||||
* overwrite it by moving all the following CPLBs
|
||||
* one space closer to the start.
|
||||
*/
|
||||
|
||||
R1.L = (DCPLB_DATA16 & 0xFFFF); /* DCPLB_DATA15 + 4 */
|
||||
R1.H = (DCPLB_DATA16 >> 16);
|
||||
R0 = P0;
|
||||
|
||||
/* If the victim happens to be in DCPLB15,
|
||||
* we don't need to move anything.
|
||||
*/
|
||||
|
||||
CC = R1 == R0;
|
||||
IF CC JUMP .Lde_moved;
|
||||
R1 = R1 - R0;
|
||||
R1 >>= 2;
|
||||
P1 = R1;
|
||||
LSETUP(.Lds_move, .Lde_move) LC0=P1;
|
||||
.Lds_move:
|
||||
R0 = [P0++]; /* move data */
|
||||
[P0 - 8] = R0;
|
||||
R0 = [P0-0x104] /* move address */
|
||||
.Lde_move: [P0-0x108] = R0;
|
||||
|
||||
/* We've now made space in DCPLB15 for the new CPLB to be
|
||||
* installed. The next stage is to locate a CPLB in the
|
||||
* config table that covers the faulting address.
|
||||
*/
|
||||
|
||||
.Lde_moved:NOP;
|
||||
R0 = I0; /* Our faulting address */
|
||||
|
||||
P2.L = _dpdt_table;
|
||||
P2.H = _dpdt_table;
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
P3.L = _dpdt_swapcount_table;
|
||||
P3.H = _dpdt_swapcount_table;
|
||||
P3 += -8;
|
||||
#endif
|
||||
|
||||
P1.L = _page_size_table;
|
||||
P1.H = _page_size_table;
|
||||
|
||||
/* An extraction pattern, to retrieve bits 17:16.*/
|
||||
|
||||
R1 = (16<<8)|2;
|
||||
.Ldnext: R4 = [P2++]; /* address */
|
||||
R2 = [P2++]; /* data */
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
P3 += 8;
|
||||
#endif
|
||||
|
||||
CC = R4 == -1;
|
||||
IF CC JUMP .Lno_page_in_table;
|
||||
|
||||
/* See if failed address > start address */
|
||||
CC = R4 <= R0(IU);
|
||||
IF !CC JUMP .Ldnext;
|
||||
|
||||
/* extract page size (17:16)*/
|
||||
R3 = EXTRACT(R2, R1.L) (Z);
|
||||
|
||||
/* add page size to addr to get range */
|
||||
|
||||
P5 = R3;
|
||||
P5 = P1 + (P5 << 2);
|
||||
R3 = [P5];
|
||||
R3 = R3 + R4;
|
||||
|
||||
/* See if failed address < (start address + page size) */
|
||||
CC = R0 < R3(IU);
|
||||
IF !CC JUMP .Ldnext;
|
||||
|
||||
/* We've found the CPLB that should be installed, so
|
||||
* write it into CPLB15, masking off any caching bits
|
||||
* if necessary.
|
||||
*/
|
||||
|
||||
P1.L = (DCPLB_DATA15 & 0xFFFF);
|
||||
P1.H = (DCPLB_DATA15 >> 16);
|
||||
|
||||
/* If the DCPLB has cache bits set, but caching hasn't
|
||||
* been enabled, then we want to mask off the cache-in-L1
|
||||
* bit before installing. Moreover, if caching is off, we
|
||||
* also want to ensure that the DCPLB has WT mode set, rather
|
||||
* than WB, since WB pages still trigger first-write exceptions
|
||||
* even when not caching is off, and the page isn't marked as
|
||||
* cachable. Finally, we could mark the page as clean, not dirty,
|
||||
* but we choose to leave that decision to the user; if the user
|
||||
* chooses to have a CPLB pre-defined as dirty, then they always
|
||||
* pay the cost of flushing during eviction, but don't pay the
|
||||
* cost of first-write exceptions to mark the page as dirty.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_BLKFIN_WT
|
||||
BITSET(R6, 14); /* Set WT*/
|
||||
#endif
|
||||
|
||||
[P1] = R2;
|
||||
[P1-0x100] = R4;
|
||||
#ifdef CONFIG_CPLB_INFO
|
||||
R3 = [P3];
|
||||
R3 += 1;
|
||||
[P3] = R3;
|
||||
#endif
|
||||
|
||||
/* We've installed the CPLB, so re-enable CPLBs. P4
|
||||
* points to DMEM_CONTROL, and R5 is the value we
|
||||
* last wrote to it, when we were disabling CPLBs.
|
||||
*/
|
||||
|
||||
BITSET(R5,ENDCPLB_P);
|
||||
CLI R2;
|
||||
.align 8;
|
||||
[P4] = R5;
|
||||
SSYNC;
|
||||
STI R2;
|
||||
|
||||
( R7:4,P5:3 ) = [SP++];
|
||||
R0 = CPLB_RELOADED;
|
||||
RTS;
|
||||
|
||||
.data
|
||||
.align 4;
|
||||
_page_size_table:
|
||||
.byte4 0x00000400; /* 1K */
|
||||
.byte4 0x00001000; /* 4K */
|
||||
.byte4 0x00100000; /* 1M */
|
||||
.byte4 0x00400000; /* 4M */
|
||||
|
||||
.align 4;
|
||||
_dcplb_preference:
|
||||
.byte4 0x00000001; /* valid bit */
|
||||
.byte4 0x00000002; /* lock bit */
|
418
arch/blackfin/mach-common/dpmc.S
Normal file
418
arch/blackfin/mach-common/dpmc.S
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/dpmc.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created: ?
|
||||
* Description: Watchdog Timer APIs
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
.text
|
||||
|
||||
ENTRY(_unmask_wdog_wakeup_evt)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.H = hi(SICA_IWR1);
|
||||
P0.L = lo(SICA_IWR1);
|
||||
#else
|
||||
P0.h = (SIC_IWR >> 16);
|
||||
P0.l = (SIC_IWR & 0xFFFF);
|
||||
#endif
|
||||
R7 = [P0];
|
||||
#if defined(CONFIG_BF561)
|
||||
BITSET(R7, 27);
|
||||
#else
|
||||
BITSET(R7,(IRQ_WATCH - IVG7));
|
||||
#endif
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
.LWRITE_TO_STAT:
|
||||
/* When watch dog timer is enabled, a write to STAT will load the
|
||||
* contents of CNT to STAT
|
||||
*/
|
||||
R7 = 0x0000(z);
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_STAT >> 16);
|
||||
P0.l = (WDOGA_STAT & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_STAT >> 16);
|
||||
P0.l = (WDOG_STAT & 0xFFFF);
|
||||
#endif
|
||||
[P0] = R7;
|
||||
SSYNC;
|
||||
JUMP .LSKIP_WRITE_TO_STAT;
|
||||
|
||||
ENTRY(_program_wdog_timer)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_CNT >> 16);
|
||||
P0.l = (WDOGA_CNT & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_CNT >> 16);
|
||||
P0.l = (WDOG_CNT & 0xFFFF);
|
||||
#endif
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_CTL >> 16);
|
||||
P0.l = (WDOGA_CTL & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_CTL >> 16);
|
||||
P0.l = (WDOG_CTL & 0xFFFF);
|
||||
#endif
|
||||
R7 = W[P0](Z);
|
||||
CC = BITTST(R7,1);
|
||||
if !CC JUMP .LWRITE_TO_STAT;
|
||||
CC = BITTST(R7,2);
|
||||
if !CC JUMP .LWRITE_TO_STAT;
|
||||
|
||||
.LSKIP_WRITE_TO_STAT:
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_CTL >> 16);
|
||||
P0.l = (WDOGA_CTL & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_CTL >> 16);
|
||||
P0.l = (WDOG_CTL & 0xFFFF);
|
||||
#endif
|
||||
R7 = W[P0](Z);
|
||||
BITCLR(R7,1); /* Enable GP event */
|
||||
BITSET(R7,2);
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
NOP;
|
||||
|
||||
R7 = W[P0](Z);
|
||||
BITCLR(R7,4); /* Enable the wdog counter */
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_clear_wdog_wakeup_evt)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_CTL >> 16);
|
||||
P0.l = (WDOGA_CTL & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_CTL >> 16);
|
||||
P0.l = (WDOG_CTL & 0xFFFF);
|
||||
#endif
|
||||
R7 = 0x0AD6(Z);
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
|
||||
R7 = W[P0](Z);
|
||||
BITSET(R7,15);
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
|
||||
R7 = W[P0](Z);
|
||||
BITSET(R7,1);
|
||||
BITSET(R7,2);
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_disable_wdog_timer)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
#if defined(CONFIG_BF561)
|
||||
P0.h = (WDOGA_CTL >> 16);
|
||||
P0.l = (WDOGA_CTL & 0xFFFF);
|
||||
#else
|
||||
P0.h = (WDOG_CTL >> 16);
|
||||
P0.l = (WDOG_CTL & 0xFFFF);
|
||||
#endif
|
||||
R7 = 0xAD6(Z);
|
||||
W[P0] = R7.L;
|
||||
SSYNC;
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
#if !defined(CONFIG_BF561)
|
||||
|
||||
.section .l1.text
|
||||
|
||||
ENTRY(_sleep_mode)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
[--SP] = RETS;
|
||||
|
||||
call _set_sic_iwr;
|
||||
|
||||
R0 = 0xFFFF (Z);
|
||||
call _set_rtc_istat
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R1 = W[P0](z);
|
||||
BITSET (R1, 3);
|
||||
W[P0] = R1.L;
|
||||
|
||||
CLI R2;
|
||||
SSYNC;
|
||||
IDLE;
|
||||
STI R2;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
R0 = IWR_ENABLE(0);
|
||||
call _set_sic_iwr;
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R7 = w[p0](z);
|
||||
BITCLR (R7, 3);
|
||||
BITCLR (R7, 5);
|
||||
w[p0] = R7.L;
|
||||
IDLE;
|
||||
call _test_pll_locked;
|
||||
|
||||
RETS = [SP++];
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_hibernate_mode)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
[--SP] = RETS;
|
||||
|
||||
call _set_sic_iwr;
|
||||
|
||||
R0 = 0xFFFF (Z);
|
||||
call _set_rtc_istat
|
||||
|
||||
P0.H = hi(VR_CTL);
|
||||
P0.L = lo(VR_CTL);
|
||||
R1 = W[P0](z);
|
||||
BITSET (R1, 8);
|
||||
BITCLR (R1, 0);
|
||||
BITCLR (R1, 1);
|
||||
W[P0] = R1.L;
|
||||
SSYNC;
|
||||
|
||||
CLI R2;
|
||||
IDLE;
|
||||
|
||||
/* Actually, adding anything may not be necessary...SDRAM contents
|
||||
* are lost
|
||||
*/
|
||||
|
||||
ENTRY(_deep_sleep)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
[--SP] = RETS;
|
||||
|
||||
CLI R4;
|
||||
|
||||
call _set_sic_iwr;
|
||||
|
||||
call _set_sdram_srfs;
|
||||
|
||||
/* Clear all the interrupts,bits sticky */
|
||||
R0 = 0xFFFF (Z);
|
||||
call _set_rtc_istat
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R0 = W[P0](z);
|
||||
BITSET (R0, 5);
|
||||
W[P0] = R0.L;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
SSYNC;
|
||||
IDLE;
|
||||
|
||||
call _unset_sdram_srfs;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
R0 = IWR_ENABLE(0);
|
||||
call _set_sic_iwr;
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R0 = w[p0](z);
|
||||
BITCLR (R0, 3);
|
||||
BITCLR (R0, 5);
|
||||
BITCLR (R0, 8);
|
||||
w[p0] = R0;
|
||||
IDLE;
|
||||
call _test_pll_locked;
|
||||
|
||||
STI R4;
|
||||
|
||||
RETS = [SP++];
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_sleep_deeper)
|
||||
[--SP] = ( R7:0, P5:0 );
|
||||
[--SP] = RETS;
|
||||
|
||||
CLI R4;
|
||||
|
||||
P3 = R0;
|
||||
R0 = IWR_ENABLE(0);
|
||||
call _set_sic_iwr;
|
||||
call _set_sdram_srfs;
|
||||
|
||||
/* Clear all the interrupts,bits sticky */
|
||||
R0 = 0xFFFF (Z);
|
||||
call _set_rtc_istat
|
||||
|
||||
P0.H = hi(PLL_DIV);
|
||||
P0.L = lo(PLL_DIV);
|
||||
R6 = W[P0](z);
|
||||
R0.L = 0xF;
|
||||
W[P0] = R0.l;
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R5 = W[P0](z);
|
||||
R0.L = (MIN_VC/CONFIG_CLKIN_HZ) << 9;
|
||||
W[P0] = R0.l;
|
||||
|
||||
SSYNC;
|
||||
IDLE;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
P0.H = hi(VR_CTL);
|
||||
P0.L = lo(VR_CTL);
|
||||
R7 = W[P0](z);
|
||||
R1 = 0x6;
|
||||
R1 <<= 16;
|
||||
R2 = 0x0404(Z);
|
||||
R1 = R1|R2;
|
||||
|
||||
R2 = DEPOSIT(R7, R1);
|
||||
W[P0] = R2;
|
||||
|
||||
SSYNC;
|
||||
IDLE;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
R0 = W[P0](z);
|
||||
BITSET (R0, 3);
|
||||
W[P0] = R0.L;
|
||||
|
||||
R0 = P3;
|
||||
call _set_sic_iwr;
|
||||
|
||||
SSYNC;
|
||||
IDLE;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
R0 = IWR_ENABLE(0);
|
||||
call _set_sic_iwr;
|
||||
|
||||
P0.H = hi(VR_CTL);
|
||||
P0.L = lo(VR_CTL);
|
||||
W[P0]= R7;
|
||||
|
||||
SSYNC;
|
||||
IDLE;
|
||||
|
||||
call _test_pll_locked;
|
||||
|
||||
P0.H = hi(PLL_DIV);
|
||||
P0.L = lo(PLL_DIV);
|
||||
W[P0]= R6;
|
||||
|
||||
P0.H = hi(PLL_CTL);
|
||||
P0.L = lo(PLL_CTL);
|
||||
w[p0] = R5;
|
||||
IDLE;
|
||||
call _test_pll_locked;
|
||||
|
||||
call _unset_sdram_srfs;
|
||||
|
||||
STI R4;
|
||||
|
||||
RETS = [SP++];
|
||||
( R7:0, P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
ENTRY(_set_sdram_srfs)
|
||||
/* set the sdram to self refresh mode */
|
||||
P0.H = hi(EBIU_SDGCTL);
|
||||
P0.L = lo(EBIU_SDGCTL);
|
||||
R2 = [P0];
|
||||
R3.H = hi(SRFS);
|
||||
R3.L = lo(SRFS);
|
||||
R2 = R2|R3;
|
||||
[P0] = R2;
|
||||
ssync;
|
||||
RTS;
|
||||
|
||||
ENTRY(_unset_sdram_srfs)
|
||||
/* set the sdram out of self refresh mode */
|
||||
P0.H = hi(EBIU_SDGCTL);
|
||||
P0.L = lo(EBIU_SDGCTL);
|
||||
R2 = [P0];
|
||||
R3.H = hi(SRFS);
|
||||
R3.L = lo(SRFS);
|
||||
R3 = ~R3;
|
||||
R2 = R2&R3;
|
||||
[P0] = R2;
|
||||
ssync;
|
||||
RTS;
|
||||
|
||||
ENTRY(_set_sic_iwr)
|
||||
P0.H = hi(SIC_IWR);
|
||||
P0.L = lo(SIC_IWR);
|
||||
[P0] = R0;
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
ENTRY(_set_rtc_istat)
|
||||
P0.H = hi(RTC_ISTAT);
|
||||
P0.L = lo(RTC_ISTAT);
|
||||
w[P0] = R0.L;
|
||||
SSYNC;
|
||||
RTS;
|
||||
|
||||
ENTRY(_test_pll_locked)
|
||||
P0.H = hi(PLL_STAT);
|
||||
P0.L = lo(PLL_STAT);
|
||||
1:
|
||||
R0 = W[P0] (Z);
|
||||
CC = BITTST(R0,5);
|
||||
IF !CC JUMP 1b;
|
||||
RTS;
|
||||
#endif
|
1207
arch/blackfin/mach-common/entry.S
Normal file
1207
arch/blackfin/mach-common/entry.S
Normal file
File diff suppressed because it is too large
Load diff
253
arch/blackfin/mach-common/interrupt.S
Normal file
253
arch/blackfin/mach-common/interrupt.S
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/interrupt.S
|
||||
* Based on:
|
||||
* Author: D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
|
||||
* Kenneth Albanowski <kjahds@kjahds.com>
|
||||
*
|
||||
* Created: ?
|
||||
* Description: Interrupt Entries
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
#include <asm/mach-common/context.S>
|
||||
|
||||
#ifdef CONFIG_I_ENTRY_L1
|
||||
.section .l1.text
|
||||
#else
|
||||
.text
|
||||
#endif
|
||||
|
||||
.align 4 /* just in case */
|
||||
|
||||
/*
|
||||
* initial interrupt handlers
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_KGDB
|
||||
/* interrupt routine for emulation - 0 */
|
||||
/* Currently used only if GDB stub is not in - invalid */
|
||||
/* gdb-stub set the evt itself */
|
||||
/* save registers for post-mortem only */
|
||||
ENTRY(_evt_emulation)
|
||||
SAVE_ALL_SYS
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
fp = 0;
|
||||
#endif
|
||||
r0 = IRQ_EMU;
|
||||
r1 = sp;
|
||||
SP += -12;
|
||||
call _irq_panic;
|
||||
SP += 12;
|
||||
/* - GDB stub fills this in by itself (if defined) */
|
||||
rte;
|
||||
#endif
|
||||
|
||||
/* Common interrupt entry code. First we do CLI, then push
|
||||
* RETI, to keep interrupts disabled, but to allow this state to be changed
|
||||
* by local_bh_enable.
|
||||
* R0 contains the interrupt number, while R1 may contain the value of IPEND,
|
||||
* or garbage if IPEND won't be needed by the ISR. */
|
||||
__common_int_entry:
|
||||
[--sp] = fp;
|
||||
[--sp] = usp;
|
||||
|
||||
[--sp] = i0;
|
||||
[--sp] = i1;
|
||||
[--sp] = i2;
|
||||
[--sp] = i3;
|
||||
|
||||
[--sp] = m0;
|
||||
[--sp] = m1;
|
||||
[--sp] = m2;
|
||||
[--sp] = m3;
|
||||
|
||||
[--sp] = l0;
|
||||
[--sp] = l1;
|
||||
[--sp] = l2;
|
||||
[--sp] = l3;
|
||||
|
||||
[--sp] = b0;
|
||||
[--sp] = b1;
|
||||
[--sp] = b2;
|
||||
[--sp] = b3;
|
||||
[--sp] = a0.x;
|
||||
[--sp] = a0.w;
|
||||
[--sp] = a1.x;
|
||||
[--sp] = a1.w;
|
||||
|
||||
[--sp] = LC0;
|
||||
[--sp] = LC1;
|
||||
[--sp] = LT0;
|
||||
[--sp] = LT1;
|
||||
[--sp] = LB0;
|
||||
[--sp] = LB1;
|
||||
|
||||
[--sp] = ASTAT;
|
||||
|
||||
[--sp] = r0; /* Skip reserved */
|
||||
[--sp] = RETS;
|
||||
r2 = RETI;
|
||||
[--sp] = r2;
|
||||
[--sp] = RETX;
|
||||
[--sp] = RETN;
|
||||
[--sp] = RETE;
|
||||
[--sp] = SEQSTAT;
|
||||
[--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */
|
||||
|
||||
/* Switch to other method of keeping interrupts disabled. */
|
||||
#ifdef CONFIG_DEBUG_HWERR
|
||||
r1 = 0x3f;
|
||||
sti r1;
|
||||
#else
|
||||
cli r1;
|
||||
#endif
|
||||
[--sp] = RETI; /* orig_pc */
|
||||
/* Clear all L registers. */
|
||||
r1 = 0 (x);
|
||||
l0 = r1;
|
||||
l1 = r1;
|
||||
l2 = r1;
|
||||
l3 = r1;
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
fp = 0;
|
||||
#endif
|
||||
|
||||
#ifdef ANOMALY_05000283
|
||||
cc = r7 == r7;
|
||||
p5.h = 0xffc0;
|
||||
p5.l = 0x0014;
|
||||
if cc jump 1f;
|
||||
r7.l = W[p5];
|
||||
1:
|
||||
#endif
|
||||
r1 = sp;
|
||||
SP += -12;
|
||||
call _do_irq;
|
||||
SP += 12;
|
||||
call _return_from_int;
|
||||
.Lcommon_restore_context:
|
||||
RESTORE_CONTEXT
|
||||
rti;
|
||||
|
||||
/* interrupt routine for ivhw - 5 */
|
||||
ENTRY(_evt_ivhw)
|
||||
SAVE_CONTEXT
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
fp = 0;
|
||||
#endif
|
||||
#ifdef ANOMALY_05000283
|
||||
cc = r7 == r7;
|
||||
p5.h = 0xffc0;
|
||||
p5.l = 0x0014;
|
||||
if cc jump 1f;
|
||||
r7.l = W[p5];
|
||||
1:
|
||||
#endif
|
||||
p0.l = lo(TBUFCTL);
|
||||
p0.h = hi(TBUFCTL);
|
||||
r0 = 1;
|
||||
[p0] = r0;
|
||||
r0 = IRQ_HWERR;
|
||||
r1 = sp;
|
||||
|
||||
#ifdef CONFIG_HARDWARE_PM
|
||||
r7 = SEQSTAT;
|
||||
r7 = r7 >>> 0xe;
|
||||
r6 = 0x1F;
|
||||
r7 = r7 & r6;
|
||||
r5 = 0x12;
|
||||
cc = r7 == r5;
|
||||
if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
|
||||
#endif
|
||||
|
||||
SP += -12;
|
||||
call _irq_panic;
|
||||
SP += 12;
|
||||
rti;
|
||||
#ifdef CONFIG_HARDWARE_PM
|
||||
.Lcall_do_ovf:
|
||||
|
||||
SP += -12;
|
||||
call _pm_overflow;
|
||||
SP += 12;
|
||||
|
||||
jump .Lcommon_restore_context;
|
||||
#endif
|
||||
|
||||
/* interrupt routine for evt2 - 2. This is NMI. */
|
||||
ENTRY(_evt_evt2)
|
||||
SAVE_CONTEXT
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
fp = 0;
|
||||
#endif
|
||||
#ifdef ANOMALY_05000283
|
||||
cc = r7 == r7;
|
||||
p5.h = 0xffc0;
|
||||
p5.l = 0x0014;
|
||||
if cc jump 1f;
|
||||
r7.l = W[p5];
|
||||
1:
|
||||
#endif
|
||||
r0 = IRQ_NMI;
|
||||
r1 = sp;
|
||||
SP += -12;
|
||||
call _asm_do_IRQ;
|
||||
SP += 12;
|
||||
RESTORE_CONTEXT
|
||||
rtn;
|
||||
|
||||
/* interrupt routine for core timer - 6 */
|
||||
ENTRY(_evt_timer)
|
||||
TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)
|
||||
|
||||
/* interrupt routine for evt7 - 7 */
|
||||
ENTRY(_evt_evt7)
|
||||
INTERRUPT_ENTRY(EVT_IVG7_P)
|
||||
ENTRY(_evt_evt8)
|
||||
INTERRUPT_ENTRY(EVT_IVG8_P)
|
||||
ENTRY(_evt_evt9)
|
||||
INTERRUPT_ENTRY(EVT_IVG9_P)
|
||||
ENTRY(_evt_evt10)
|
||||
INTERRUPT_ENTRY(EVT_IVG10_P)
|
||||
ENTRY(_evt_evt11)
|
||||
INTERRUPT_ENTRY(EVT_IVG11_P)
|
||||
ENTRY(_evt_evt12)
|
||||
INTERRUPT_ENTRY(EVT_IVG12_P)
|
||||
ENTRY(_evt_evt13)
|
||||
INTERRUPT_ENTRY(EVT_IVG13_P)
|
||||
|
||||
|
||||
/* interrupt routine for system_call - 15 */
|
||||
ENTRY(_evt_system_call)
|
||||
SAVE_CONTEXT_SYSCALL
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
fp = 0;
|
||||
#endif
|
||||
call _system_call;
|
||||
jump .Lcommon_restore_context;
|
476
arch/blackfin/mach-common/ints-priority-dc.c
Normal file
476
arch/blackfin/mach-common/ints-priority-dc.c
Normal file
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/ints-priority-dc.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created: ?
|
||||
* Description: Set up the interupt priorities
|
||||
*
|
||||
* Modified:
|
||||
* 1996 Roman Zippel
|
||||
* 1999 D. Jeff Dionne <jeff@uclinux.org>
|
||||
* 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
|
||||
* 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
|
||||
* 2003 Metrowerks/Motorola
|
||||
* 2003 Bas Vermeulen <bas@buyways.nl>
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/irq.h>
|
||||
#ifdef CONFIG_KGDB
|
||||
#include <linux/kgdb.h>
|
||||
#endif
|
||||
#include <asm/traps.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/irq_handler.h>
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
* - we have separated the physical Hardware interrupt from the
|
||||
* levels that the LINUX kernel sees (see the description in irq.h)
|
||||
* -
|
||||
*/
|
||||
|
||||
unsigned long irq_flags = 0;
|
||||
|
||||
/* The number of spurious interrupts */
|
||||
atomic_t num_spurious;
|
||||
|
||||
struct ivgx {
|
||||
/* irq number for request_irq, available in mach-bf561/irq.h */
|
||||
int irqno;
|
||||
/* corresponding bit in the SICA_ISR0 register */
|
||||
int isrflag0;
|
||||
/* corresponding bit in the SICA_ISR1 register */
|
||||
int isrflag1;
|
||||
} ivg_table[NR_PERI_INTS];
|
||||
|
||||
struct ivg_slice {
|
||||
/* position of first irq in ivg_table for given ivg */
|
||||
struct ivgx *ifirst;
|
||||
struct ivgx *istop;
|
||||
} ivg7_13[IVG13 - IVG7 + 1];
|
||||
|
||||
static void search_IAR(void);
|
||||
|
||||
/*
|
||||
* Search SIC_IAR and fill tables with the irqvalues
|
||||
* and their positions in the SIC_ISR register.
|
||||
*/
|
||||
static void __init search_IAR(void)
|
||||
{
|
||||
unsigned ivg, irq_pos = 0;
|
||||
for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
|
||||
int irqn;
|
||||
|
||||
ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
|
||||
|
||||
for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
|
||||
int iar_shift = (irqn & 7) * 4;
|
||||
if (ivg ==
|
||||
(0xf &
|
||||
bfin_read32((unsigned long *)SICA_IAR0 +
|
||||
(irqn >> 3)) >> iar_shift)) {
|
||||
ivg_table[irq_pos].irqno = IVG7 + irqn;
|
||||
ivg_table[irq_pos].isrflag0 =
|
||||
(irqn < 32 ? (1 << irqn) : 0);
|
||||
ivg_table[irq_pos].isrflag1 =
|
||||
(irqn < 32 ? 0 : (1 << (irqn - 32)));
|
||||
ivg7_13[ivg].istop++;
|
||||
irq_pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is for BF561 internal IRQs
|
||||
*/
|
||||
|
||||
static void ack_noop(unsigned int irq)
|
||||
{
|
||||
/* Dummy function. */
|
||||
}
|
||||
|
||||
static void bf561_core_mask_irq(unsigned int irq)
|
||||
{
|
||||
irq_flags &= ~(1 << irq);
|
||||
if (!irqs_disabled())
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static void bf561_core_unmask_irq(unsigned int irq)
|
||||
{
|
||||
irq_flags |= 1 << irq;
|
||||
/*
|
||||
* If interrupts are enabled, IMASK must contain the same value
|
||||
* as irq_flags. Make sure that invariant holds. If interrupts
|
||||
* are currently disabled we need not do anything; one of the
|
||||
* callers will take care of setting IMASK to the proper value
|
||||
* when reenabling interrupts.
|
||||
* local_irq_enable just does "STI irq_flags", so it's exactly
|
||||
* what we need.
|
||||
*/
|
||||
if (!irqs_disabled())
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
static void bf561_internal_mask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long irq_mask;
|
||||
if ((irq - (IRQ_CORETMR + 1)) < 32) {
|
||||
irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
|
||||
bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() & ~irq_mask);
|
||||
} else {
|
||||
irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
|
||||
bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() & ~irq_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void bf561_internal_unmask_irq(unsigned int irq)
|
||||
{
|
||||
unsigned long irq_mask;
|
||||
|
||||
if ((irq - (IRQ_CORETMR + 1)) < 32) {
|
||||
irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
|
||||
bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() | irq_mask);
|
||||
} else {
|
||||
irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
|
||||
bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() | irq_mask);
|
||||
}
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static struct irq_chip bf561_core_irqchip = {
|
||||
.ack = ack_noop,
|
||||
.mask = bf561_core_mask_irq,
|
||||
.unmask = bf561_core_unmask_irq,
|
||||
};
|
||||
|
||||
static struct irq_chip bf561_internal_irqchip = {
|
||||
.ack = ack_noop,
|
||||
.mask = bf561_internal_mask_irq,
|
||||
.unmask = bf561_internal_unmask_irq,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
|
||||
static void bf561_gpio_ack_irq(unsigned int irq)
|
||||
{
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
|
||||
set_gpio_data(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
}
|
||||
|
||||
static void bf561_gpio_mask_ack_irq(unsigned int irq)
|
||||
{
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
|
||||
set_gpio_data(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
set_gpio_maska(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static void bf561_gpio_mask_irq(unsigned int irq)
|
||||
{
|
||||
set_gpio_maska(irq - IRQ_PF0, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static void bf561_gpio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
set_gpio_maska(irq - IRQ_PF0, 1);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static unsigned int bf561_gpio_irq_startup(unsigned int irq)
|
||||
{
|
||||
unsigned int ret;
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
|
||||
|
||||
ret = gpio_request(gpionr, NULL);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
bf561_gpio_unmask_irq(irq);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void bf561_gpio_irq_shutdown(unsigned int irq)
|
||||
{
|
||||
bf561_gpio_mask_irq(irq);
|
||||
gpio_free(irq - IRQ_PF0);
|
||||
gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
|
||||
}
|
||||
|
||||
static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
|
||||
unsigned int ret;
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
|
||||
if (type == IRQ_TYPE_PROBE) {
|
||||
/* only probe unenabled GPIO interrupt lines */
|
||||
if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
|
||||
return 0;
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
|
||||
}
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
|
||||
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
||||
|
||||
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
|
||||
|
||||
ret = gpio_request(gpionr, NULL);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
} else {
|
||||
gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
set_gpio_dir(gpionr, 0);
|
||||
set_gpio_inen(gpionr, 1);
|
||||
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
|
||||
gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
set_gpio_edge(gpionr, 1);
|
||||
} else {
|
||||
set_gpio_edge(gpionr, 0);
|
||||
gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
|
||||
}
|
||||
|
||||
if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
== (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
set_gpio_both(gpionr, 1);
|
||||
else
|
||||
set_gpio_both(gpionr, 0);
|
||||
|
||||
if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
|
||||
set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
|
||||
else
|
||||
set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
|
||||
|
||||
SSYNC();
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
set_irq_handler(irq, handle_edge_irq);
|
||||
else
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip bf561_gpio_irqchip = {
|
||||
.ack = bf561_gpio_ack_irq,
|
||||
.mask = bf561_gpio_mask_irq,
|
||||
.mask_ack = bf561_gpio_mask_ack_irq,
|
||||
.unmask = bf561_gpio_unmask_irq,
|
||||
.set_type = bf561_gpio_irq_type,
|
||||
.startup = bf561_gpio_irq_startup,
|
||||
.shutdown = bf561_gpio_irq_shutdown
|
||||
};
|
||||
|
||||
static void bf561_demux_gpio_irq(unsigned int inta_irq,
|
||||
struct irq_desc *intb_desc)
|
||||
{
|
||||
int irq, flag_d, mask;
|
||||
u16 gpio;
|
||||
|
||||
switch (inta_irq) {
|
||||
case IRQ_PROG0_INTA:
|
||||
irq = IRQ_PF0;
|
||||
break;
|
||||
case IRQ_PROG1_INTA:
|
||||
irq = IRQ_PF16;
|
||||
break;
|
||||
case IRQ_PROG2_INTA:
|
||||
irq = IRQ_PF32;
|
||||
break;
|
||||
default:
|
||||
dump_stack();
|
||||
return;
|
||||
}
|
||||
|
||||
gpio = irq - IRQ_PF0;
|
||||
|
||||
flag_d = get_gpiop_data(gpio);
|
||||
mask = flag_d & (gpio_enabled[gpio_bank(gpio)] &
|
||||
get_gpiop_maska(gpio));
|
||||
|
||||
do {
|
||||
if (mask & 1) {
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
desc->handle_irq(irq, desc);
|
||||
}
|
||||
irq++;
|
||||
mask >>= 1;
|
||||
} while (mask);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */
|
||||
|
||||
/*
|
||||
* This function should be called during kernel startup to initialize
|
||||
* the BFin IRQ handling routines.
|
||||
*/
|
||||
int __init init_arch_irq(void)
|
||||
{
|
||||
int irq;
|
||||
unsigned long ilat = 0;
|
||||
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
|
||||
bfin_write_SICA_IMASK0(SIC_UNMASK_ALL);
|
||||
bfin_write_SICA_IMASK1(SIC_UNMASK_ALL);
|
||||
SSYNC();
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
init_exception_buff();
|
||||
|
||||
#ifndef CONFIG_KGDB
|
||||
bfin_write_EVT0(evt_emulation);
|
||||
#endif
|
||||
bfin_write_EVT2(evt_evt2);
|
||||
bfin_write_EVT3(trap);
|
||||
bfin_write_EVT5(evt_ivhw);
|
||||
bfin_write_EVT6(evt_timer);
|
||||
bfin_write_EVT7(evt_evt7);
|
||||
bfin_write_EVT8(evt_evt8);
|
||||
bfin_write_EVT9(evt_evt9);
|
||||
bfin_write_EVT10(evt_evt10);
|
||||
bfin_write_EVT11(evt_evt11);
|
||||
bfin_write_EVT12(evt_evt12);
|
||||
bfin_write_EVT13(evt_evt13);
|
||||
bfin_write_EVT14(evt14_softirq);
|
||||
bfin_write_EVT15(evt_system_call);
|
||||
CSYNC();
|
||||
|
||||
for (irq = 0; irq < SYS_IRQS; irq++) {
|
||||
if (irq <= IRQ_CORETMR)
|
||||
set_irq_chip(irq, &bf561_core_irqchip);
|
||||
else
|
||||
set_irq_chip(irq, &bf561_internal_irqchip);
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
if ((irq != IRQ_PROG0_INTA) &&
|
||||
(irq != IRQ_PROG1_INTA) && (irq != IRQ_PROG2_INTA)) {
|
||||
#endif
|
||||
set_irq_handler(irq, handle_simple_irq);
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
} else {
|
||||
set_irq_chained_handler(irq, bf561_demux_gpio_irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) {
|
||||
set_irq_chip(irq, &bf561_gpio_irqchip);
|
||||
/* if configured as edge, then will be changed to do_edge_IRQ */
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
}
|
||||
#endif
|
||||
bfin_write_IMASK(0);
|
||||
CSYNC();
|
||||
ilat = bfin_read_ILAT();
|
||||
CSYNC();
|
||||
bfin_write_ILAT(ilat);
|
||||
CSYNC();
|
||||
|
||||
printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
|
||||
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
|
||||
* local_irq_enable()
|
||||
*/
|
||||
program_IAR();
|
||||
/* Therefore it's better to setup IARs before interrupts enabled */
|
||||
search_IAR();
|
||||
|
||||
/* Enable interrupts IVG7-15 */
|
||||
irq_flags = irq_flags | IMASK_IVG15 |
|
||||
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
|
||||
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DO_IRQ_L1
|
||||
void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
void do_irq(int vec, struct pt_regs *fp)
|
||||
{
|
||||
if (vec == EVT_IVTMR_P) {
|
||||
vec = IRQ_CORETMR;
|
||||
} else {
|
||||
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
|
||||
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
|
||||
unsigned long sic_status0, sic_status1;
|
||||
|
||||
SSYNC();
|
||||
sic_status0 = bfin_read_SICA_IMASK0() & bfin_read_SICA_ISR0();
|
||||
sic_status1 = bfin_read_SICA_IMASK1() & bfin_read_SICA_ISR1();
|
||||
|
||||
for (;; ivg++) {
|
||||
if (ivg >= ivg_stop) {
|
||||
atomic_inc(&num_spurious);
|
||||
return;
|
||||
} else if ((sic_status0 & ivg->isrflag0) ||
|
||||
(sic_status1 & ivg->isrflag1))
|
||||
break;
|
||||
}
|
||||
vec = ivg->irqno;
|
||||
}
|
||||
asm_do_IRQ(vec, fp);
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
kgdb_process_breakpoint();
|
||||
#endif
|
||||
}
|
577
arch/blackfin/mach-common/ints-priority-sc.c
Normal file
577
arch/blackfin/mach-common/ints-priority-sc.c
Normal file
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/ints-priority-sc.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created: ?
|
||||
* Description: Set up the interupt priorities
|
||||
*
|
||||
* Modified:
|
||||
* 1996 Roman Zippel
|
||||
* 1999 D. Jeff Dionne <jeff@uclinux.org>
|
||||
* 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
|
||||
* 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
|
||||
* 2003 Metrowerks/Motorola
|
||||
* 2003 Bas Vermeulen <bas@buyways.nl>
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/irq.h>
|
||||
#ifdef CONFIG_KGDB
|
||||
#include <linux/kgdb.h>
|
||||
#endif
|
||||
#include <asm/traps.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/irq_handler.h>
|
||||
|
||||
#ifdef BF537_FAMILY
|
||||
# define BF537_GENERIC_ERROR_INT_DEMUX
|
||||
#else
|
||||
# undef BF537_GENERIC_ERROR_INT_DEMUX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
* - we have separated the physical Hardware interrupt from the
|
||||
* levels that the LINUX kernel sees (see the description in irq.h)
|
||||
* -
|
||||
*/
|
||||
|
||||
unsigned long irq_flags = 0;
|
||||
|
||||
/* The number of spurious interrupts */
|
||||
atomic_t num_spurious;
|
||||
|
||||
struct ivgx {
|
||||
/* irq number for request_irq, available in mach-bf533/irq.h */
|
||||
int irqno;
|
||||
/* corresponding bit in the SIC_ISR register */
|
||||
int isrflag;
|
||||
} ivg_table[NR_PERI_INTS];
|
||||
|
||||
struct ivg_slice {
|
||||
/* position of first irq in ivg_table for given ivg */
|
||||
struct ivgx *ifirst;
|
||||
struct ivgx *istop;
|
||||
} ivg7_13[IVG13 - IVG7 + 1];
|
||||
|
||||
static void search_IAR(void);
|
||||
|
||||
/*
|
||||
* Search SIC_IAR and fill tables with the irqvalues
|
||||
* and their positions in the SIC_ISR register.
|
||||
*/
|
||||
static void __init search_IAR(void)
|
||||
{
|
||||
unsigned ivg, irq_pos = 0;
|
||||
for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
|
||||
int irqn;
|
||||
|
||||
ivg7_13[ivg].istop = ivg7_13[ivg].ifirst =
|
||||
&ivg_table[irq_pos];
|
||||
|
||||
for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
|
||||
int iar_shift = (irqn & 7) * 4;
|
||||
if (ivg ==
|
||||
(0xf &
|
||||
bfin_read32((unsigned long *) SIC_IAR0 +
|
||||
(irqn >> 3)) >> iar_shift)) {
|
||||
ivg_table[irq_pos].irqno = IVG7 + irqn;
|
||||
ivg_table[irq_pos].isrflag = 1 << irqn;
|
||||
ivg7_13[ivg].istop++;
|
||||
irq_pos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is for BF533 internal IRQs
|
||||
*/
|
||||
|
||||
static void ack_noop(unsigned int irq)
|
||||
{
|
||||
/* Dummy function. */
|
||||
}
|
||||
|
||||
static void bfin_core_mask_irq(unsigned int irq)
|
||||
{
|
||||
irq_flags &= ~(1 << irq);
|
||||
if (!irqs_disabled())
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static void bfin_core_unmask_irq(unsigned int irq)
|
||||
{
|
||||
irq_flags |= 1 << irq;
|
||||
/*
|
||||
* If interrupts are enabled, IMASK must contain the same value
|
||||
* as irq_flags. Make sure that invariant holds. If interrupts
|
||||
* are currently disabled we need not do anything; one of the
|
||||
* callers will take care of setting IMASK to the proper value
|
||||
* when reenabling interrupts.
|
||||
* local_irq_enable just does "STI irq_flags", so it's exactly
|
||||
* what we need.
|
||||
*/
|
||||
if (!irqs_disabled())
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
static void bfin_internal_mask_irq(unsigned int irq)
|
||||
{
|
||||
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
|
||||
~(1 << (irq - (IRQ_CORETMR + 1))));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static void bfin_internal_unmask_irq(unsigned int irq)
|
||||
{
|
||||
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
|
||||
(1 << (irq - (IRQ_CORETMR + 1))));
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static struct irq_chip bfin_core_irqchip = {
|
||||
.ack = ack_noop,
|
||||
.mask = bfin_core_mask_irq,
|
||||
.unmask = bfin_core_unmask_irq,
|
||||
};
|
||||
|
||||
static struct irq_chip bfin_internal_irqchip = {
|
||||
.ack = ack_noop,
|
||||
.mask = bfin_internal_mask_irq,
|
||||
.unmask = bfin_internal_unmask_irq,
|
||||
};
|
||||
|
||||
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
|
||||
static int error_int_mask;
|
||||
|
||||
static void bfin_generic_error_ack_irq(unsigned int irq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bfin_generic_error_mask_irq(unsigned int irq)
|
||||
{
|
||||
error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
|
||||
|
||||
if (!error_int_mask) {
|
||||
local_irq_disable();
|
||||
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
|
||||
~(1 <<
|
||||
(IRQ_GENERIC_ERROR -
|
||||
(IRQ_CORETMR + 1))));
|
||||
SSYNC();
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
static void bfin_generic_error_unmask_irq(unsigned int irq)
|
||||
{
|
||||
local_irq_disable();
|
||||
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 1 <<
|
||||
(IRQ_GENERIC_ERROR - (IRQ_CORETMR + 1)));
|
||||
SSYNC();
|
||||
local_irq_enable();
|
||||
|
||||
error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
|
||||
}
|
||||
|
||||
static struct irq_chip bfin_generic_error_irqchip = {
|
||||
.ack = bfin_generic_error_ack_irq,
|
||||
.mask = bfin_generic_error_mask_irq,
|
||||
.unmask = bfin_generic_error_unmask_irq,
|
||||
};
|
||||
|
||||
static void bfin_demux_error_irq(unsigned int int_err_irq,
|
||||
struct irq_desc *intb_desc)
|
||||
{
|
||||
int irq = 0;
|
||||
|
||||
SSYNC();
|
||||
|
||||
#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
|
||||
if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
|
||||
irq = IRQ_MAC_ERROR;
|
||||
else
|
||||
#endif
|
||||
if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
|
||||
irq = IRQ_SPORT0_ERROR;
|
||||
else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
|
||||
irq = IRQ_SPORT1_ERROR;
|
||||
else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
|
||||
irq = IRQ_PPI_ERROR;
|
||||
else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
|
||||
irq = IRQ_CAN_ERROR;
|
||||
else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
|
||||
irq = IRQ_SPI_ERROR;
|
||||
else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) &&
|
||||
(bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0))
|
||||
irq = IRQ_UART0_ERROR;
|
||||
else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) &&
|
||||
(bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0))
|
||||
irq = IRQ_UART1_ERROR;
|
||||
|
||||
if (irq) {
|
||||
if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) {
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
desc->handle_irq(irq, desc);
|
||||
} else {
|
||||
|
||||
switch (irq) {
|
||||
case IRQ_PPI_ERROR:
|
||||
bfin_write_PPI_STATUS(PPI_ERR_MASK);
|
||||
break;
|
||||
#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
|
||||
case IRQ_MAC_ERROR:
|
||||
bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
|
||||
break;
|
||||
#endif
|
||||
case IRQ_SPORT0_ERROR:
|
||||
bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
|
||||
break;
|
||||
|
||||
case IRQ_SPORT1_ERROR:
|
||||
bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
|
||||
break;
|
||||
|
||||
case IRQ_CAN_ERROR:
|
||||
bfin_write_CAN_GIS(CAN_ERR_MASK);
|
||||
break;
|
||||
|
||||
case IRQ_SPI_ERROR:
|
||||
bfin_write_SPI_STAT(SPI_ERR_MASK);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("IRQ %d:"
|
||||
" MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
|
||||
irq);
|
||||
}
|
||||
} else
|
||||
printk(KERN_ERR
|
||||
"%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
|
||||
" INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
|
||||
__FUNCTION__, __FILE__, __LINE__);
|
||||
|
||||
|
||||
}
|
||||
#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
|
||||
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
|
||||
static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
|
||||
|
||||
static void bfin_gpio_ack_irq(unsigned int irq)
|
||||
{
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
|
||||
set_gpio_data(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
}
|
||||
|
||||
static void bfin_gpio_mask_ack_irq(unsigned int irq)
|
||||
{
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
|
||||
set_gpio_data(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
set_gpio_maska(gpionr, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static void bfin_gpio_mask_irq(unsigned int irq)
|
||||
{
|
||||
set_gpio_maska(irq - IRQ_PF0, 0);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static void bfin_gpio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
set_gpio_maska(irq - IRQ_PF0, 1);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static unsigned int bfin_gpio_irq_startup(unsigned int irq)
|
||||
{
|
||||
unsigned int ret;
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
|
||||
ret = gpio_request(gpionr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
bfin_gpio_unmask_irq(irq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bfin_gpio_irq_shutdown(unsigned int irq)
|
||||
{
|
||||
bfin_gpio_mask_irq(irq);
|
||||
gpio_free(irq - IRQ_PF0);
|
||||
gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
|
||||
}
|
||||
|
||||
static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
|
||||
unsigned int ret;
|
||||
u16 gpionr = irq - IRQ_PF0;
|
||||
|
||||
if (type == IRQ_TYPE_PROBE) {
|
||||
/* only probe unenabled GPIO interrupt lines */
|
||||
if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
|
||||
return 0;
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
}
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
|
||||
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||
{
|
||||
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
|
||||
ret = gpio_request(gpionr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
} else {
|
||||
gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_gpio_dir(gpionr, 0);
|
||||
set_gpio_inen(gpionr, 1);
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
|
||||
gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
|
||||
set_gpio_edge(gpionr, 1);
|
||||
} else {
|
||||
set_gpio_edge(gpionr, 0);
|
||||
gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
|
||||
}
|
||||
|
||||
if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
== (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
set_gpio_both(gpionr, 1);
|
||||
else
|
||||
set_gpio_both(gpionr, 0);
|
||||
|
||||
if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
|
||||
set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
|
||||
else
|
||||
set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
|
||||
|
||||
SSYNC();
|
||||
|
||||
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
|
||||
set_irq_handler(irq, handle_edge_irq);
|
||||
else
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct irq_chip bfin_gpio_irqchip = {
|
||||
.ack = bfin_gpio_ack_irq,
|
||||
.mask = bfin_gpio_mask_irq,
|
||||
.mask_ack = bfin_gpio_mask_ack_irq,
|
||||
.unmask = bfin_gpio_unmask_irq,
|
||||
.set_type = bfin_gpio_irq_type,
|
||||
.startup = bfin_gpio_irq_startup,
|
||||
.shutdown = bfin_gpio_irq_shutdown
|
||||
};
|
||||
|
||||
static void bfin_demux_gpio_irq(unsigned int intb_irq,
|
||||
struct irq_desc *intb_desc)
|
||||
{
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=16) {
|
||||
int irq = IRQ_PF0 + i;
|
||||
int flag_d = get_gpiop_data(i);
|
||||
int mask =
|
||||
flag_d & (gpio_enabled[gpio_bank(i)] &
|
||||
get_gpiop_maska(i));
|
||||
|
||||
while (mask) {
|
||||
if (mask & 1) {
|
||||
struct irq_desc *desc = irq_desc + irq;
|
||||
desc->handle_irq(irq, desc);
|
||||
}
|
||||
irq++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */
|
||||
|
||||
/*
|
||||
* This function should be called during kernel startup to initialize
|
||||
* the BFin IRQ handling routines.
|
||||
*/
|
||||
int __init init_arch_irq(void)
|
||||
{
|
||||
int irq;
|
||||
unsigned long ilat = 0;
|
||||
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
|
||||
bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
|
||||
SSYNC();
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
#ifndef CONFIG_KGDB
|
||||
bfin_write_EVT0(evt_emulation);
|
||||
#endif
|
||||
bfin_write_EVT2(evt_evt2);
|
||||
bfin_write_EVT3(trap);
|
||||
bfin_write_EVT5(evt_ivhw);
|
||||
bfin_write_EVT6(evt_timer);
|
||||
bfin_write_EVT7(evt_evt7);
|
||||
bfin_write_EVT8(evt_evt8);
|
||||
bfin_write_EVT9(evt_evt9);
|
||||
bfin_write_EVT10(evt_evt10);
|
||||
bfin_write_EVT11(evt_evt11);
|
||||
bfin_write_EVT12(evt_evt12);
|
||||
bfin_write_EVT13(evt_evt13);
|
||||
bfin_write_EVT14(evt14_softirq);
|
||||
bfin_write_EVT15(evt_system_call);
|
||||
CSYNC();
|
||||
|
||||
for (irq = 0; irq < SYS_IRQS; irq++) {
|
||||
if (irq <= IRQ_CORETMR)
|
||||
set_irq_chip(irq, &bfin_core_irqchip);
|
||||
else
|
||||
set_irq_chip(irq, &bfin_internal_irqchip);
|
||||
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
|
||||
if (irq != IRQ_GENERIC_ERROR) {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
if ((irq != IRQ_PROG_INTA) /*PORT F & G MASK_A Interrupt*/
|
||||
# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
|
||||
&& (irq != IRQ_MAC_RX) /*PORT H MASK_A Interrupt*/
|
||||
# endif
|
||||
) {
|
||||
#endif
|
||||
set_irq_handler(irq, handle_simple_irq);
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
} else {
|
||||
set_irq_chained_handler(irq,
|
||||
bfin_demux_gpio_irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
|
||||
} else {
|
||||
set_irq_handler(irq, bfin_demux_error_irq);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
|
||||
for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) {
|
||||
set_irq_chip(irq, &bfin_generic_error_irqchip);
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
|
||||
for (irq = IRQ_PF0; irq < NR_IRQS; irq++) {
|
||||
set_irq_chip(irq, &bfin_gpio_irqchip);
|
||||
/* if configured as edge, then will be changed to do_edge_IRQ */
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
}
|
||||
#endif
|
||||
bfin_write_IMASK(0);
|
||||
CSYNC();
|
||||
ilat = bfin_read_ILAT();
|
||||
CSYNC();
|
||||
bfin_write_ILAT(ilat);
|
||||
CSYNC();
|
||||
|
||||
printk(KERN_INFO
|
||||
"Configuring Blackfin Priority Driven Interrupts\n");
|
||||
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
|
||||
* local_irq_enable()
|
||||
*/
|
||||
program_IAR();
|
||||
/* Therefore it's better to setup IARs before interrupts enabled */
|
||||
search_IAR();
|
||||
|
||||
/* Enable interrupts IVG7-15 */
|
||||
irq_flags = irq_flags | IMASK_IVG15 |
|
||||
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
|
||||
IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 |
|
||||
IMASK_IVGHW;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DO_IRQ_L1
|
||||
void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
|
||||
#endif
|
||||
|
||||
void do_irq(int vec, struct pt_regs *fp)
|
||||
{
|
||||
if (vec == EVT_IVTMR_P) {
|
||||
vec = IRQ_CORETMR;
|
||||
} else {
|
||||
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
|
||||
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
|
||||
unsigned long sic_status;
|
||||
|
||||
SSYNC();
|
||||
sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
|
||||
|
||||
for (;; ivg++) {
|
||||
if (ivg >= ivg_stop) {
|
||||
atomic_inc(&num_spurious);
|
||||
return;
|
||||
} else if (sic_status & ivg->isrflag)
|
||||
break;
|
||||
}
|
||||
vec = ivg->irqno;
|
||||
}
|
||||
asm_do_IRQ(vec, fp);
|
||||
|
||||
#ifdef CONFIG_KGDB
|
||||
kgdb_process_breakpoint();
|
||||
#endif
|
||||
}
|
194
arch/blackfin/mach-common/irqpanic.c
Normal file
194
arch/blackfin/mach-common/irqpanic.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/irqpanic.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created: ?
|
||||
* Description: panic kernel with dump information
|
||||
*
|
||||
* Modified: rgetz - added cache checking code 14Feb06
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
#include "../oprofile/op_blackfin.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_ICACHE_CHECK
|
||||
#define L1_ICACHE_START 0xffa10000
|
||||
#define L1_ICACHE_END 0xffa13fff
|
||||
void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* irq_panic - calls panic with string setup
|
||||
*/
|
||||
asmlinkage void irq_panic(int reason, struct pt_regs *regs)
|
||||
{
|
||||
int sig = 0;
|
||||
siginfo_t info;
|
||||
|
||||
#ifdef CONFIG_DEBUG_ICACHE_CHECK
|
||||
unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
|
||||
unsigned short i, j, die;
|
||||
unsigned int bad[10][6];
|
||||
|
||||
/* check entire cache for coherency
|
||||
* Since printk is in cacheable memory,
|
||||
* don't call it until you have checked everything
|
||||
*/
|
||||
|
||||
die = 0;
|
||||
i = 0;
|
||||
|
||||
/* check icache */
|
||||
|
||||
for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
|
||||
|
||||
/* Grab various address bits for the itest_cmd fields */
|
||||
cmd = (((ca & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
|
||||
((ca & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
|
||||
((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
|
||||
0); /* Access Tag, Read access */
|
||||
|
||||
SSYNC();
|
||||
bfin_write_ITEST_COMMAND(cmd);
|
||||
SSYNC();
|
||||
tag = bfin_read_ITEST_DATA0();
|
||||
SSYNC();
|
||||
|
||||
/* if tag is marked as valid, check it */
|
||||
if (tag & 1) {
|
||||
/* The icache is arranged in 4 groups of 64-bits */
|
||||
for (j = 0; j < 32; j += 8) {
|
||||
cmd = ((((ca + j) & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
|
||||
(((ca + j) & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
|
||||
(((ca + j) & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
|
||||
4); /* Access Data, Read access */
|
||||
|
||||
SSYNC();
|
||||
bfin_write_ITEST_COMMAND(cmd);
|
||||
SSYNC();
|
||||
|
||||
cache_hi = bfin_read_ITEST_DATA1();
|
||||
cache_lo = bfin_read_ITEST_DATA0();
|
||||
|
||||
pa = ((unsigned int *)((tag & 0xffffcc00) |
|
||||
((ca + j) & ~(0xffffcc00))));
|
||||
|
||||
/*
|
||||
* Debugging this, enable
|
||||
*
|
||||
* printk("addr: %08x %08x%08x | %08x%08x\n",
|
||||
* ((unsigned int *)((tag & 0xffffcc00) | ((ca+j) & ~(0xffffcc00)))),
|
||||
* cache_hi, cache_lo, *(pa+1), *pa);
|
||||
*/
|
||||
|
||||
if (cache_hi != *(pa + 1) || cache_lo != *pa) {
|
||||
/* Since icache is not working, stay out of it, by not printing */
|
||||
die = 1;
|
||||
bad[i][0] = (ca + j);
|
||||
bad[i][1] = cache_hi;
|
||||
bad[i][2] = cache_lo;
|
||||
bad[i][3] = ((tag & 0xffffcc00) |
|
||||
((ca + j) & ~(0xffffcc00)));
|
||||
bad[i][4] = *(pa + 1);
|
||||
bad[i][5] = *(pa);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (die) {
|
||||
printk(KERN_EMERG "icache coherency error\n");
|
||||
for (j = 0; j <= i; j++) {
|
||||
printk(KERN_EMERG
|
||||
"cache address : %08x cache value : %08x%08x\n",
|
||||
bad[j][0], bad[j][1], bad[j][2]);
|
||||
printk(KERN_EMERG
|
||||
"physical address: %08x SDRAM value : %08x%08x\n",
|
||||
bad[j][3], bad[j][4], bad[j][5]);
|
||||
}
|
||||
panic("icache coherency error");
|
||||
} else {
|
||||
printk(KERN_EMERG "icache checked, and OK\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(KERN_EMERG "\n");
|
||||
printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
|
||||
printk(KERN_EMERG " code=[0x%08lx], stack frame=0x%08lx, "
|
||||
" bad PC=0x%08lx\n",
|
||||
(unsigned long)regs->seqstat,
|
||||
(unsigned long)regs,
|
||||
(unsigned long)regs->pc);
|
||||
if (reason == 0x5) {
|
||||
printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
|
||||
|
||||
/* There is only need to check for Hardware Errors, since other
|
||||
* EXCEPTIONS are handled in TRAPS.c (MH)
|
||||
*/
|
||||
switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
|
||||
case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): /* System MMR Error */
|
||||
info.si_code = BUS_ADRALN;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG HWC_x2);
|
||||
break;
|
||||
case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): /* External Memory Addressing Error */
|
||||
info.si_code = BUS_ADRERR;
|
||||
sig = SIGBUS;
|
||||
printk(KERN_EMERG HWC_x3);
|
||||
break;
|
||||
case (SEQSTAT_HWERRCAUSE_PERF_FLOW): /* Performance Monitor Overflow */
|
||||
printk(KERN_EMERG HWC_x12);
|
||||
break;
|
||||
case (SEQSTAT_HWERRCAUSE_RAISE_5): /* RAISE 5 instruction */
|
||||
printk(KERN_EMERG HWC_x18);
|
||||
break;
|
||||
default: /* Reserved */
|
||||
printk(KERN_EMERG HWC_default);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
regs->ipend = bfin_read_IPEND();
|
||||
dump_bfin_regs(regs, (void *)regs->pc);
|
||||
if (0 == (info.si_signo = sig) || 0 == user_mode(regs)) /* in kernelspace */
|
||||
panic("Unhandled IRQ or exceptions!\n");
|
||||
else { /* in userspace */
|
||||
info.si_errno = 0;
|
||||
info.si_addr = (void *)regs->pc;
|
||||
force_sig_info(sig, &info, current);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HARDWARE_PM
|
||||
/*
|
||||
* call the handler of Performance overflow
|
||||
*/
|
||||
asmlinkage void pm_overflow(int irq, struct pt_regs *regs)
|
||||
{
|
||||
pm_overflow_handler(irq, regs);
|
||||
}
|
||||
#endif
|
204
arch/blackfin/mach-common/lock.S
Normal file
204
arch/blackfin/mach-common/lock.S
Normal file
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/lock.S
|
||||
* Based on:
|
||||
* Author: LG Soft India
|
||||
*
|
||||
* Created: ?
|
||||
* Description: kernel locks
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/cplb.h>
|
||||
#include <asm/blackfin.h>
|
||||
|
||||
.text
|
||||
|
||||
#ifdef CONFIG_BLKFIN_CACHE_LOCK
|
||||
|
||||
/* When you come here, it is assumed that
|
||||
* R0 - Which way to be locked
|
||||
*/
|
||||
|
||||
ENTRY(_cache_grab_lock)
|
||||
|
||||
[--SP]=( R7:0,P5:0 );
|
||||
|
||||
P1.H = (IMEM_CONTROL >> 16);
|
||||
P1.L = (IMEM_CONTROL & 0xFFFF);
|
||||
P5.H = (ICPLB_ADDR0 >> 16);
|
||||
P5.L = (ICPLB_ADDR0 & 0xFFFF);
|
||||
P4.H = (ICPLB_DATA0 >> 16);
|
||||
P4.L = (ICPLB_DATA0 & 0xFFFF);
|
||||
R7 = R0;
|
||||
|
||||
/* If the code of interest already resides in the cache
|
||||
* invalidate the entire cache itself.
|
||||
* invalidate_entire_icache;
|
||||
*/
|
||||
|
||||
SP += -12;
|
||||
[--SP] = RETS;
|
||||
CALL _invalidate_entire_icache;
|
||||
RETS = [SP++];
|
||||
SP += 12;
|
||||
|
||||
/* Disable the Interrupts*/
|
||||
|
||||
CLI R3;
|
||||
|
||||
.LLOCK_WAY:
|
||||
|
||||
/* Way0 - 0xFFA133E0
|
||||
* Way1 - 0xFFA137E0
|
||||
* Way2 - 0xFFA13BE0 Total Way Size = 4K
|
||||
* Way3 - 0xFFA13FE0
|
||||
*/
|
||||
|
||||
/* Procedure Ex. -Set the locks for other ways by setting ILOC[3:1]
|
||||
* Only Way0 of the instruction cache can now be
|
||||
* replaced by a new code
|
||||
*/
|
||||
|
||||
R5 = R7;
|
||||
CC = BITTST(R7,0);
|
||||
IF CC JUMP .LCLEAR1;
|
||||
R7 = 0;
|
||||
BITSET(R7,0);
|
||||
JUMP .LDONE1;
|
||||
|
||||
.LCLEAR1:
|
||||
R7 = 0;
|
||||
BITCLR(R7,0);
|
||||
.LDONE1: R4 = R7 << 3;
|
||||
R7 = [P1];
|
||||
R7 = R7 | R4;
|
||||
SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P1] = R7;
|
||||
SSYNC;
|
||||
|
||||
R7 = R5;
|
||||
CC = BITTST(R7,1);
|
||||
IF CC JUMP .LCLEAR2;
|
||||
R7 = 0;
|
||||
BITSET(R7,1);
|
||||
JUMP .LDONE2;
|
||||
|
||||
.LCLEAR2:
|
||||
R7 = 0;
|
||||
BITCLR(R7,1);
|
||||
.LDONE2: R4 = R7 << 3;
|
||||
R7 = [P1];
|
||||
R7 = R7 | R4;
|
||||
SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P1] = R7;
|
||||
SSYNC;
|
||||
|
||||
R7 = R5;
|
||||
CC = BITTST(R7,2);
|
||||
IF CC JUMP .LCLEAR3;
|
||||
R7 = 0;
|
||||
BITSET(R7,2);
|
||||
JUMP .LDONE3;
|
||||
.LCLEAR3:
|
||||
R7 = 0;
|
||||
BITCLR(R7,2);
|
||||
.LDONE3: R4 = R7 << 3;
|
||||
R7 = [P1];
|
||||
R7 = R7 | R4;
|
||||
SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P1] = R7;
|
||||
SSYNC;
|
||||
|
||||
|
||||
R7 = R5;
|
||||
CC = BITTST(R7,3);
|
||||
IF CC JUMP .LCLEAR4;
|
||||
R7 = 0;
|
||||
BITSET(R7,3);
|
||||
JUMP .LDONE4;
|
||||
.LCLEAR4:
|
||||
R7 = 0;
|
||||
BITCLR(R7,3);
|
||||
.LDONE4: R4 = R7 << 3;
|
||||
R7 = [P1];
|
||||
R7 = R7 | R4;
|
||||
SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P1] = R7;
|
||||
SSYNC;
|
||||
|
||||
STI R3;
|
||||
|
||||
( R7:0,P5:0 ) = [SP++];
|
||||
|
||||
RTS;
|
||||
|
||||
/* After the execution of critical code, the code is now locked into
|
||||
* the cache way. Now we need to set ILOC.
|
||||
*
|
||||
* R0 - Which way to be locked
|
||||
*/
|
||||
|
||||
ENTRY(_cache_lock)
|
||||
|
||||
[--SP]=( R7:0,P5:0 );
|
||||
|
||||
P1.H = (IMEM_CONTROL >> 16);
|
||||
P1.L = (IMEM_CONTROL & 0xFFFF);
|
||||
|
||||
/* Disable the Interrupts*/
|
||||
CLI R3;
|
||||
|
||||
R7 = [P1];
|
||||
R2 = 0xFFFFFF87 (X);
|
||||
R7 = R7 & R2;
|
||||
R0 = R0 << 3;
|
||||
R7 = R0 | R7;
|
||||
SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
|
||||
.align 8;
|
||||
[P1] = R7;
|
||||
SSYNC;
|
||||
/* Renable the Interrupts */
|
||||
STI R3;
|
||||
|
||||
( R7:0,P5:0 ) = [SP++];
|
||||
RTS;
|
||||
|
||||
#endif /* BLKFIN_CACHE_LOCK */
|
||||
|
||||
/* Return the ILOC bits of IMEM_CONTROL
|
||||
*/
|
||||
|
||||
ENTRY(_read_iloc)
|
||||
|
||||
P1.H = (IMEM_CONTROL >> 16);
|
||||
P1.L = (IMEM_CONTROL & 0xFFFF);
|
||||
R1 = 0xF;
|
||||
R0 = [P1];
|
||||
R0 = R0 >> 3;
|
||||
R0 = R0 & R1;
|
||||
|
||||
RTS;
|
181
arch/blackfin/mach-common/pm.c
Normal file
181
arch/blackfin/mach-common/pm.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* File: arch/blackfin/mach-common/pm.c
|
||||
* Based on: arm/mach-omap/pm.c
|
||||
* Author: Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
|
||||
*
|
||||
* Created: 2001
|
||||
* Description: Power management for the bfin
|
||||
*
|
||||
* Modified: Nicolas Pitre - PXA250 support
|
||||
* Copyright (c) 2002 Monta Vista Software, Inc.
|
||||
* David Singleton - OMAP1510
|
||||
* Copyright (c) 2002 Monta Vista Software, Inc.
|
||||
* Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
|
||||
* Copyright 2004
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/pm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/dpmc.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
|
||||
#define WAKEUP_TYPE PM_WAKE_HIGH
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L
|
||||
#define WAKEUP_TYPE PM_WAKE_LOW
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F
|
||||
#define WAKEUP_TYPE PM_WAKE_FALLING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R
|
||||
#define WAKEUP_TYPE PM_WAKE_RISING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B
|
||||
#define WAKEUP_TYPE PM_WAKE_BOTH_EDGES
|
||||
#endif
|
||||
|
||||
void bfin_pm_suspend_standby_enter(void)
|
||||
{
|
||||
#ifdef CONFIG_PM_WAKEUP_BY_GPIO
|
||||
gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API)
|
||||
{
|
||||
u32 flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/
|
||||
|
||||
gpio_pm_restore();
|
||||
|
||||
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
|
||||
sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
|
||||
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
|
||||
#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* bfin_pm_prepare - Do preliminary suspend work.
|
||||
* @state: suspend state we're entering.
|
||||
*
|
||||
*/
|
||||
static int bfin_pm_prepare(suspend_state_t state)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (state) {
|
||||
case PM_SUSPEND_STANDBY:
|
||||
break;
|
||||
case PM_SUSPEND_MEM:
|
||||
return -ENOTSUPP;
|
||||
|
||||
case PM_SUSPEND_DISK:
|
||||
return -ENOTSUPP;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* bfin_pm_enter - Actually enter a sleep state.
|
||||
* @state: State we're entering.
|
||||
*
|
||||
*/
|
||||
static int bfin_pm_enter(suspend_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case PM_SUSPEND_STANDBY:
|
||||
bfin_pm_suspend_standby_enter();
|
||||
break;
|
||||
case PM_SUSPEND_MEM:
|
||||
return -ENOTSUPP;
|
||||
|
||||
case PM_SUSPEND_DISK:
|
||||
return -ENOTSUPP;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* bfin_pm_finish - Finish up suspend sequence.
|
||||
* @state: State we're coming out of.
|
||||
*
|
||||
* This is called after we wake back up (or if entering the sleep state
|
||||
* failed).
|
||||
*/
|
||||
static int bfin_pm_finish(suspend_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case PM_SUSPEND_STANDBY:
|
||||
break;
|
||||
|
||||
case PM_SUSPEND_MEM:
|
||||
return -ENOTSUPP;
|
||||
|
||||
case PM_SUSPEND_DISK:
|
||||
return -ENOTSUPP;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pm_ops bfin_pm_ops = {
|
||||
.pm_disk_mode = PM_DISK_PLATFORM,
|
||||
.prepare = bfin_pm_prepare,
|
||||
.enter = bfin_pm_enter,
|
||||
.finish = bfin_pm_finish,
|
||||
};
|
||||
|
||||
static int __init bfin_pm_init(void)
|
||||
{
|
||||
pm_set_ops(&bfin_pm_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(bfin_pm_init);
|
5
arch/blackfin/mm/Makefile
Normal file
5
arch/blackfin/mm/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# arch/blackfin/mm/Makefile
|
||||
#
|
||||
|
||||
obj-y := blackfin_sram.o init.o
|
540
arch/blackfin/mm/blackfin_sram.c
Normal file
540
arch/blackfin/mm/blackfin_sram.c
Normal file
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
* File: arch/blackfin/mm/blackfin_sram.c
|
||||
* Based on:
|
||||
* Author:
|
||||
*
|
||||
* Created:
|
||||
* Description: SRAM driver for Blackfin ADSP-BF5xx
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2004-2006 Analog Devices Inc.
|
||||
*
|
||||
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* 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, see the file COPYING, or write
|
||||
* to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/autoconf.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <asm/blackfin.h>
|
||||
#include "blackfin_sram.h"
|
||||
|
||||
spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
|
||||
|
||||
#if CONFIG_L1_MAX_PIECE < 16
|
||||
#undef CONFIG_L1_MAX_PIECE
|
||||
#define CONFIG_L1_MAX_PIECE 16
|
||||
#endif
|
||||
|
||||
#if CONFIG_L1_MAX_PIECE > 1024
|
||||
#undef CONFIG_L1_MAX_PIECE
|
||||
#define CONFIG_L1_MAX_PIECE 1024
|
||||
#endif
|
||||
|
||||
#define SRAM_SLT_NULL 0
|
||||
#define SRAM_SLT_FREE 1
|
||||
#define SRAM_SLT_ALLOCATED 2
|
||||
|
||||
/* the data structure for L1 scratchpad and DATA SRAM */
|
||||
struct l1_sram_piece {
|
||||
void *paddr;
|
||||
int size;
|
||||
int flag;
|
||||
};
|
||||
|
||||
static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE];
|
||||
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE];
|
||||
#endif
|
||||
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE];
|
||||
#endif
|
||||
|
||||
#if L1_CODE_LENGTH != 0
|
||||
static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE];
|
||||
#endif
|
||||
|
||||
/* L1 Scratchpad SRAM initialization function */
|
||||
void l1sram_init(void)
|
||||
{
|
||||
printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
|
||||
L1_SCRATCH_LENGTH >> 10);
|
||||
|
||||
memset(&l1_ssram, 0x00, sizeof(l1_ssram));
|
||||
l1_ssram[0].paddr = (void*)L1_SCRATCH_START;
|
||||
l1_ssram[0].size = L1_SCRATCH_LENGTH;
|
||||
l1_ssram[0].flag = SRAM_SLT_FREE;
|
||||
|
||||
/* mutex initialize */
|
||||
spin_lock_init(&l1sram_lock);
|
||||
}
|
||||
|
||||
void l1_data_sram_init(void)
|
||||
{
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n",
|
||||
L1_DATA_A_LENGTH >> 10);
|
||||
|
||||
memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram));
|
||||
l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START +
|
||||
(_ebss_l1 - _sdata_l1);
|
||||
l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
|
||||
l1_data_A_sram[0].flag = SRAM_SLT_FREE;
|
||||
#endif
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n",
|
||||
L1_DATA_B_LENGTH >> 10);
|
||||
|
||||
memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram));
|
||||
l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START;
|
||||
l1_data_B_sram[0].size = L1_DATA_B_LENGTH;
|
||||
l1_data_B_sram[0].flag = SRAM_SLT_FREE;
|
||||
#endif
|
||||
|
||||
/* mutex initialize */
|
||||
spin_lock_init(&l1_data_sram_lock);
|
||||
}
|
||||
|
||||
void l1_inst_sram_init(void)
|
||||
{
|
||||
#if L1_CODE_LENGTH != 0
|
||||
printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n",
|
||||
L1_CODE_LENGTH >> 10);
|
||||
|
||||
memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram));
|
||||
l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1);
|
||||
l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
|
||||
l1_inst_sram[0].flag = SRAM_SLT_FREE;
|
||||
#endif
|
||||
|
||||
/* mutex initialize */
|
||||
spin_lock_init(&l1_inst_sram_lock);
|
||||
}
|
||||
|
||||
/* L1 memory allocate function */
|
||||
static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count)
|
||||
{
|
||||
int i, index = 0;
|
||||
void *addr = NULL;
|
||||
|
||||
if (size <= 0)
|
||||
return NULL;
|
||||
|
||||
/* Align the size */
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
/* not use the good method to match the best slot !!! */
|
||||
/* search an available memeory slot */
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((pfree[i].flag == SRAM_SLT_FREE)
|
||||
&& (pfree[i].size >= size)) {
|
||||
addr = pfree[i].paddr;
|
||||
pfree[i].flag = SRAM_SLT_ALLOCATED;
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= count)
|
||||
return NULL;
|
||||
|
||||
/* updated the NULL memeory slot !!! */
|
||||
if (pfree[i].size > size) {
|
||||
for (i = 0; i < count; i++) {
|
||||
if (pfree[i].flag == SRAM_SLT_NULL) {
|
||||
pfree[i].flag = SRAM_SLT_FREE;
|
||||
pfree[i].paddr = addr + size;
|
||||
pfree[i].size = pfree[index].size - size;
|
||||
pfree[index].size = size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* Allocate the largest available block. */
|
||||
static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count,
|
||||
unsigned long *psize)
|
||||
{
|
||||
unsigned long best = 0;
|
||||
int i, index = -1;
|
||||
void *addr = NULL;
|
||||
|
||||
/* search an available memeory slot */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) {
|
||||
addr = pfree[i].paddr;
|
||||
index = i;
|
||||
best = pfree[i].size;
|
||||
}
|
||||
}
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
*psize = best;
|
||||
|
||||
pfree[index].flag = SRAM_SLT_ALLOCATED;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* L1 memory free function */
|
||||
static int _l1_sram_free(const void *addr,
|
||||
struct l1_sram_piece *pfree, int count)
|
||||
{
|
||||
int i, index = 0;
|
||||
|
||||
/* search the relevant memory slot */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (pfree[i].paddr == addr) {
|
||||
if (pfree[i].flag != SRAM_SLT_ALLOCATED) {
|
||||
/* error log */
|
||||
return -1;
|
||||
}
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= count)
|
||||
return -1;
|
||||
|
||||
pfree[index].flag = SRAM_SLT_FREE;
|
||||
|
||||
/* link the next address slot */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr)
|
||||
&& (pfree[i].flag == SRAM_SLT_FREE)) {
|
||||
pfree[i].flag = SRAM_SLT_NULL;
|
||||
pfree[index].size += pfree[i].size;
|
||||
pfree[index].flag = SRAM_SLT_FREE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* link the last address slot */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) &&
|
||||
(pfree[i].flag == SRAM_SLT_FREE)) {
|
||||
pfree[index].flag = SRAM_SLT_NULL;
|
||||
pfree[i].size += pfree[index].size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sram_free(const void *addr)
|
||||
{
|
||||
if (0) {}
|
||||
#if L1_CODE_LENGTH != 0
|
||||
else if (addr >= (void *)L1_CODE_START
|
||||
&& addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
|
||||
return l1_inst_sram_free(addr);
|
||||
#endif
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
else if (addr >= (void *)L1_DATA_A_START
|
||||
&& addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
|
||||
return l1_data_A_sram_free(addr);
|
||||
#endif
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
else if (addr >= (void *)L1_DATA_B_START
|
||||
&& addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
|
||||
return l1_data_B_sram_free(addr);
|
||||
#endif
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(sram_free);
|
||||
|
||||
void *l1_data_A_sram_alloc(size_t size)
|
||||
{
|
||||
unsigned flags;
|
||||
void *addr = NULL;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_data_sram_lock, flags);
|
||||
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
|
||||
#endif
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_data_sram_lock, flags);
|
||||
|
||||
pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
|
||||
(long unsigned int)addr, size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_A_sram_alloc);
|
||||
|
||||
int l1_data_A_sram_free(const void *addr)
|
||||
{
|
||||
unsigned flags;
|
||||
int ret;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_data_sram_lock, flags);
|
||||
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
ret = _l1_sram_free(addr,
|
||||
l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
|
||||
#else
|
||||
ret = -1;
|
||||
#endif
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_data_sram_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_A_sram_free);
|
||||
|
||||
void *l1_data_B_sram_alloc(size_t size)
|
||||
{
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
unsigned flags;
|
||||
void *addr;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_data_sram_lock, flags);
|
||||
|
||||
addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_data_sram_lock, flags);
|
||||
|
||||
pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
|
||||
(long unsigned int)addr, size);
|
||||
|
||||
return addr;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_B_sram_alloc);
|
||||
|
||||
int l1_data_B_sram_free(const void *addr)
|
||||
{
|
||||
#if L1_DATA_B_LENGTH != 0
|
||||
unsigned flags;
|
||||
int ret;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_data_sram_lock, flags);
|
||||
|
||||
ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_data_sram_lock, flags);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_B_sram_free);
|
||||
|
||||
void *l1_data_sram_alloc(size_t size)
|
||||
{
|
||||
void *addr = l1_data_A_sram_alloc(size);
|
||||
|
||||
if (!addr)
|
||||
addr = l1_data_B_sram_alloc(size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_sram_alloc);
|
||||
|
||||
void *l1_data_sram_zalloc(size_t size)
|
||||
{
|
||||
void *addr = l1_data_sram_alloc(size);
|
||||
|
||||
if (addr)
|
||||
memset(addr, 0x00, size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_sram_zalloc);
|
||||
|
||||
int l1_data_sram_free(const void *addr)
|
||||
{
|
||||
int ret;
|
||||
ret = l1_data_A_sram_free(addr);
|
||||
if (ret == -1)
|
||||
ret = l1_data_B_sram_free(addr);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(l1_data_sram_free);
|
||||
|
||||
void *l1_inst_sram_alloc(size_t size)
|
||||
{
|
||||
#if L1_DATA_A_LENGTH != 0
|
||||
unsigned flags;
|
||||
void *addr;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_inst_sram_lock, flags);
|
||||
|
||||
addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
|
||||
|
||||
pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
|
||||
(long unsigned int)addr, size);
|
||||
|
||||
return addr;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(l1_inst_sram_alloc);
|
||||
|
||||
int l1_inst_sram_free(const void *addr)
|
||||
{
|
||||
#if L1_CODE_LENGTH != 0
|
||||
unsigned flags;
|
||||
int ret;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1_inst_sram_lock, flags);
|
||||
|
||||
ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(l1_inst_sram_free);
|
||||
|
||||
/* L1 Scratchpad memory allocate function */
|
||||
void *l1sram_alloc(size_t size)
|
||||
{
|
||||
unsigned flags;
|
||||
void *addr;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1sram_lock, flags);
|
||||
|
||||
addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1sram_lock, flags);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* L1 Scratchpad memory allocate function */
|
||||
void *l1sram_alloc_max(size_t *psize)
|
||||
{
|
||||
unsigned flags;
|
||||
void *addr;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1sram_lock, flags);
|
||||
|
||||
addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize);
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1sram_lock, flags);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* L1 Scratchpad memory free function */
|
||||
int l1sram_free(const void *addr)
|
||||
{
|
||||
unsigned flags;
|
||||
int ret;
|
||||
|
||||
/* add mutex operation */
|
||||
spin_lock_irqsave(&l1sram_lock, flags);
|
||||
|
||||
ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram));
|
||||
|
||||
/* add mutex operation */
|
||||
spin_unlock_irqrestore(&l1sram_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sram_free_with_lsl(const void *addr)
|
||||
{
|
||||
struct sram_list_struct *lsl, **tmp;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
|
||||
if ((*tmp)->addr == addr)
|
||||
goto found;
|
||||
return -1;
|
||||
found:
|
||||
lsl = *tmp;
|
||||
sram_free(addr);
|
||||
*tmp = lsl->next;
|
||||
kfree(lsl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sram_free_with_lsl);
|
||||
|
||||
void *sram_alloc_with_lsl(size_t size, unsigned long flags)
|
||||
{
|
||||
void *addr = NULL;
|
||||
struct sram_list_struct *lsl = NULL;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
|
||||
if (!lsl)
|
||||
return NULL;
|
||||
memset(lsl, 0, sizeof(*lsl));
|
||||
|
||||
if (flags & L1_INST_SRAM)
|
||||
addr = l1_inst_sram_alloc(size);
|
||||
|
||||
if (addr == NULL && (flags & L1_DATA_A_SRAM))
|
||||
addr = l1_data_A_sram_alloc(size);
|
||||
|
||||
if (addr == NULL && (flags & L1_DATA_B_SRAM))
|
||||
addr = l1_data_B_sram_alloc(size);
|
||||
|
||||
if (addr == NULL) {
|
||||
kfree(lsl);
|
||||
return NULL;
|
||||
}
|
||||
lsl->addr = addr;
|
||||
lsl->length = size;
|
||||
lsl->next = mm->context.sram_list;
|
||||
mm->context.sram_list = lsl;
|
||||
return addr;
|
||||
}
|
||||
EXPORT_SYMBOL(sram_alloc_with_lsl);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue