Merge branch 'cris' of git://www.jni.nu/cris
* 'cris' of git://www.jni.nu/cris: (158 commits) CRIS v32: Remove hwregs/timer_defs.h, it is now architecture specific. CRIS v32: Change drivers/i2c.c locking. CRIS v32: Rewrite ARTPEC-3 gpio driver to avoid volatiles and general cleanup. CRIS: Add new timerfd syscall entries. MAINTAINERS: Add my information for the CRIS port. CRIS v32: Correct spelling of bandwidth in function name. CRIS v32: Clean up nandflash.c for ARTPEC-3 and ETRAX FS. CRIS v10: Cleanup of drivers/gpio.c CRIS v10: drivers/net/cris/eth_v10.c rename LED defines to CRIS_LED to avoid name clash. CRIS: Make io_pwm_set_period members unsigned in etraxgpio.h CRIS: Move ETRAX_AXISFLASHMAP to common Kconfig file. CRIS: Drop regs parameter from call to profile_tick in kernel/time.c CRIS v32: Fix minor formatting issue in mach-a3/io.c CRIS v32: Initialize GIO even if we're rambooting in kernel/head.S CRIS v32: Remove kernel/arbiter.c, it now exists in machine dependent directory. CRIS v32: Minor changes to avoid errors in asm-cris/arch-v32/hwregs/reg_rdwr.h CRIS v32: arch-v32/hwregs/intr_vect_defs.h moved to machine dependent directory. CRIS v32: Correct offset for TASK_pid in asm-cris/arch-v32/offset.h CRIS v32: Move register map header to machine dependent directory. CRIS v32: Let compiler know that memory is clobbered after a break op. ...
This commit is contained in:
commit
0cf975e169
|
@ -1173,6 +1173,8 @@ S: Orphan
|
|||
CRIS PORT
|
||||
P: Mikael Starvik
|
||||
M: starvik@axis.com
|
||||
P: Jesper Nilsson
|
||||
M: jesper.nilsson@axis.com
|
||||
L: dev-etrax@axis.com
|
||||
W: http://developer.axis.com
|
||||
S: Maintained
|
||||
|
|
|
@ -13,10 +13,6 @@ config ZONE_DMA
|
|||
bool
|
||||
default y
|
||||
|
||||
config NO_DMA
|
||||
bool
|
||||
default y
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
default y
|
||||
|
@ -24,6 +20,10 @@ config RWSEM_GENERIC_SPINLOCK
|
|||
config RWSEM_XCHGADD_ALGORITHM
|
||||
bool
|
||||
|
||||
config GENERIC_IOMAP
|
||||
bool
|
||||
default y
|
||||
|
||||
config ARCH_HAS_ILOG2_U32
|
||||
bool
|
||||
default n
|
||||
|
@ -44,13 +44,13 @@ config GENERIC_CALIBRATE_DELAY
|
|||
bool
|
||||
default y
|
||||
|
||||
config IRQ_PER_CPU
|
||||
bool
|
||||
default y
|
||||
|
||||
config NO_IOPORT
|
||||
def_bool y
|
||||
|
||||
config FORCE_MAX_ZONEORDER
|
||||
int
|
||||
default 6
|
||||
|
||||
config CRIS
|
||||
bool
|
||||
default y
|
||||
|
@ -97,17 +97,15 @@ config ETRAX_FAST_TIMER
|
|||
timers).
|
||||
This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled.
|
||||
|
||||
config PREEMPT
|
||||
bool "Preemptible Kernel"
|
||||
config ETRAX_KMALLOCED_MODULES
|
||||
bool "Enable module allocation with kmalloc"
|
||||
help
|
||||
This option reduces the latency of the kernel when reacting to
|
||||
real-time or interactive events by allowing a low priority process to
|
||||
be preempted even if it is in kernel mode executing a system call.
|
||||
This allows applications to run more reliably even when the system is
|
||||
under load.
|
||||
Enable module allocation with kmalloc instead of vmalloc.
|
||||
|
||||
Say Y here if you are building a kernel for a desktop, embedded
|
||||
or real-time system. Say N if you are unsure.
|
||||
config OOM_REBOOT
|
||||
bool "Enable reboot at out of memory"
|
||||
|
||||
source "kernel/Kconfig.preempt"
|
||||
|
||||
source mm/Kconfig
|
||||
|
||||
|
@ -134,24 +132,124 @@ config SVINTO_SIM
|
|||
help
|
||||
Support the xsim ETRAX Simulator.
|
||||
|
||||
config ETRAXFS
|
||||
bool "ETRAX-FS-V32"
|
||||
help
|
||||
Support CRIS V32.
|
||||
|
||||
config CRIS_MACH_ARTPEC3
|
||||
bool "ARTPEC-3"
|
||||
help
|
||||
Support Axis ARTPEC-3.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_VCS_SIM
|
||||
bool "VCS Simulator"
|
||||
help
|
||||
Setup hardware to be run in the VCS simulator.
|
||||
|
||||
config ETRAX_ARCH_V10
|
||||
bool
|
||||
default y if ETRAX100LX || ETRAX100LX_V2
|
||||
default n if !(ETRAX100LX || ETRAX100LX_V2)
|
||||
|
||||
config ETRAX_ARCH_V32
|
||||
bool
|
||||
default y if (ETRAXFS || CRIS_MACH_ARTPEC3)
|
||||
default n if !(ETRAXFS || CRIS_MACH_ARTPEC3)
|
||||
|
||||
config ETRAX_DRAM_SIZE
|
||||
int "DRAM size (dec, in MB)"
|
||||
default "8"
|
||||
help
|
||||
Size of DRAM (decimal in MB) typically 2, 8 or 16.
|
||||
|
||||
config ETRAX_VMEM_SIZE
|
||||
int "Video memory size (dec, in MB)"
|
||||
depends on ETRAX_ARCH_V32 && !ETRAXFS
|
||||
default 8 if !ETRAXFS
|
||||
help
|
||||
Size of Video accessible memory (decimal, in MB).
|
||||
|
||||
config ETRAX_FLASH_BUSWIDTH
|
||||
int "Buswidth of flash in bytes"
|
||||
int "Buswidth of NOR flash in bytes"
|
||||
default "2"
|
||||
help
|
||||
Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
|
||||
Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2.
|
||||
|
||||
config ETRAX_NANDFLASH_BUSWIDTH
|
||||
int "Buswidth of NAND flash in bytes"
|
||||
default "1"
|
||||
help
|
||||
Width in bytes of the NAND flash (1 or 2).
|
||||
|
||||
config ETRAX_FLASH1_SIZE
|
||||
int "FLASH1 size (dec, in MB. 0 = Unknown)"
|
||||
default "0"
|
||||
|
||||
choice
|
||||
prompt "Product debug-port"
|
||||
default ETRAX_DEBUG_PORT0
|
||||
|
||||
config ETRAX_DEBUG_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Choose a serial port for the ETRAX debug console. Default to
|
||||
port 0.
|
||||
|
||||
config ETRAX_DEBUG_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT_NULL
|
||||
bool "disabled"
|
||||
help
|
||||
Disable serial-port debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Kernel GDB port"
|
||||
depends on ETRAX_KGDB
|
||||
default ETRAX_KGDB_PORT0
|
||||
help
|
||||
Choose a serial port for kernel debugging. NOTE: This port should
|
||||
not be enabled under Drivers for built-in interfaces (as it has its
|
||||
own initialization code) and should not be the same as the debug port.
|
||||
|
||||
config ETRAX_KGDB_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Use serial port 0 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for kernel debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
source arch/cris/arch-v10/Kconfig
|
||||
source arch/cris/arch-v32/Kconfig
|
||||
|
@ -165,6 +263,387 @@ menu "Drivers for built-in interfaces"
|
|||
source arch/cris/arch-v10/drivers/Kconfig
|
||||
source arch/cris/arch-v32/drivers/Kconfig
|
||||
|
||||
config ETRAX_AXISFLASHMAP
|
||||
bool "Axis flash-map support"
|
||||
select MTD
|
||||
select MTD_CFI
|
||||
select MTD_CFI_AMDSTD
|
||||
select MTD_JEDECPROBE if ETRAX_ARCH_V32
|
||||
select MTD_CHAR
|
||||
select MTD_BLOCK
|
||||
select MTD_PARTITIONS
|
||||
select MTD_CONCAT
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
This option enables MTD mapping of flash devices. Needed to use
|
||||
flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_RTC
|
||||
bool "Real Time Clock support"
|
||||
depends on ETRAX_I2C
|
||||
help
|
||||
Enables drivers for the Real-Time Clock battery-backed chips on
|
||||
some products. The kernel reads the time when booting, and
|
||||
the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
|
||||
rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
|
||||
device. You can check the time with cat /proc/rtc, but
|
||||
normal time reading should be done using libc function time and
|
||||
friends.
|
||||
|
||||
choice
|
||||
prompt "RTC chip"
|
||||
depends on ETRAX_RTC
|
||||
default ETRAX_PCF8563 if ETRAX_ARCH_V32
|
||||
default ETRAX_DS1302 if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_DS1302
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "DS1302"
|
||||
help
|
||||
Enables the driver for the DS1302 Real-Time Clock battery-backed
|
||||
chip on some products.
|
||||
|
||||
config ETRAX_PCF8563
|
||||
bool "PCF8563"
|
||||
help
|
||||
Enables the driver for the PCF8563 Real-Time Clock battery-backed
|
||||
chip on some products.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL
|
||||
bool "Synchronous serial-port support"
|
||||
help
|
||||
Select this to enable the synchronous serial port driver.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL_PORT0
|
||||
bool "Synchronous serial port 0 enabled"
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL
|
||||
help
|
||||
Enabled synchronous serial port 0.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL0_DMA
|
||||
bool "Enable DMA on synchronous serial port 0."
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0
|
||||
help
|
||||
A synchronous serial port can run in manual or DMA mode.
|
||||
Selecting this option will make it run in DMA mode.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL_PORT1
|
||||
bool "Synchronous serial port 1 enabled"
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL && (ETRAXFS || ETRAX_ARCH_V10)
|
||||
help
|
||||
Enabled synchronous serial port 1.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL1_DMA
|
||||
bool "Enable DMA on synchronous serial port 1."
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1
|
||||
help
|
||||
A synchronous serial port can run in manual or DMA mode.
|
||||
Selecting this option will make it run in DMA mode.
|
||||
|
||||
choice
|
||||
prompt "Network LED behavior"
|
||||
depends on ETRAX_ETHERNET
|
||||
default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_LINK
|
||||
bool "LED_on_when_link"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
bool "LED_on_when_activity"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_DMA6_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_OUT
|
||||
bool "Ser0 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser0 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA6_OUT
|
||||
bool "Ser0 uses DMA6 for output"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA6 output channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA0_OUT
|
||||
bool "Ser0 uses DMA0 for output"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA0 output channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA in channel "
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT0_DMA7_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser0.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_IN
|
||||
bool "Ser0 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser0 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
bool "Ser0 uses DMA7 for input"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA7 input channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA1_IN
|
||||
bool "Ser0 uses DMA1 for input"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA1 input channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiveing data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA in channel "
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT1_DMA9_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_IN
|
||||
bool "Ser1 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser1 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA5_IN
|
||||
bool "Ser1 uses DMA5 for input"
|
||||
depends on ETRAX_ARCH_V32
|
||||
help
|
||||
Enables the DMA5 input channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA9_IN
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "Ser1 uses DMA9 for input"
|
||||
|
||||
endchoice
|
||||
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT1_DMA8_OUT if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_OUT
|
||||
bool "Ser1 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser1 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA8_OUT
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "Ser1 uses DMA8 for output"
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA4_OUT
|
||||
depends on ETRAX_ARCH_V32
|
||||
bool "Ser1 uses DMA4 for output"
|
||||
help
|
||||
Enables the DMA4 output channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT2_DMA2_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_OUT
|
||||
bool "Ser2 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser2 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA2_OUT
|
||||
bool "Ser2 uses DMA2 for output"
|
||||
depends on ETRAXFS || ETRAX_ARCH_V10
|
||||
help
|
||||
Enables the DMA2 output channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA6_OUT
|
||||
bool "Ser2 uses DMA6 for output"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA6 output channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA in channel"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT2_DMA3_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser2.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_IN
|
||||
bool "Ser2 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser2 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA3_IN
|
||||
bool "Ser2 uses DMA3 for input"
|
||||
depends on ETRAXFS || ETRAX_ARCH_V10
|
||||
help
|
||||
Enables the DMA3 input channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA7_IN
|
||||
bool "Ser2 uses DMA7 for input"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA7 input channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiveing data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA in channel"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_IN if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT3_DMA5_IN if ETRAX_ARCH_V10
|
||||
help
|
||||
What DMA channel to use for ser3.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_IN
|
||||
bool "Ser3 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser3 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA5_IN
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "DMA 5"
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA9_IN
|
||||
bool "Ser3 uses DMA9 for input"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA9 input channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA3_IN
|
||||
bool "Ser3 uses DMA3 for input"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA3 input channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiveing data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_OUT if ETRAX_ARCH_V32
|
||||
default ETRAX_SERIAL_PORT3_DMA4_OUT if ETRAX_ARCH_V10
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_OUT
|
||||
bool "Ser3 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser3 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA4_OUT
|
||||
depends on ETRAX_ARCH_V10
|
||||
bool "DMA 4"
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA8_OUT
|
||||
bool "Ser3 uses DMA8 for output"
|
||||
depends on ETRAXFS
|
||||
help
|
||||
Enables the DMA8 output channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA2_OUT
|
||||
bool "Ser3 uses DMA2 for output"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the DMA2 output channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/base/Kconfig"
|
||||
|
@ -178,22 +657,10 @@ source "drivers/pnp/Kconfig"
|
|||
|
||||
source "drivers/block/Kconfig"
|
||||
|
||||
source "drivers/md/Kconfig"
|
||||
|
||||
source "drivers/ide/Kconfig"
|
||||
|
||||
source "drivers/scsi/Kconfig"
|
||||
|
||||
source "drivers/ieee1394/Kconfig"
|
||||
|
||||
source "drivers/message/i2o/Kconfig"
|
||||
|
||||
source "drivers/net/Kconfig"
|
||||
|
||||
source "drivers/isdn/Kconfig"
|
||||
|
||||
source "drivers/telephony/Kconfig"
|
||||
|
||||
source "drivers/i2c/Kconfig"
|
||||
|
||||
source "drivers/rtc/Kconfig"
|
||||
|
@ -205,17 +672,8 @@ source "drivers/input/Kconfig"
|
|||
|
||||
source "drivers/char/Kconfig"
|
||||
|
||||
#source drivers/misc/Config.in
|
||||
source "drivers/media/Kconfig"
|
||||
|
||||
source "fs/Kconfig"
|
||||
|
||||
source "sound/Kconfig"
|
||||
|
||||
source "drivers/pcmcia/Kconfig"
|
||||
|
||||
source "drivers/pci/Kconfig"
|
||||
|
||||
source "drivers/usb/Kconfig"
|
||||
|
||||
source "arch/cris/Kconfig.debug"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile,v 1.28 2005/03/17 10:44:37 larsv Exp $
|
||||
#
|
||||
# cris/Makefile
|
||||
#
|
||||
# This file is included by the global makefile so that you can add your own
|
||||
|
@ -10,28 +10,36 @@
|
|||
# License. See the file "COPYING" in the main directory of this archive
|
||||
# for more details.
|
||||
|
||||
# A bug in ld prevents us from having a (constant-value) symbol in a
|
||||
# "ORIGIN =" or "LENGTH =" expression.
|
||||
|
||||
arch-y := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V10) := v10
|
||||
arch-$(CONFIG_ETRAX_ARCH_V32) := v32
|
||||
|
||||
# No config avaiable for make clean etc
|
||||
# No config available for make clean etc
|
||||
mach-y := fs
|
||||
mach-$(CONFIG_CRIS_MACH_ARTPEC3) := a3
|
||||
mach-$(CONFIG_ETRAXFS) := fs
|
||||
|
||||
ifneq ($(arch-y),)
|
||||
SARCH := arch-$(arch-y)
|
||||
else
|
||||
SARCH :=
|
||||
endif
|
||||
|
||||
ifneq ($(mach-y),)
|
||||
MACH := mach-$(mach-y)
|
||||
else
|
||||
MACH :=
|
||||
endif
|
||||
|
||||
LD = $(CROSS_COMPILE)ld -mcrislinux
|
||||
|
||||
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
|
||||
|
||||
CPPFLAGS_vmlinux.lds = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)
|
||||
KBUILD_AFLAGS += -mlinux
|
||||
|
||||
KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe
|
||||
KBUILD_AFLAGS += -mlinux -march=$(arch-y) -Iinclude/asm/arch/mach -Iinclude/asm/arch
|
||||
|
||||
KBUILD_CFLAGS += -mlinux -march=$(arch-y) -pipe -Iinclude/asm/arch/mach -Iinclude/asm/arch
|
||||
|
||||
ifdef CONFIG_FRAME_POINTER
|
||||
KBUILD_CFLAGS := $(subst -fomit-frame-pointer,,$(KBUILD_CFLAGS)) -g
|
||||
|
@ -44,6 +52,9 @@ LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a)
|
|||
|
||||
core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
|
||||
core-y += arch/$(ARCH)/$(SARCH)/kernel/ arch/$(ARCH)/$(SARCH)/mm/
|
||||
ifdef CONFIG_ETRAX_ARCH_V32
|
||||
core-y += arch/$(ARCH)/$(SARCH)/$(MACH)/
|
||||
endif
|
||||
drivers-y += arch/$(ARCH)/$(SARCH)/drivers/
|
||||
libs-y += arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC)
|
||||
|
||||
|
@ -52,79 +63,69 @@ SRC_ARCH = $(srctree)/arch/$(ARCH)
|
|||
# cris object files path
|
||||
OBJ_ARCH = $(objtree)/arch/$(ARCH)
|
||||
|
||||
target_boot_arch_dir = $(OBJ_ARCH)/$(SARCH)/boot
|
||||
target_boot_dir = $(OBJ_ARCH)/boot
|
||||
src_boot_dir = $(SRC_ARCH)/boot
|
||||
target_compressed_dir = $(OBJ_ARCH)/boot/compressed
|
||||
src_compressed_dir = $(SRC_ARCH)/boot/compressed
|
||||
target_rescue_dir = $(OBJ_ARCH)/boot/rescue
|
||||
src_rescue_dir = $(SRC_ARCH)/boot/rescue
|
||||
boot := arch/$(ARCH)/boot
|
||||
MACHINE := arch/$(ARCH)/$(SARCH)
|
||||
|
||||
export target_boot_arch_dir target_boot_dir src_boot_dir target_compressed_dir src_compressed_dir target_rescue_dir src_rescue_dir
|
||||
all: zImage
|
||||
|
||||
vmlinux.bin: vmlinux
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin
|
||||
zImage Image: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
|
||||
|
||||
timage: vmlinux.bin
|
||||
cat vmlinux.bin cramfs.img >timage
|
||||
|
||||
simimage: timage
|
||||
cp vmlinux.bin simvmlinux.bin
|
||||
|
||||
# the following will remake timage without compiling the kernel
|
||||
# it does of course require that all object files exist...
|
||||
|
||||
cramfs:
|
||||
## cramfs - Creates a cramfs image
|
||||
mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img
|
||||
cat vmlinux.bin cramfs.img >timage
|
||||
|
||||
clinux: vmlinux.bin decompress.bin rescue.bin
|
||||
|
||||
decompress.bin: $(target_boot_dir)
|
||||
@$(MAKE) -f $(src_compressed_dir)/Makefile $(target_compressed_dir)/decompress.bin
|
||||
|
||||
$(target_rescue_dir)/rescue.bin: $(target_boot_dir)
|
||||
@$(MAKE) -f $(src_rescue_dir)/Makefile $(target_rescue_dir)/rescue.bin
|
||||
|
||||
zImage: $(target_boot_dir) vmlinux.bin $(target_rescue_dir)/rescue.bin
|
||||
## zImage - Compressed kernel (gzip)
|
||||
@$(MAKE) -f $(src_boot_dir)/Makefile zImage
|
||||
|
||||
$(target_boot_dir): $(target_boot_arch_dir)
|
||||
ln -sfn $< $@
|
||||
|
||||
$(target_boot_arch_dir):
|
||||
mkdir -p $@
|
||||
|
||||
compressed: zImage
|
||||
|
||||
archmrproper:
|
||||
archclean:
|
||||
@if [ -d arch/$(ARCH)/boot ]; then \
|
||||
$(MAKE) $(clean)=arch/$(ARCH)/boot ; \
|
||||
fi
|
||||
rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img
|
||||
rm -rf $(LD_SCRIPT).tmp
|
||||
|
||||
archprepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch
|
||||
archprepare: $(SRC_ARCH)/.links $(srctree)/include/asm-$(ARCH)/.arch FORCE
|
||||
|
||||
# Create some links to make all tools happy
|
||||
$(SRC_ARCH)/.links:
|
||||
@rm -rf $(SRC_ARCH)/drivers
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH)/drivers $(SRC_ARCH)/drivers
|
||||
@ln -sfn $(SARCH)/drivers $(SRC_ARCH)/drivers
|
||||
@rm -rf $(SRC_ARCH)/boot
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH)/boot $(SRC_ARCH)/boot
|
||||
@ln -sfn $(SARCH)/boot $(SRC_ARCH)/boot
|
||||
@rm -rf $(SRC_ARCH)/lib
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH)/lib $(SRC_ARCH)/lib
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH) $(SRC_ARCH)/arch
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH)/vmlinux.lds.S $(SRC_ARCH)/kernel/vmlinux.lds.S
|
||||
@ln -sfn $(SRC_ARCH)/$(SARCH)/kernel/asm-offsets.c $(SRC_ARCH)/kernel/asm-offsets.c
|
||||
@ln -sfn $(SARCH)/lib $(SRC_ARCH)/lib
|
||||
@rm -f $(SRC_ARCH)/arch/mach
|
||||
@rm -rf $(SRC_ARCH)/arch
|
||||
@ln -sfn $(SARCH) $(SRC_ARCH)/arch
|
||||
ifdef CONFIG_ETRAX_ARCH_V32
|
||||
@ln -sfn ../$(SARCH)/$(MACH) $(SRC_ARCH)/arch/mach
|
||||
endif
|
||||
@rm -rf $(SRC_ARCH)/kernel/vmlinux.lds.S
|
||||
@ln -sfn ../$(SARCH)/vmlinux.lds.S $(SRC_ARCH)/kernel/vmlinux.lds.S
|
||||
@rm -rf $(SRC_ARCH)/kernel/asm-offsets.c
|
||||
@ln -sfn ../$(SARCH)/kernel/asm-offsets.c $(SRC_ARCH)/kernel/asm-offsets.c
|
||||
@touch $@
|
||||
|
||||
# Create link to sub arch includes
|
||||
$(srctree)/include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h)
|
||||
@echo ' Making $(srctree)/include/asm-$(ARCH)/arch -> $(srctree)/include/asm-$(ARCH)/$(SARCH) symlink'
|
||||
@rm -f include/asm-$(ARCH)/arch
|
||||
@ln -sf $(srctree)/include/asm-$(ARCH)/$(SARCH) $(srctree)/include/asm-$(ARCH)/arch
|
||||
@echo ' SYMLINK include/asm-$(ARCH)/arch -> include/asm-$(ARCH)/$(SARCH)'
|
||||
@rm -f $(srctree)/include/asm-$(ARCH)/arch/mach
|
||||
@rm -f $(srctree)/include/asm-$(ARCH)/arch
|
||||
@ln -sf $(SARCH) $(srctree)/include/asm-$(ARCH)/arch
|
||||
ifdef CONFIG_ETRAX_ARCH_V32
|
||||
@ln -sf $(MACH) $(srctree)/include/asm-$(ARCH)/arch/mach
|
||||
endif
|
||||
@touch $@
|
||||
|
||||
archclean:
|
||||
$(Q)if [ -e arch/$(ARCH)/boot ]; then \
|
||||
$(MAKE) $(clean)=arch/$(ARCH)/boot; \
|
||||
fi
|
||||
|
||||
CLEAN_FILES += \
|
||||
$(MACHINE)/boot/zImage \
|
||||
$(MACHINE)/boot/compressed/decompress.bin \
|
||||
$(MACHINE)/boot/compressed/piggy.gz \
|
||||
$(MACHINE)/boot/rescue/rescue.bin \
|
||||
$(SRC_ARCH)/.links \
|
||||
$(srctree)/include/asm-$(ARCH)/.arch
|
||||
|
||||
MRPROPER_FILES += \
|
||||
$(SRC_ARCH)/drivers \
|
||||
$(SRC_ARCH)/boot \
|
||||
$(SRC_ARCH)/lib \
|
||||
$(SRC_ARCH)/arch \
|
||||
$(SRC_ARCH)/kernel/vmlinux.lds.S \
|
||||
$(SRC_ARCH)/kernel/asm-offsets.c
|
||||
|
||||
define archhelp
|
||||
echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
|
||||
echo '* Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
|
||||
endef
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
if ETRAX_ARCH_V10
|
||||
|
||||
menu "CRIS v10 options"
|
||||
|
||||
# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping
|
||||
config CRIS_LOW_MAP
|
||||
bool
|
||||
|
@ -228,69 +230,6 @@ config ETRAX_LED12R
|
|||
For products with only one or two controllable LEDs,
|
||||
set this to same as CONFIG_ETRAX_LED1G (normally 2).
|
||||
|
||||
choice
|
||||
prompt "Product debug-port"
|
||||
depends on ETRAX_ARCH_V10
|
||||
default ETRAX_DEBUG_PORT0
|
||||
|
||||
config ETRAX_DEBUG_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Choose a serial port for the ETRAX debug console. Default to
|
||||
port 0.
|
||||
|
||||
config ETRAX_DEBUG_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT_NULL
|
||||
bool "disabled"
|
||||
help
|
||||
Disable serial-port debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Kernel GDB port"
|
||||
depends on ETRAX_KGDB
|
||||
default ETRAX_KGDB_PORT0
|
||||
help
|
||||
Choose a serial port for kernel debugging. NOTE: This port should
|
||||
not be enabled under Drivers for built-in interfaces (as it has its
|
||||
own initialization code) and should not be the same as the debug port.
|
||||
|
||||
config ETRAX_KGDB_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Use serial port 0 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for kernel debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Product rescue-port"
|
||||
|
@ -454,4 +393,6 @@ config ETRAX_POWERBUTTON_BIT
|
|||
help
|
||||
Configure where power button is connected.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
#
|
||||
# arch/cris/boot/Makefile
|
||||
# arch/cris/arch-v10/boot/Makefile
|
||||
#
|
||||
target = $(target_boot_dir)
|
||||
src = $(src_boot_dir)
|
||||
|
||||
zImage: compressed/vmlinuz
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
|
||||
compressed/vmlinuz:
|
||||
@$(MAKE) -f $(src)/compressed/Makefile $(target_compressed_dir)/vmlinuz
|
||||
subdir- := compressed rescue
|
||||
targets := Image
|
||||
|
||||
clean:
|
||||
@$(MAKE) -f $(src)/compressed/Makefile clean
|
||||
$(obj)/Image: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@echo ' Kernel: $@ is ready'
|
||||
|
||||
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
|
||||
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
|
||||
$(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
|
||||
|
||||
$(obj)/zImage: $(obj)/compressed/vmlinux
|
||||
@cp $< $@
|
||||
@echo ' Kernel: $@ is ready'
|
||||
|
|
|
@ -1,45 +1,35 @@
|
|||
#
|
||||
# create a compressed vmlinuz image from the binary vmlinux.bin file
|
||||
# arch/cris/arch-v10/boot/compressed/Makefile
|
||||
#
|
||||
target = $(target_compressed_dir)
|
||||
src = $(src_compressed_dir)
|
||||
|
||||
CC = gcc-cris -melf $(LINUXINCLUDE)
|
||||
CFLAGS = -O2
|
||||
ccflags-y += -O2
|
||||
LD = ld-cris
|
||||
ldflags-y += -T $(obj)/decompress.ld
|
||||
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
OBJECTS = $(target)/head.o $(target)/misc.o
|
||||
|
||||
# files to compress
|
||||
SYSTEM = $(objtree)/vmlinux.bin
|
||||
quiet_cmd_image = BUILD $@
|
||||
cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
|
||||
|
||||
all: $(target_compressed_dir)/vmlinuz
|
||||
targets := vmlinux piggy.gz decompress.o decompress.bin
|
||||
|
||||
$(target)/decompress.bin: $(OBJECTS)
|
||||
$(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin
|
||||
$(obj)/decompress.o: $(OBJECTS) FORCE
|
||||
$(call if_changed,ld)
|
||||
|
||||
# Create vmlinuz image in top-level build directory
|
||||
$(target_compressed_dir)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
|
||||
@echo " COMPR vmlinux.bin --> vmlinuz"
|
||||
@cat $(target)/decompress.bin piggy.img > $(target_compressed_dir)/vmlinuz
|
||||
@rm -f piggy.img
|
||||
$(obj)/decompress.bin: $(obj)/decompress.o FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
$(target)/head.o: $(src)/head.S
|
||||
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
|
||||
$(obj)/head.o: $(obj)/head.S .config
|
||||
@$(CC) -D__ASSEMBLY__ -traditional -c $< -o $@
|
||||
|
||||
$(target)/misc.o: $(src)/misc.c
|
||||
$(CC) -D__KERNEL__ -c $< -o $@
|
||||
$(obj)/misc.o: $(obj)/misc.c .config
|
||||
@$(CC) -D__KERNEL__ -c $< -o $@
|
||||
|
||||
# gzip the kernel image
|
||||
$(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE
|
||||
$(call if_changed,image)
|
||||
|
||||
piggy.img: $(SYSTEM)
|
||||
@cat $(SYSTEM) | gzip -f -9 > piggy.img
|
||||
|
||||
$(target):
|
||||
mkdir -p $(target)
|
||||
|
||||
clean:
|
||||
rm -f piggy.img $(objtree)/vmlinuz
|
||||
$(obj)/piggy.gz: $(obj)/../Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
/*
|
||||
* misc.c
|
||||
*
|
||||
* $Id: misc.c,v 1.6 2003/10/27 08:04:31 starvik Exp $
|
||||
*
|
||||
* This is a collection of several routines from gzip-1.0.3
|
||||
* This is a collection of several routines from gzip-1.0.3
|
||||
* adapted for Linux.
|
||||
*
|
||||
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
|
||||
* puts by Nick Holloway 1993, better puts by Martin Mares 1995
|
||||
* adaptation for Linux/CRIS Axis Communications AB, 1999
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* where the piggybacked kernel image expects itself to live.
|
||||
|
|
|
@ -1,56 +1,38 @@
|
|||
#
|
||||
# Makefile for rescue code
|
||||
# Makefile for rescue (bootstrap) code
|
||||
#
|
||||
target = $(target_rescue_dir)
|
||||
src = $(src_rescue_dir)
|
||||
|
||||
CC = gcc-cris -mlinux $(LINUXINCLUDE)
|
||||
CFLAGS = -O2
|
||||
ccflags-y += -O2
|
||||
asflags-y += -traditional
|
||||
LD = gcc-cris -mlinux -nostdlib
|
||||
ldflags-y += -T $(obj)/rescue.ld
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||
OBJECT := $(obj)/head.o
|
||||
|
||||
all: $(target)/rescue.bin $(target)/testrescue.bin $(target)/kimagerescue.bin
|
||||
targets := rescue.o rescue.bin
|
||||
|
||||
$(target)/rescue.bin: $(target) $(target)/head.o
|
||||
$(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
|
||||
# Place a copy in top-level build directory
|
||||
cp -p $(target)/rescue.bin $(objtree)
|
||||
$(obj)/rescue.o: $(OBJECT) FORCE
|
||||
$(call if_changed,ld)
|
||||
|
||||
$(target)/testrescue.bin: $(target) $(target)/testrescue.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/testrescue.o tr.bin
|
||||
$(obj)/rescue.bin: $(obj)/rescue.o FORCE
|
||||
$(call if_changed,objcopy)
|
||||
cp -p $(obj)/rescue.bin $(objtree)
|
||||
|
||||
$(obj)/testrescue.bin: $(obj)/testrescue.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/testrescue.o tr.bin
|
||||
# Pad it to 784 bytes
|
||||
dd if=/dev/zero of=tmp2423 bs=1 count=784
|
||||
cat tr.bin tmp2423 >testrescue_tmp.bin
|
||||
dd if=testrescue_tmp.bin of=$(target)/testrescue.bin bs=1 count=784
|
||||
dd if=testrescue_tmp.bin of=$(obj)/testrescue.bin bs=1 count=784
|
||||
rm tr.bin tmp2423 testrescue_tmp.bin
|
||||
|
||||
$(target)/kimagerescue.bin: $(target) $(target)/kimagerescue.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/kimagerescue.o ktr.bin
|
||||
$(obj)/kimagerescue.bin: $(obj)/kimagerescue.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(obj)/kimagerescue.o ktr.bin
|
||||
# Pad it to 784 bytes, that's what the rescue loader expects
|
||||
dd if=/dev/zero of=tmp2423 bs=1 count=784
|
||||
cat ktr.bin tmp2423 >kimagerescue_tmp.bin
|
||||
dd if=kimagerescue_tmp.bin of=$(target)/kimagerescue.bin bs=1 count=784
|
||||
dd if=kimagerescue_tmp.bin of=$(obj)/kimagerescue.bin bs=1 count=784
|
||||
rm ktr.bin tmp2423 kimagerescue_tmp.bin
|
||||
|
||||
$(target):
|
||||
mkdir -p $(target)
|
||||
|
||||
$(target)/head.o: $(src)/head.S
|
||||
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
|
||||
|
||||
$(target)/testrescue.o: $(src)/testrescue.S
|
||||
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
|
||||
|
||||
$(target)/kimagerescue.o: $(src)/kimagerescue.S
|
||||
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
|
||||
|
||||
clean:
|
||||
rm -f $(target)/*.o $(target)/*.bin
|
||||
|
||||
fastdep:
|
||||
|
||||
modules:
|
||||
|
||||
modules-install:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: head.S,v 1.7 2005/03/07 12:11:06 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* Rescue code, made to reside at the beginning of the
|
||||
* flash-memory. when it starts, it checks a partition
|
||||
* table at the first sector after the rescue sector.
|
||||
|
@ -23,20 +22,20 @@
|
|||
* Partition table format:
|
||||
*
|
||||
* Code transparency:
|
||||
*
|
||||
*
|
||||
* 2 bytes [opcode 'nop']
|
||||
* 2 bytes [opcode 'di']
|
||||
* 4 bytes [opcode 'ba <offset>', 8-bit or 16-bit version]
|
||||
* 2 bytes [opcode 'nop', delay slot]
|
||||
*
|
||||
* Table validation (at +10):
|
||||
*
|
||||
* Table validation (at +10):
|
||||
*
|
||||
* 2 bytes [magic/version word for partitiontable - 0xef, 0xbe]
|
||||
* 2 bytes [length of all entries plus the end marker]
|
||||
* 4 bytes [checksum for the partitiontable itself]
|
||||
*
|
||||
* Entries, each with the following format, last has offset -1:
|
||||
*
|
||||
* Entries, each with the following format, last has offset -1:
|
||||
*
|
||||
* 4 bytes [offset in bytes, from start of flash]
|
||||
* 4 bytes [length in bytes of partition]
|
||||
* 4 bytes [checksum, simple longword sum]
|
||||
|
@ -47,9 +46,9 @@
|
|||
* End marker
|
||||
*
|
||||
* 4 bytes [-1]
|
||||
*
|
||||
*
|
||||
* 10 bytes [0, padding]
|
||||
*
|
||||
*
|
||||
* Bit 0 in flags signifies RW or RO. The rescue code only bothers
|
||||
* to check the checksum for RO partitions, since the others will
|
||||
* change their data without updating the checksums. A 1 in bit 0
|
||||
|
@ -59,26 +58,29 @@
|
|||
*
|
||||
* During the wait for serial input, the status LED will flash so the
|
||||
* user knows something went wrong.
|
||||
*
|
||||
* Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
|
||||
*
|
||||
* Copyright (C) 1999-2007 Axis Communications AB
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
#include <asm/arch/sv_addr_ag.h>
|
||||
|
||||
;; The partitiontable is looked for at the first sector after the boot
|
||||
;; sector. Sector size is 65536 bytes in all flashes we use.
|
||||
|
||||
|
||||
#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR
|
||||
#define PTABLE_MAGIC 0xbeef
|
||||
|
||||
;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0.
|
||||
;; That is not where we put our downloaded serial boot-code. The length is
|
||||
;; enough for downloading code that loads the rest of itself (after
|
||||
;; having setup the DRAM etc). It is the same length as the on-chip
|
||||
;; ROM loads, so the same host loader can be used to load a rescued
|
||||
;; product as well as one booted through the Etrax serial boot code.
|
||||
|
||||
;; That is not where we put our downloaded serial boot-code.
|
||||
;; The length is enough for downloading code that loads the rest
|
||||
;; of itself (after having setup the DRAM etc).
|
||||
;; It is the same length as the on-chip ROM loads, so the same
|
||||
;; host loader can be used to load a rescued product as well as
|
||||
;; one booted through the Etrax serial boot code.
|
||||
|
||||
#define CODE_START 0x40000000
|
||||
#define CODE_LENGTH 784
|
||||
|
||||
|
@ -102,7 +104,7 @@
|
|||
#define SERRECC R_SERIAL2_REC_CTRL
|
||||
#define SERRDAT R_SERIAL2_REC_DATA
|
||||
#define SERSTAT R_SERIAL2_STATUS
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_RESCUE_SER3
|
||||
#define SERXOFF R_SERIAL3_XOFF
|
||||
#define SERBAUD R_SERIAL3_BAUD
|
||||
|
@ -115,60 +117,61 @@
|
|||
#define RAM_INIT_MAGIC 0x56902387
|
||||
|
||||
.text
|
||||
|
||||
|
||||
;; This is the entry point of the rescue code
|
||||
;; 0x80000000 if loaded in flash (as it should be)
|
||||
;; since etrax actually starts at address 2 when booting from flash, we
|
||||
;; Since etrax actually starts at address 2 when booting from flash, we
|
||||
;; put a nop (2 bytes) here first so we dont accidentally skip the di
|
||||
|
||||
nop
|
||||
nop
|
||||
di
|
||||
|
||||
jump in_cache ; enter cached area instead
|
||||
in_cache:
|
||||
|
||||
|
||||
;; first put a jump test to give a possibility of upgrading the rescue code
|
||||
;; without erasing/reflashing the sector. we put a longword of -1 here and if
|
||||
;; it is not -1, we jump using the value as jump target. since we can always
|
||||
;; change 1's to 0's without erasing the sector, it is possible to add new
|
||||
;; First put a jump test to give a possibility of upgrading the
|
||||
;; rescue code without erasing/reflashing the sector.
|
||||
;; We put a longword of -1 here and if it is not -1, we jump using
|
||||
;; the value as jump target. Since we can always change 1's to 0's
|
||||
;; without erasing the sector, it is possible to add new
|
||||
;; code after this and altering the jumptarget in an upgrade.
|
||||
|
||||
jtcd: move.d [jumptarget], $r0
|
||||
cmp.d 0xffffffff, $r0
|
||||
beq no_newjump
|
||||
nop
|
||||
|
||||
|
||||
jump [$r0]
|
||||
|
||||
jumptarget:
|
||||
jumptarget:
|
||||
.dword 0xffffffff ; can be overwritten later to insert new code
|
||||
|
||||
|
||||
no_newjump:
|
||||
#ifdef CONFIG_ETRAX_ETHERNET
|
||||
#ifdef CONFIG_ETRAX_ETHERNET
|
||||
;; Start MII clock to make sure it is running when tranceiver is reset
|
||||
move.d 0x3, $r0 ; enable = on, phy = mii_clk
|
||||
move.d $r0, [R_NETWORK_GEN_CONFIG]
|
||||
#endif
|
||||
|
||||
|
||||
;; We need to setup the bus registers before we start using the DRAM
|
||||
#include "../../lib/dram_init.S"
|
||||
|
||||
;; we now should go through the checksum-table and check the listed
|
||||
;; partitions for errors.
|
||||
|
||||
|
||||
move.d PTABLE_START, $r3
|
||||
move.d [$r3], $r0
|
||||
cmp.d NOP_DI, $r0 ; make sure the nop/di is there...
|
||||
bne do_rescue
|
||||
nop
|
||||
|
||||
|
||||
;; skip the code transparency block (10 bytes).
|
||||
|
||||
addq 10, $r3
|
||||
|
||||
|
||||
;; check for correct magic
|
||||
|
||||
|
||||
move.w [$r3+], $r0
|
||||
cmp.w PTABLE_MAGIC, $r0
|
||||
bne do_rescue ; didn't recognize - trig rescue
|
||||
|
@ -186,11 +189,11 @@ no_newjump:
|
|||
cmp.d $r0, $r4
|
||||
bne do_rescue ; didn't match - trig rescue
|
||||
nop
|
||||
|
||||
|
||||
;; ptable is ok. validate each entry.
|
||||
|
||||
moveq -1, $r7
|
||||
|
||||
|
||||
ploop: move.d [$r3+], $r1 ; partition offset (from ptable start)
|
||||
bne notfirst ; check if it is the partition containing ptable
|
||||
nop ; yes..
|
||||
|
@ -199,7 +202,7 @@ ploop: move.d [$r3+], $r1 ; partition offset (from ptable start)
|
|||
sub.d $r8, $r2 ; minus the ptable length
|
||||
ba bosse
|
||||
nop
|
||||
notfirst:
|
||||
notfirst:
|
||||
cmp.d -1, $r1 ; the end of the ptable ?
|
||||
beq flash_ok ; if so, the flash is validated
|
||||
move.d [$r3+], $r2 ; partition length
|
||||
|
@ -213,47 +216,46 @@ bosse: move.d [$r3+], $r5 ; checksum
|
|||
bpl 1f
|
||||
nop
|
||||
move.d $r1, $r7 ; remember boot partition offset
|
||||
1:
|
||||
|
||||
1:
|
||||
add.d PTABLE_START, $r1
|
||||
|
||||
|
||||
jsr checksum ; checksum the partition
|
||||
|
||||
|
||||
cmp.d $r0, $r5
|
||||
beq ploop ; checksums matched, go to next entry
|
||||
nop
|
||||
|
||||
;; otherwise fall through to the rescue code.
|
||||
|
||||
|
||||
do_rescue:
|
||||
;; setup port PA and PB default initial directions and data
|
||||
;; (so we can flash LEDs, and so that DTR and others are set)
|
||||
|
||||
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
|
||||
move.b $r0, [R_PORT_PA_DIR]
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
|
||||
move.b $r0, [R_PORT_PA_DATA]
|
||||
|
||||
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
|
||||
move.b $r0, [R_PORT_PB_DIR]
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
|
||||
move.b $r0, [R_PORT_PB_DATA]
|
||||
|
||||
;; setup the serial port at 115200 baud
|
||||
|
||||
|
||||
moveq 0, $r0
|
||||
move.d $r0, [SERXOFF]
|
||||
move.d $r0, [SERXOFF]
|
||||
|
||||
move.b 0x99, $r0
|
||||
move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit and receive
|
||||
move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit and receive
|
||||
|
||||
move.b 0x40, $r0 ; rec enable
|
||||
move.b $r0, [SERRECC]
|
||||
move.b 0x40, $r0 ; rec enable
|
||||
move.b $r0, [SERRECC]
|
||||
|
||||
moveq 0, $r1 ; "timer" to clock out a LED red flash
|
||||
move.d CODE_START, $r3 ; destination counter
|
||||
movu.w CODE_LENGTH, $r4; length
|
||||
|
||||
|
||||
wait_ser:
|
||||
addq 1, $r1
|
||||
#ifndef CONFIG_ETRAX_NO_LEDS
|
||||
|
@ -272,20 +274,20 @@ wait_ser:
|
|||
nop
|
||||
1: not $r0 ; clear bit
|
||||
and.d $r0, $r2
|
||||
2:
|
||||
2:
|
||||
#ifdef CONFIG_ETRAX_PA_LEDS
|
||||
move.b $r2, [R_PORT_PA_DATA]
|
||||
#endif
|
||||
move.b $r2, [R_PORT_PA_DATA]
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_PB_LEDS
|
||||
move.b $r2, [R_PORT_PB_DATA]
|
||||
move.b $r2, [R_PORT_PB_DATA]
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_90000000_LEDS
|
||||
move.b $r2, [0x90000000]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
;; check if we got something on the serial port
|
||||
|
||||
|
||||
move.b [SERSTAT], $r0
|
||||
btstq 0, $r0 ; data_avail
|
||||
bpl wait_ser
|
||||
|
@ -295,14 +297,15 @@ wait_ser:
|
|||
|
||||
move.b [SERRDAT], $r0
|
||||
move.b $r0, [$r3+]
|
||||
|
||||
|
||||
subq 1, $r4 ; decrease length
|
||||
bne wait_ser
|
||||
nop
|
||||
|
||||
;; jump into downloaded code
|
||||
|
||||
move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is initialized
|
||||
move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is
|
||||
; initialized
|
||||
jump CODE_START
|
||||
|
||||
flash_ok:
|
||||
|
@ -313,7 +316,8 @@ flash_ok:
|
|||
nop
|
||||
move.d PTABLE_START, $r7; otherwise use the ptable start
|
||||
1:
|
||||
move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is initialized
|
||||
move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is
|
||||
; initialized
|
||||
jump $r7 ; boot!
|
||||
|
||||
|
||||
|
@ -327,7 +331,8 @@ checksum:
|
|||
moveq 0, $r0
|
||||
moveq CONFIG_ETRAX_FLASH1_SIZE, $r6
|
||||
|
||||
;; If the first physical flash memory is exceeded wrap to the second one.
|
||||
;; If the first physical flash memory is exceeded wrap to the
|
||||
;; second one
|
||||
btstq 26, $r1 ; Are we addressing first flash?
|
||||
bpl 1f
|
||||
nop
|
||||
|
@ -351,3 +356,5 @@ checksum:
|
|||
3: move.d MEM_CSE1_START, $r1 ; wrap to second flash
|
||||
ba 2b
|
||||
nop
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
|
||||
*
|
||||
/*
|
||||
* Rescue code to be prepended on a kimage and copied to the
|
||||
* rescue serial port.
|
||||
* This is called from the rescue code, it will copy received data to
|
||||
|
@ -7,13 +6,13 @@
|
|||
*/
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
#include <asm/sv_addr_ag.h>
|
||||
#include <asm/arch/sv_addr_ag.h>
|
||||
|
||||
#define CODE_START 0x40004000
|
||||
#define CODE_LENGTH 784
|
||||
#define TIMEOUT_VALUE 1000
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CONFIG_ETRAX_RESCUE_SER0
|
||||
#define SERXOFF R_SERIAL0_XOFF
|
||||
#define SERBAUD R_SERIAL0_BAUD
|
||||
|
@ -34,7 +33,7 @@
|
|||
#define SERRECC R_SERIAL2_REC_CTRL
|
||||
#define SERRDAT R_SERIAL2_REC_DATA
|
||||
#define SERSTAT R_SERIAL2_STATUS
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_RESCUE_SER3
|
||||
#define SERXOFF R_SERIAL3_XOFF
|
||||
#define SERBAUD R_SERIAL3_BAUD
|
||||
|
@ -48,54 +47,55 @@
|
|||
;; 0x80000000 if loaded in flash (as it should be)
|
||||
;; since etrax actually starts at address 2 when booting from flash, we
|
||||
;; put a nop (2 bytes) here first so we dont accidentally skip the di
|
||||
|
||||
nop
|
||||
|
||||
nop
|
||||
di
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
#ifndef CONFIG_SVINTO_SIM
|
||||
;; setup port PA and PB default initial directions and data
|
||||
;; (so we can flash LEDs, and so that DTR and others are set)
|
||||
|
||||
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0
|
||||
move.b $r0, [R_PORT_PA_DIR]
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0
|
||||
move.b $r0, [R_PORT_PA_DATA]
|
||||
|
||||
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0
|
||||
move.b $r0, [R_PORT_PB_DIR]
|
||||
move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0
|
||||
move.b $r0, [R_PORT_PB_DATA]
|
||||
|
||||
|
||||
;; We need to setup the bus registers before we start using the DRAM
|
||||
#include "../../lib/dram_init.S"
|
||||
|
||||
|
||||
#endif
|
||||
;; Setup the stack to a suitably high address.
|
||||
;; We assume 8 MB is the minimum DRAM in an eLinux
|
||||
;; product and put the sp at the top for now.
|
||||
|
||||
move.d 0x40800000, $sp
|
||||
|
||||
|
||||
;; setup the serial port at 115200 baud
|
||||
|
||||
|
||||
moveq 0, $r0
|
||||
move.d $r0, [SERXOFF]
|
||||
move.d $r0, [SERXOFF]
|
||||
|
||||
move.b 0x99, $r0
|
||||
move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit and receive
|
||||
move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit
|
||||
; and receive
|
||||
|
||||
move.b 0x40, $r0 ; rec enable
|
||||
move.b $r0, [SERRECC]
|
||||
move.b $r0, [SERRECC]
|
||||
|
||||
|
||||
moveq 0, $r1 ; "timer" to clock out a LED red flash
|
||||
move.d CODE_START, $r3 ; destination counter
|
||||
moveq 0, $r1 ; "timer" to clock out a LED red flash
|
||||
move.d CODE_START, $r3 ; destination counter
|
||||
move.d CODE_LENGTH, $r4 ; length
|
||||
move.d TIMEOUT_VALUE, $r5 ; "timeout" until jump
|
||||
|
||||
wait_ser:
|
||||
addq 1, $r1
|
||||
subq 1, $r5 ; decrease timeout
|
||||
beq jump_start ; timed out
|
||||
subq 1, $r5 ; decrease timeout
|
||||
beq jump_start ; timed out
|
||||
nop
|
||||
#ifndef CONFIG_ETRAX_NO_LEDS
|
||||
#ifdef CONFIG_ETRAX_PA_LEDS
|
||||
|
@ -111,21 +111,21 @@ wait_ser:
|
|||
or.d $r0, $r2 ; set bit
|
||||
ba 2f
|
||||
nop
|
||||
1: not $r0 ; clear bit
|
||||
1: not $r0 ; clear bit
|
||||
and.d $r0, $r2
|
||||
2:
|
||||
2:
|
||||
#ifdef CONFIG_ETRAX_PA_LEDS
|
||||
move.b $r2, [R_PORT_PA_DATA]
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_PB_LEDS
|
||||
move.b $r2, [R_PORT_PB_DATA]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
;; check if we got something on the serial port
|
||||
|
||||
|
||||
move.b [SERSTAT], $r0
|
||||
btstq 0, $r0 ; data_avail
|
||||
btstq 0, $r0 ; data_avail
|
||||
bpl wait_ser
|
||||
nop
|
||||
|
||||
|
@ -134,7 +134,7 @@ wait_ser:
|
|||
move.b [SERRDAT], $r0
|
||||
move.b $r0, [$r3+]
|
||||
move.d TIMEOUT_VALUE, $r5 ; reset "timeout"
|
||||
subq 1, $r4 ; decrease length
|
||||
subq 1, $r4 ; decrease length
|
||||
bne wait_ser
|
||||
nop
|
||||
jump_start:
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
/* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
|
||||
*
|
||||
/*
|
||||
* Simple testcode to download by the rescue block.
|
||||
* Just lits some LEDs to show it was downloaded correctly.
|
||||
*
|
||||
* Just lights some LEDs to show it was downloaded correctly.
|
||||
*
|
||||
* Copyright (C) 1999 Axis Communications AB
|
||||
*/
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
#include <asm/sv_addr_ag.h>
|
||||
#include <asm/arch/sv_addr_ag.h>
|
||||
|
||||
.text
|
||||
|
||||
|
@ -16,11 +15,10 @@
|
|||
moveq -1, $r2
|
||||
move.b $r2, [R_PORT_PA_DIR]
|
||||
moveq 0, $r2
|
||||
move.b $r2, [R_PORT_PA_DATA]
|
||||
move.b $r2, [R_PORT_PA_DATA]
|
||||
|
||||
endless:
|
||||
nop
|
||||
ba endless
|
||||
nop
|
||||
|
||||
|
||||
|
|
|
@ -9,37 +9,6 @@ config ETRAX_ETHERNET
|
|||
This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
|
||||
controller.
|
||||
|
||||
choice
|
||||
prompt "Network LED behavior"
|
||||
depends on ETRAX_ETHERNET
|
||||
default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_LINK
|
||||
bool "LED_on_when_link"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
bool "LED_on_when_activity"
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SERIAL
|
||||
bool "Serial-port support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
|
@ -83,32 +52,6 @@ config ETRAX_SERIAL_PORT0
|
|||
Normally you want this on, unless you use external DMA 1 that uses
|
||||
the same DMA channels.
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA out assignment"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_DMA6_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_OUT
|
||||
bool "No DMA out"
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA6_OUT
|
||||
bool "DMA 6"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA in assignment"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_IN
|
||||
bool "No DMA in"
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
bool "DMA 7"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
|
@ -197,32 +140,6 @@ config ETRAX_SERIAL_PORT1
|
|||
help
|
||||
Enables the ETRAX 100 serial driver for ser1 (ttyS1).
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA out assignment"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_DMA8_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_OUT
|
||||
bool "No DMA out"
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA8_OUT
|
||||
bool "DMA 8"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA in assignment"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_DMA9_IN
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_IN
|
||||
bool "No DMA in"
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA9_IN
|
||||
bool "DMA 9"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser1 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
|
@ -314,32 +231,6 @@ config ETRAX_SERIAL_PORT2
|
|||
help
|
||||
Enables the ETRAX 100 serial driver for ser2 (ttyS2).
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA out assignment"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_DMA2_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_OUT
|
||||
bool "No DMA out"
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA2_OUT
|
||||
bool "DMA 2"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA in assignment"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_DMA3_IN
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_IN
|
||||
bool "No DMA in"
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA3_IN
|
||||
bool "DMA 3"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
|
@ -428,32 +319,6 @@ config ETRAX_SERIAL_PORT3
|
|||
help
|
||||
Enables the ETRAX 100 serial driver for ser3 (ttyS3).
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA out assignment"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_DMA4_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_OUT
|
||||
bool "No DMA out"
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA4_OUT
|
||||
bool "DMA 4"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA in assignment"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_DMA5_IN
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_IN
|
||||
bool "No DMA in"
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA5_IN
|
||||
bool "DMA 5"
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DTR, RI, DSR and CD assignment"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
|
@ -563,21 +428,6 @@ config ETRAX_USB_HOST_PORT2
|
|||
depends on ETRAX_USB_HOST
|
||||
default n
|
||||
|
||||
config ETRAX_AXISFLASHMAP
|
||||
bool "Axis flash-map support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
select MTD
|
||||
select MTD_CFI
|
||||
select MTD_CFI_AMDSTD
|
||||
select MTD_CHAR
|
||||
select MTD_BLOCK
|
||||
select MTD_PARTITIONS
|
||||
select MTD_CONCAT
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
This option enables MTD mapping of flash devices. Needed to use
|
||||
flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_PTABLE_SECTOR
|
||||
int "Byte-offset of partition table sector"
|
||||
depends on ETRAX_AXISFLASHMAP
|
||||
|
@ -731,37 +581,6 @@ config ETRAX_PB_CHANGEABLE_BITS
|
|||
Bit set = changeable.
|
||||
You probably want 00 here.
|
||||
|
||||
config ETRAX_RTC
|
||||
bool "Real Time Clock support"
|
||||
depends on ETRAX_ARCH_V10
|
||||
help
|
||||
Enables drivers for the Real-Time Clock battery-backed chips on
|
||||
some products. The kernel reads the time when booting, and
|
||||
the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
|
||||
rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc
|
||||
device, major 121. You can check the time with cat /proc/rtc, but
|
||||
normal time reading should be done using libc function time and
|
||||
friends.
|
||||
|
||||
choice
|
||||
prompt "RTC chip"
|
||||
depends on ETRAX_RTC
|
||||
default ETRAX_DS1302
|
||||
|
||||
config ETRAX_DS1302
|
||||
bool "DS1302"
|
||||
help
|
||||
Enables the driver for the DS1302 Real-Time Clock battery-backed
|
||||
chip on some products.
|
||||
|
||||
config ETRAX_PCF8563
|
||||
bool "PCF8563"
|
||||
help
|
||||
Enables the driver for the PCF8563 Real-Time Clock battery-backed
|
||||
chip on some products.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_DS1302_RST_ON_GENERIC_PORT
|
||||
bool "DS1302 RST on Generic Port"
|
||||
depends on ETRAX_DS1302
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
# Makefile for Etrax-specific drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
|
||||
obj-$(CONFIG_ETRAX_I2C) += i2c.o
|
||||
obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
||||
obj-$(CONFIG_ETRAX_DS1302) += ds1302.o
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
|
||||
obj-$(CONFIG_ETRAX_I2C) += i2c.o
|
||||
obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
||||
obj-$(CONFIG_ETRAX_DS1302) += ds1302.o
|
||||
obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o
|
||||
|
||||
obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
|
||||
|
||||
|
|
|
@ -10,129 +10,6 @@
|
|||
* tells us what other partitions to define. If there isn't, we use a default
|
||||
* partition split defined below.
|
||||
*
|
||||
* $Log: axisflashmap.c,v $
|
||||
* Revision 1.11 2004/11/15 10:27:14 starvik
|
||||
* Corrected typo (Thanks to Milton Miller <miltonm@bga.com>).
|
||||
*
|
||||
* Revision 1.10 2004/08/16 12:37:22 starvik
|
||||
* Merge of Linux 2.6.8
|
||||
*
|
||||
* Revision 1.8 2004/05/14 07:58:03 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.6 2003/07/04 08:27:37 starvik
|
||||
* Merge of Linux 2.5.74
|
||||
*
|
||||
* Revision 1.5 2002/12/11 13:13:57 starvik
|
||||
* Added arch/ to v10 specific includes
|
||||
* Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
|
||||
*
|
||||
* Revision 1.4 2002/11/20 11:56:10 starvik
|
||||
* Merge of Linux 2.5.48
|
||||
*
|
||||
* Revision 1.3 2002/11/13 14:54:13 starvik
|
||||
* Copied from linux 2.4
|
||||
*
|
||||
* Revision 1.28 2002/10/01 08:08:43 jonashg
|
||||
* The first partition ends at the start of the partition table.
|
||||
*
|
||||
* Revision 1.27 2002/08/21 09:23:13 jonashg
|
||||
* Speling.
|
||||
*
|
||||
* Revision 1.26 2002/08/21 08:35:20 jonashg
|
||||
* Cosmetic change to printouts.
|
||||
*
|
||||
* Revision 1.25 2002/08/21 08:15:42 jonashg
|
||||
* Made it compile even without CONFIG_MTD_CONCAT defined.
|
||||
*
|
||||
* Revision 1.24 2002/08/20 13:12:35 jonashg
|
||||
* * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat
|
||||
* the results.
|
||||
* * Removed compile time tests concerning how the mtdram driver has been
|
||||
* configured. The user will know about the misconfiguration at runtime
|
||||
* instead. (The old approach made it impossible to use mtdram for anything
|
||||
* else than RAM boot).
|
||||
*
|
||||
* Revision 1.23 2002/05/13 12:12:28 johana
|
||||
* Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and
|
||||
* be informative at runtime.
|
||||
*
|
||||
* Revision 1.22 2002/05/13 10:24:44 johana
|
||||
* Added #if checks on MTDRAM CONFIG
|
||||
*
|
||||
* Revision 1.21 2002/05/06 16:05:20 johana
|
||||
* Removed debug printout.
|
||||
*
|
||||
* Revision 1.20 2002/05/06 16:03:00 johana
|
||||
* No more cramfs as root hack in generic code.
|
||||
* It's handled by axisflashmap using mtdram.
|
||||
*
|
||||
* Revision 1.19 2002/03/15 17:10:28 bjornw
|
||||
* Changed comment about cached access since we changed this before
|
||||
*
|
||||
* Revision 1.18 2002/03/05 17:06:15 jonashg
|
||||
* Try amd_flash probe before cfi_probe since amd_flash driver can handle two
|
||||
* (or more) flash chips of different model and the cfi driver cannot.
|
||||
*
|
||||
* Revision 1.17 2001/11/12 19:42:38 pkj
|
||||
* Fixed compiler warnings.
|
||||
*
|
||||
* Revision 1.16 2001/11/08 11:18:58 jonashg
|
||||
* Always read from uncached address to avoid problems with flushing
|
||||
* cachelines after write and MTD-erase. No performance loss have been
|
||||
* seen yet.
|
||||
*
|
||||
* Revision 1.15 2001/10/19 12:41:04 jonashg
|
||||
* Name of probe has changed in MTD.
|
||||
*
|
||||
* Revision 1.14 2001/09/21 07:14:10 jonashg
|
||||
* Made root filesystem (cramfs) use mtdblock driver when booting from flash.
|
||||
*
|
||||
* Revision 1.13 2001/08/15 13:57:35 jonashg
|
||||
* Entire MTD updated to the linux 2.4.7 version.
|
||||
*
|
||||
* Revision 1.12 2001/06/11 09:50:30 jonashg
|
||||
* Oops, 2MB is 0x200000 bytes.
|
||||
*
|
||||
* Revision 1.11 2001/06/08 11:39:44 jonashg
|
||||
* Changed sizes and offsets in axis_default_partitions to use
|
||||
* CONFIG_ETRAX_PTABLE_SECTOR.
|
||||
*
|
||||
* Revision 1.10 2001/05/29 09:42:03 jonashg
|
||||
* Use macro for end marker length instead of sizeof.
|
||||
*
|
||||
* Revision 1.9 2001/05/29 08:52:52 jonashg
|
||||
* Gave names to the magic fours (size of the ptable end marker).
|
||||
*
|
||||
* Revision 1.8 2001/05/28 15:36:20 jonashg
|
||||
* * Removed old comment about ptable location in flash (it's a CONFIG_ option).
|
||||
* * Variable ptable was initialized twice to the same value.
|
||||
*
|
||||
* Revision 1.7 2001/04/05 13:41:46 markusl
|
||||
* Updated according to review remarks
|
||||
*
|
||||
* Revision 1.6 2001/03/07 09:21:21 bjornw
|
||||
* No need to waste .data
|
||||
*
|
||||
* Revision 1.5 2001/03/06 16:27:01 jonashg
|
||||
* Probe the entire flash area for flash devices.
|
||||
*
|
||||
* Revision 1.4 2001/02/23 12:47:15 bjornw
|
||||
* Uncached flash in LOW_MAP moved from 0xe to 0x8
|
||||
*
|
||||
* Revision 1.3 2001/02/16 12:11:45 jonashg
|
||||
* MTD driver amd_flash is now included in MTD CVS repository.
|
||||
* (It's now in drivers/mtd).
|
||||
*
|
||||
* Revision 1.2 2001/02/09 11:12:22 jonashg
|
||||
* Support for AMD compatible non-CFI flash chips.
|
||||
* Only tested with Toshiba TC58FVT160 so far.
|
||||
*
|
||||
* Revision 1.1 2001/01/12 17:01:18 bjornw
|
||||
* * Added axisflashmap.c, a physical mapping for MTD that reads and understands
|
||||
* Axis partition-table format.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -235,7 +112,7 @@ static struct map_info map_cse1 = {
|
|||
};
|
||||
|
||||
/* If no partition-table was found, we use this default-set. */
|
||||
#define MAX_PARTITIONS 7
|
||||
#define MAX_PARTITIONS 7
|
||||
#define NUM_DEFAULT_PARTITIONS 3
|
||||
|
||||
/*
|
||||
|
@ -300,6 +177,15 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
|
|||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
|
||||
/* Main flash device */
|
||||
static struct mtd_partition main_partition = {
|
||||
.name = "main",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
|
||||
* chips in that order (because the amd_flash-driver is faster).
|
||||
|
@ -316,15 +202,14 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
|
|||
mtd_cs = do_map_probe("cfi_probe", map_cs);
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_JEDECPROBE
|
||||
if (!mtd_cs) {
|
||||
if (!mtd_cs)
|
||||
mtd_cs = do_map_probe("jedec_probe", map_cs);
|
||||
}
|
||||
#endif
|
||||
|
||||
return mtd_cs;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Probe each chip select individually for flash chips. If there are chips on
|
||||
* both cse0 and cse1, the mtd_info structs will be concatenated to one struct
|
||||
* so that MTD partitions can cross chip boundries.
|
||||
|
@ -351,7 +236,7 @@ static struct mtd_info *flash_probe(void)
|
|||
if (mtd_cse0 && mtd_cse1) {
|
||||
#ifdef CONFIG_MTD_CONCAT
|
||||
struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
|
||||
|
||||
|
||||
/* Since the concatenation layer adds a small overhead we
|
||||
* could try to figure out if the chips in cse0 and cse1 are
|
||||
* identical and reprobe the whole cse0+cse1 window. But since
|
||||
|
@ -372,7 +257,7 @@ static struct mtd_info *flash_probe(void)
|
|||
|
||||
/* The best we can do now is to only use what we found
|
||||
* at cse0.
|
||||
*/
|
||||
*/
|
||||
mtd_cse = mtd_cse0;
|
||||
map_destroy(mtd_cse1);
|
||||
}
|
||||
|
@ -395,7 +280,7 @@ static int __init init_axis_flash(void)
|
|||
struct partitiontable_head *ptable_head = NULL;
|
||||
struct partitiontable_entry *ptable;
|
||||
int use_default_ptable = 1; /* Until proven otherwise. */
|
||||
const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n";
|
||||
const char pmsg[] = " /dev/flash%d at 0x%08x, size 0x%08x\n";
|
||||
|
||||
if (!(mymtd = flash_probe())) {
|
||||
/* There's no reason to use this module if no flash chip can
|
||||
|
@ -435,7 +320,7 @@ static int __init init_axis_flash(void)
|
|||
unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
|
||||
unsigned char *p;
|
||||
unsigned long csum = 0;
|
||||
|
||||
|
||||
ptable = (struct partitiontable_entry *)
|
||||
((unsigned long)ptable_head + sizeof(*ptable_head));
|
||||
|
||||
|
@ -490,6 +375,16 @@ static int __init init_axis_flash(void)
|
|||
pidx++;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
|
||||
if (mymtd) {
|
||||
main_partition.size = mymtd->size;
|
||||
err = add_mtd_partitions(mymtd, &main_partition, 1);
|
||||
if (err)
|
||||
panic("axisflashmap: Could not initialize "
|
||||
"partition for whole main mtd device!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mymtd) {
|
||||
if (use_default_ptable) {
|
||||
printk(KERN_INFO " Using default partition table.\n");
|
||||
|
@ -499,9 +394,8 @@ static int __init init_axis_flash(void)
|
|||
err = add_mtd_partitions(mymtd, axis_partitions, pidx);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (err)
|
||||
panic("axisflashmap could not add MTD partitions!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!romfs_in_flash) {
|
||||
|
@ -515,25 +409,24 @@ static int __init init_axis_flash(void)
|
|||
#else
|
||||
struct mtd_info *mtd_ram;
|
||||
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info),
|
||||
GFP_KERNEL);
|
||||
if (!mtd_ram) {
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
|
||||
if (!mtd_ram)
|
||||
panic("axisflashmap couldn't allocate memory for "
|
||||
"mtd_info!\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO " Adding RAM partition for romfs image:\n");
|
||||
printk(pmsg, pidx, romfs_start, romfs_length);
|
||||
printk(pmsg, pidx, (unsigned)romfs_start,
|
||||
(unsigned)romfs_length);
|
||||
|
||||
err = mtdram_init_device(mtd_ram, (void*)romfs_start,
|
||||
romfs_length, "romfs");
|
||||
if (err) {
|
||||
err = mtdram_init_device(mtd_ram,
|
||||
(void *)romfs_start,
|
||||
romfs_length,
|
||||
"romfs");
|
||||
if (err)
|
||||
panic("axisflashmap could not initialize MTD RAM "
|
||||
"device!\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|||
ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
|
||||
return 0;
|
||||
}
|
||||
case RTC_VLOW_RD:
|
||||
case RTC_VL_READ:
|
||||
{
|
||||
/* TODO:
|
||||
* Implement voltage low detection support
|
||||
|
@ -342,7 +342,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
|
|||
" is not supported\n");
|
||||
return 0;
|
||||
}
|
||||
case RTC_VLOW_SET:
|
||||
case RTC_VL_CLR:
|
||||
{
|
||||
/* TODO:
|
||||
* Nothing to do since Voltage Low detection is not supported
|
||||
|
|
|
@ -19,77 +19,6 @@
|
|||
*! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted
|
||||
*! in the spin-lock.
|
||||
*!
|
||||
*! $Log: eeprom.c,v $
|
||||
*! Revision 1.12 2005/06/19 17:06:46 starvik
|
||||
*! Merge of Linux 2.6.12.
|
||||
*!
|
||||
*! Revision 1.11 2005/01/26 07:14:46 starvik
|
||||
*! Applied diff from kernel janitors (Nish Aravamudan).
|
||||
*!
|
||||
*! Revision 1.10 2003/09/11 07:29:48 starvik
|
||||
*! Merge of Linux 2.6.0-test5
|
||||
*!
|
||||
*! Revision 1.9 2003/07/04 08:27:37 starvik
|
||||
*! Merge of Linux 2.5.74
|
||||
*!
|
||||
*! Revision 1.8 2003/04/09 05:20:47 starvik
|
||||
*! Merge of Linux 2.5.67
|
||||
*!
|
||||
*! Revision 1.6 2003/02/10 07:19:28 starvik
|
||||
*! Removed misplaced ;
|
||||
*!
|
||||
*! Revision 1.5 2002/12/11 13:13:57 starvik
|
||||
*! Added arch/ to v10 specific includes
|
||||
*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
|
||||
*!
|
||||
*! Revision 1.4 2002/11/20 11:56:10 starvik
|
||||
*! Merge of Linux 2.5.48
|
||||
*!
|
||||
*! Revision 1.3 2002/11/18 13:16:06 starvik
|
||||
*! Linux 2.5 port of latest 2.4 drivers
|
||||
*!
|
||||
*! Revision 1.8 2001/06/15 13:24:29 jonashg
|
||||
*! * Added verification of pointers from userspace in read and write.
|
||||
*! * Made busy counter volatile.
|
||||
*! * Added define for initial write delay.
|
||||
*! * Removed warnings by using loff_t instead of unsigned long.
|
||||
*!
|
||||
*! Revision 1.7 2001/06/14 15:26:54 jonashg
|
||||
*! Removed test because condition is always true.
|
||||
*!
|
||||
*! Revision 1.6 2001/06/14 15:18:20 jonashg
|
||||
*! Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).
|
||||
*!
|
||||
*! Revision 1.5 2001/06/14 14:39:51 jonashg
|
||||
*! Forgot to use name when registering the driver.
|
||||
*!
|
||||
*! Revision 1.4 2001/06/14 14:35:47 jonashg
|
||||
*! * Gave driver a name and used it in printk's.
|
||||
*! * Cleanup.
|
||||
*!
|
||||
*! Revision 1.3 2001/03/19 16:04:46 markusl
|
||||
*! Fixed init of fops struct
|
||||
*!
|
||||
*! Revision 1.2 2001/03/19 10:35:07 markusl
|
||||
*! 2.4 port of eeprom driver
|
||||
*!
|
||||
*! Revision 1.8 2000/05/18 10:42:25 edgar
|
||||
*! Make sure to end write cycle on _every_ write
|
||||
*!
|
||||
*! Revision 1.7 2000/01/17 17:41:01 johana
|
||||
*! Adjusted probing and return -ENOSPC when writing outside EEPROM
|
||||
*!
|
||||
*! Revision 1.6 2000/01/17 15:50:36 johana
|
||||
*! Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?)
|
||||
*! EEPROMs
|
||||
*!
|
||||
*! Revision 1.5 1999/09/03 15:07:37 edgar
|
||||
*! Added bail-out check to the spinlock
|
||||
*!
|
||||
*! Revision 1.4 1999/09/03 12:11:17 bjornw
|
||||
*! Proper atomicity (need to use spinlocks, not if's). users -> busy.
|
||||
*!
|
||||
*!
|
||||
*! (c) 1999 Axis Communications AB, Lund, Sweden
|
||||
*!*****************************************************************************/
|
||||
|
||||
|
@ -103,10 +32,10 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include "i2c.h"
|
||||
|
||||
#define D(x)
|
||||
#define D(x)
|
||||
|
||||
/* If we should use adaptive timing or not: */
|
||||
//#define EEPROM_ADAPTIVE_TIMING
|
||||
/* #define EEPROM_ADAPTIVE_TIMING */
|
||||
|
||||
#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */
|
||||
#define EEPROM_MINOR_NR 0
|
||||
|
|
|
@ -1,138 +1,11 @@
|
|||
/* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* Etrax general port I/O device
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB
|
||||
* Copyright (c) 1999-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (initial version)
|
||||
* Ola Knutsson (LED handling)
|
||||
* Johan Adolfsson (read/set directions, write, port G)
|
||||
*
|
||||
* $Log: gpio.c,v $
|
||||
* Revision 1.17 2005/06/19 17:06:46 starvik
|
||||
* Merge of Linux 2.6.12.
|
||||
*
|
||||
* Revision 1.16 2005/03/07 13:02:29 starvik
|
||||
* Protect driver global states with spinlock
|
||||
*
|
||||
* Revision 1.15 2005/01/05 06:08:55 starvik
|
||||
* No need to do local_irq_disable after local_irq_save.
|
||||
*
|
||||
* Revision 1.14 2004/12/13 12:21:52 starvik
|
||||
* Added I/O and DMA allocators from Linux 2.4
|
||||
*
|
||||
* Revision 1.12 2004/08/24 07:19:59 starvik
|
||||
* Whitespace cleanup
|
||||
*
|
||||
* Revision 1.11 2004/05/14 07:58:03 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.9 2003/09/11 07:29:48 starvik
|
||||
* Merge of Linux 2.6.0-test5
|
||||
*
|
||||
* Revision 1.8 2003/07/04 08:27:37 starvik
|
||||
* Merge of Linux 2.5.74
|
||||
*
|
||||
* Revision 1.7 2003/01/10 07:44:07 starvik
|
||||
* init_ioremap is now called by kernel before drivers are initialized
|
||||
*
|
||||
* Revision 1.6 2002/12/11 13:13:57 starvik
|
||||
* Added arch/ to v10 specific includes
|
||||
* Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
|
||||
*
|
||||
* Revision 1.5 2002/11/20 11:56:11 starvik
|
||||
* Merge of Linux 2.5.48
|
||||
*
|
||||
* Revision 1.4 2002/11/18 10:10:05 starvik
|
||||
* Linux 2.5 port of latest gpio.c from Linux 2.4
|
||||
*
|
||||
* Revision 1.20 2002/10/16 21:16:24 johana
|
||||
* Added support for PA high level interrupt.
|
||||
* That gives 2ms response time with iodtest for high levels and 2-12 ms
|
||||
* response time on low levels if the check is not made in
|
||||
* process.c:cpu_idle() as well.
|
||||
*
|
||||
* Revision 1.19 2002/10/14 18:27:33 johana
|
||||
* Implemented alarm handling so select() now works.
|
||||
* Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in
|
||||
* cpu_idle().
|
||||
* Otherwise I get 15-18 ms (same as doing the poll in userspace -
|
||||
* but less overhead).
|
||||
* TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it
|
||||
* is in 2.4) as well?
|
||||
* TODO? Perhaps call request_irq()/free_irq() only when needed?
|
||||
* Increased version to 2.5
|
||||
*
|
||||
* Revision 1.18 2002/10/11 15:02:00 johana
|
||||
* Mask inverted 8 bit value in setget_input().
|
||||
*
|
||||
* Revision 1.17 2002/06/17 15:53:01 johana
|
||||
* Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT
|
||||
* that take a pointer as argument and thus can handle 32 bit ports (G)
|
||||
* correctly.
|
||||
* These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT.
|
||||
* (especially if Port G bit 31 is used)
|
||||
*
|
||||
* Revision 1.16 2002/06/17 09:59:51 johana
|
||||
* Returning 32 bit values in the ioctl return value doesn't work if bit
|
||||
* 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF.
|
||||
* A new set of ioctl's will be added.
|
||||
*
|
||||
* Revision 1.15 2002/05/06 13:19:13 johana
|
||||
* IO_SETINPUT returns mask with bit set = inputs for PA and PB as well.
|
||||
*
|
||||
* Revision 1.14 2002/04/12 12:01:53 johana
|
||||
* Use global r_port_g_data_shadow.
|
||||
* Moved gpio_init_port_g() closer to gpio_init() and marked it __init.
|
||||
*
|
||||
* Revision 1.13 2002/04/10 12:03:55 johana
|
||||
* Added support for port G /dev/gpiog (minor 3).
|
||||
* Changed indentation on switch cases.
|
||||
* Fixed other spaces to tabs.
|
||||
*
|
||||
* Revision 1.12 2001/11/12 19:42:15 pkj
|
||||
* * Corrected return values from gpio_leds_ioctl().
|
||||
* * Fixed compiler warnings.
|
||||
*
|
||||
* Revision 1.11 2001/10/30 14:39:12 johana
|
||||
* Added D() around gpio_write printk.
|
||||
*
|
||||
* Revision 1.10 2001/10/25 10:24:42 johana
|
||||
* Added IO_CFG_WRITE_MODE ioctl and write method that can do fast
|
||||
* bittoggling in the kernel. (This speeds up programming an FPGA with 450kB
|
||||
* from ~60 seconds to 4 seconds).
|
||||
* Added save_flags/cli/restore_flags in ioctl.
|
||||
*
|
||||
* Revision 1.9 2001/05/04 14:16:07 matsfg
|
||||
* Corrected spelling error
|
||||
*
|
||||
* Revision 1.8 2001/04/27 13:55:26 matsfg
|
||||
* Moved initioremap.
|
||||
* Turns off all LEDS on init.
|
||||
* Added support for shutdown and powerbutton.
|
||||
*
|
||||
* Revision 1.7 2001/04/04 13:30:08 matsfg
|
||||
* Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping
|
||||
*
|
||||
* Revision 1.6 2001/03/26 16:03:06 bjornw
|
||||
* Needs linux/config.h
|
||||
*
|
||||
* Revision 1.5 2001/03/26 14:22:03 bjornw
|
||||
* Namechange of some config options
|
||||
*
|
||||
* Revision 1.4 2001/02/27 13:52:48 bjornw
|
||||
* malloc.h -> slab.h
|
||||
*
|
||||
* Revision 1.3 2001/01/24 15:06:48 bjornw
|
||||
* gpio_wq correct type
|
||||
*
|
||||
* Revision 1.2 2001/01/18 16:07:30 bjornw
|
||||
* 2.4 port
|
||||
*
|
||||
* Revision 1.1 2001/01/18 15:55:16 bjornw
|
||||
* Verbatim copy of etraxgpio.c from elinux 2.0 added
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
@ -165,7 +38,7 @@ static int dp_cnt;
|
|||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
|
||||
static char gpio_name[] = "etrax gpio";
|
||||
|
||||
#if 0
|
||||
|
@ -173,9 +46,9 @@ static wait_queue_head_t *gpio_wq;
|
|||
#endif
|
||||
|
||||
static int gpio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off);
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off);
|
||||
static int gpio_open(struct inode *inode, struct file *filp);
|
||||
static int gpio_release(struct inode *inode, struct file *filp);
|
||||
static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
|
||||
|
@ -201,22 +74,22 @@ struct gpio_private {
|
|||
|
||||
/* linked list of alarms to check for */
|
||||
|
||||
static struct gpio_private *alarmlist = 0;
|
||||
static struct gpio_private *alarmlist;
|
||||
|
||||
static int gpio_some_alarms = 0; /* Set if someone uses alarm */
|
||||
static unsigned long gpio_pa_irq_enabled_mask = 0;
|
||||
static int gpio_some_alarms; /* Set if someone uses alarm */
|
||||
static unsigned long gpio_pa_irq_enabled_mask;
|
||||
|
||||
static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */
|
||||
|
||||
/* Port A and B use 8 bit access, but Port G is 32 bit */
|
||||
#define NUM_PORTS (GPIO_MINOR_B+1)
|
||||
|
||||
static volatile unsigned char *ports[NUM_PORTS] = {
|
||||
R_PORT_PA_DATA,
|
||||
static volatile unsigned char *ports[NUM_PORTS] = {
|
||||
R_PORT_PA_DATA,
|
||||
R_PORT_PB_DATA,
|
||||
};
|
||||
static volatile unsigned char *shads[NUM_PORTS] = {
|
||||
&port_pa_data_shadow,
|
||||
&port_pa_data_shadow,
|
||||
&port_pb_data_shadow
|
||||
};
|
||||
|
||||
|
@ -236,29 +109,29 @@ static volatile unsigned char *shads[NUM_PORTS] = {
|
|||
#endif
|
||||
|
||||
|
||||
static unsigned char changeable_dir[NUM_PORTS] = {
|
||||
static unsigned char changeable_dir[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_DIR,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_DIR
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_DIR
|
||||
};
|
||||
static unsigned char changeable_bits[NUM_PORTS] = {
|
||||
static unsigned char changeable_bits[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_BITS,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_BITS
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_BITS
|
||||
};
|
||||
|
||||
static volatile unsigned char *dir[NUM_PORTS] = {
|
||||
R_PORT_PA_DIR,
|
||||
R_PORT_PB_DIR
|
||||
static volatile unsigned char *dir[NUM_PORTS] = {
|
||||
R_PORT_PA_DIR,
|
||||
R_PORT_PB_DIR
|
||||
};
|
||||
|
||||
static volatile unsigned char *dir_shadow[NUM_PORTS] = {
|
||||
&port_pa_dir_shadow,
|
||||
&port_pb_dir_shadow
|
||||
&port_pa_dir_shadow,
|
||||
&port_pb_dir_shadow
|
||||
};
|
||||
|
||||
/* All bits in port g that can change dir. */
|
||||
static const unsigned long int changeable_dir_g_mask = 0x01FFFF01;
|
||||
|
||||
/* Port G is 32 bit, handle it special, some bits are both inputs
|
||||
/* Port G is 32 bit, handle it special, some bits are both inputs
|
||||
and outputs at the same time, only some of the bits can change direction
|
||||
and some of them in groups of 8 bit. */
|
||||
static unsigned long changeable_dir_g;
|
||||
|
@ -269,18 +142,17 @@ static unsigned long dir_g_shadow; /* 1=output */
|
|||
#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B)
|
||||
|
||||
|
||||
|
||||
static unsigned int
|
||||
gpio_poll(struct file *file,
|
||||
poll_table *wait)
|
||||
static unsigned int gpio_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long data;
|
||||
spin_lock(&gpio_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
poll_wait(file, &priv->alarm_wq, wait);
|
||||
if (priv->minor == GPIO_MINOR_A) {
|
||||
unsigned long flags;
|
||||
unsigned long tmp;
|
||||
data = *R_PORT_PA_DATA;
|
||||
/* PA has support for high level interrupt -
|
||||
|
@ -288,27 +160,25 @@ gpio_poll(struct file *file,
|
|||
*/
|
||||
tmp = ~data & priv->highalarm & 0xFF;
|
||||
tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
|
||||
local_irq_save(flags);
|
||||
|
||||
gpio_pa_irq_enabled_mask |= tmp;
|
||||
*R_IRQ_MASK1_SET = tmp;
|
||||
local_irq_restore(flags);
|
||||
|
||||
} else if (priv->minor == GPIO_MINOR_B)
|
||||
data = *R_PORT_PB_DATA;
|
||||
else if (priv->minor == GPIO_MINOR_G)
|
||||
data = *R_PORT_G_DATA;
|
||||
else {
|
||||
spin_unlock(&gpio_lock);
|
||||
return 0;
|
||||
mask = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
mask = POLLIN|POLLRDNORM;
|
||||
}
|
||||
|
||||
spin_unlock(&gpio_lock);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
|
||||
|
||||
return mask;
|
||||
|
@ -316,16 +186,19 @@ gpio_poll(struct file *file,
|
|||
|
||||
int etrax_gpio_wake_up_check(void)
|
||||
{
|
||||
struct gpio_private *priv = alarmlist;
|
||||
struct gpio_private *priv;
|
||||
unsigned long data = 0;
|
||||
int ret = 0;
|
||||
spin_lock(&gpio_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv = alarmlist;
|
||||
while (priv) {
|
||||
if (USE_PORTS(priv)) {
|
||||
if (USE_PORTS(priv))
|
||||
data = *priv->port;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
else if (priv->minor == GPIO_MINOR_G)
|
||||
data = *R_PORT_G_DATA;
|
||||
}
|
||||
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
|
||||
|
@ -334,12 +207,12 @@ int etrax_gpio_wake_up_check(void)
|
|||
}
|
||||
priv = priv->next;
|
||||
}
|
||||
spin_unlock(&gpio_lock);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
gpio_poll_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
if (gpio_some_alarms) {
|
||||
etrax_gpio_wake_up_check();
|
||||
|
@ -349,10 +222,13 @@ gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
gpio_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long tmp;
|
||||
spin_lock(&gpio_lock);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
/* Find what PA interrupts are active */
|
||||
tmp = (*R_IRQ_READ1);
|
||||
|
||||
|
@ -363,75 +239,70 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
*R_IRQ_MASK1_CLR = tmp;
|
||||
gpio_pa_irq_enabled_mask &= ~tmp;
|
||||
|
||||
spin_unlock(&gpio_lock);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (gpio_some_alarms) {
|
||||
if (gpio_some_alarms)
|
||||
return IRQ_RETVAL(etrax_gpio_wake_up_check());
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off)
|
||||
static void gpio_write_bit(struct gpio_private *priv,
|
||||
unsigned char data, int bit)
|
||||
{
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
unsigned char data, clk_mask, data_mask, write_msb;
|
||||
*priv->port = *priv->shadow &= ~(priv->clk_mask);
|
||||
if (data & 1 << bit)
|
||||
*priv->port = *priv->shadow |= priv->data_mask;
|
||||
else
|
||||
*priv->port = *priv->shadow &= ~(priv->data_mask);
|
||||
|
||||
/* For FPGA: min 5.0ns (DCC) before CCLK high */
|
||||
*priv->port = *priv->shadow |= priv->clk_mask;
|
||||
}
|
||||
|
||||
static void gpio_write_byte(struct gpio_private *priv, unsigned char data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (priv->write_msb)
|
||||
for (i = 7; i >= 0; i--)
|
||||
gpio_write_bit(priv, data, i);
|
||||
else
|
||||
for (i = 0; i <= 7; i++)
|
||||
gpio_write_bit(priv, data, i);
|
||||
}
|
||||
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off)
|
||||
{
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&gpio_lock);
|
||||
|
||||
ssize_t retval = count;
|
||||
if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count)) {
|
||||
retval = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
clk_mask = priv->clk_mask;
|
||||
data_mask = priv->data_mask;
|
||||
|
||||
if (priv->minor != GPIO_MINOR_A && priv->minor != GPIO_MINOR_B)
|
||||
return -EFAULT;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
/* It must have been configured using the IO_CFG_WRITE_MODE */
|
||||
/* Perhaps a better error code? */
|
||||
if (clk_mask == 0 || data_mask == 0) {
|
||||
if (priv->clk_mask == 0 || priv->data_mask == 0) {
|
||||
retval = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
write_msb = priv->write_msb;
|
||||
D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb));
|
||||
while (count--) {
|
||||
int i;
|
||||
data = *buf++;
|
||||
if (priv->write_msb) {
|
||||
for (i = 7; i >= 0;i--) {
|
||||
local_irq_save(flags);
|
||||
*priv->port = *priv->shadow &= ~clk_mask;
|
||||
if (data & 1<<i)
|
||||
*priv->port = *priv->shadow |= data_mask;
|
||||
else
|
||||
*priv->port = *priv->shadow &= ~data_mask;
|
||||
/* For FPGA: min 5.0ns (DCC) before CCLK high */
|
||||
*priv->port = *priv->shadow |= clk_mask;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i <= 7;i++) {
|
||||
local_irq_save(flags);
|
||||
*priv->port = *priv->shadow &= ~clk_mask;
|
||||
if (data & 1<<i)
|
||||
*priv->port = *priv->shadow |= data_mask;
|
||||
else
|
||||
*priv->port = *priv->shadow &= ~data_mask;
|
||||
/* For FPGA: min 5.0ns (DCC) before CCLK high */
|
||||
*priv->port = *priv->shadow |= clk_mask;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D(printk(KERN_DEBUG "gpio_write: %02X to data 0x%02X "
|
||||
"clk 0x%02X msb: %i\n",
|
||||
count, priv->data_mask, priv->clk_mask, priv->write_msb));
|
||||
|
||||
while (count--)
|
||||
gpio_write_byte(priv, *buf++);
|
||||
|
||||
out:
|
||||
spin_unlock(&gpio_lock);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -442,22 +313,20 @@ gpio_open(struct inode *inode, struct file *filp)
|
|||
{
|
||||
struct gpio_private *priv;
|
||||
int p = iminor(inode);
|
||||
unsigned long flags;
|
||||
|
||||
if (p > GPIO_MINOR_LAST)
|
||||
return -EINVAL;
|
||||
|
||||
priv = kmalloc(sizeof(struct gpio_private),
|
||||
GFP_KERNEL);
|
||||
priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL);
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->minor = p;
|
||||
|
||||
/* initialize the io/alarm struct and link it into our alarmlist */
|
||||
/* initialize the io/alarm struct */
|
||||
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
if (USE_PORTS(priv)) { /* A and B */
|
||||
priv->port = ports[p];
|
||||
priv->shadow = shads[p];
|
||||
|
@ -480,7 +349,13 @@ gpio_open(struct inode *inode, struct file *filp)
|
|||
priv->data_mask = 0;
|
||||
init_waitqueue_head(&priv->alarm_wq);
|
||||
|
||||
filp->private_data = (void *)priv;
|
||||
filp->private_data = priv;
|
||||
|
||||
/* link it into our alarmlist */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -490,11 +365,12 @@ gpio_release(struct inode *inode, struct file *filp)
|
|||
{
|
||||
struct gpio_private *p;
|
||||
struct gpio_private *todel;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&gpio_lock);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
p = alarmlist;
|
||||
todel = (struct gpio_private *)filp->private_data;
|
||||
p = alarmlist;
|
||||
todel = filp->private_data;
|
||||
|
||||
/* unlink from alarmlist and free the private structure */
|
||||
|
||||
|
@ -512,123 +388,114 @@ gpio_release(struct inode *inode, struct file *filp)
|
|||
while (p) {
|
||||
if (p->highalarm | p->lowalarm) {
|
||||
gpio_some_alarms = 1;
|
||||
spin_unlock(&gpio_lock);
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
gpio_some_alarms = 0;
|
||||
spin_unlock(&gpio_lock);
|
||||
out:
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main device API. ioctl's to read/set/clear bits, as well as to
|
||||
/* Main device API. ioctl's to read/set/clear bits, as well as to
|
||||
* set alarms to wait for using a subsequent select().
|
||||
*/
|
||||
|
||||
unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input
|
||||
*/
|
||||
unsigned long flags;
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input */
|
||||
if (USE_PORTS(priv)) {
|
||||
local_irq_save(flags);
|
||||
*priv->dir = *priv->dir_shadow &=
|
||||
*priv->dir = *priv->dir_shadow &=
|
||||
~((unsigned char)arg & priv->changeable_dir);
|
||||
local_irq_restore(flags);
|
||||
return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
local_irq_save(flags);
|
||||
if (((arg & dir_g_in_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
arg &= changeable_dir_g;
|
||||
/* Clear bits in genconfig to set to input */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir);
|
||||
dir_g_in_bits |= (1<<0);
|
||||
dir_g_out_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir);
|
||||
dir_g_in_bits |= 0x0000FF00;
|
||||
dir_g_out_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir);
|
||||
dir_g_in_bits |= 0x00FF0000;
|
||||
dir_g_out_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir);
|
||||
dir_g_in_bits |= (1<<24);
|
||||
dir_g_out_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_INFO "gpio: SETINPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
return dir_g_in_bits;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (priv->minor != GPIO_MINOR_G)
|
||||
return 0;
|
||||
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
if (((arg & dir_g_in_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
arg &= changeable_dir_g;
|
||||
/* Clear bits in genconfig to set to input */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g0dir);
|
||||
dir_g_in_bits |= (1<<0);
|
||||
dir_g_out_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g8_15dir);
|
||||
dir_g_in_bits |= 0x0000FF00;
|
||||
dir_g_out_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g16_23dir);
|
||||
dir_g_in_bits |= 0x00FF0000;
|
||||
dir_g_out_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, g24dir);
|
||||
dir_g_in_bits |= (1<<24);
|
||||
dir_g_out_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_DEBUG "gpio: SETINPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
|
||||
}
|
||||
return dir_g_in_bits;
|
||||
} /* setget_input */
|
||||
|
||||
unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
if (USE_PORTS(priv)) {
|
||||
local_irq_save(flags);
|
||||
*priv->dir = *priv->dir_shadow |=
|
||||
((unsigned char)arg & priv->changeable_dir);
|
||||
local_irq_restore(flags);
|
||||
*priv->dir = *priv->dir_shadow |=
|
||||
((unsigned char)arg & priv->changeable_dir);
|
||||
return *priv->dir_shadow;
|
||||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
local_irq_save(flags);
|
||||
if (((arg & dir_g_out_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
/* Set bits in genconfig to set to output */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir);
|
||||
dir_g_out_bits |= (1<<0);
|
||||
dir_g_in_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir);
|
||||
dir_g_out_bits |= 0x0000FF00;
|
||||
dir_g_in_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir);
|
||||
dir_g_out_bits |= 0x00FF0000;
|
||||
dir_g_in_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir);
|
||||
dir_g_out_bits |= (1<<24);
|
||||
dir_g_in_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
return dir_g_out_bits & 0x7FFFFFFF;
|
||||
}
|
||||
return 0;
|
||||
if (priv->minor != GPIO_MINOR_G)
|
||||
return 0;
|
||||
|
||||
/* We must fiddle with R_GEN_CONFIG to change dir */
|
||||
if (((arg & dir_g_out_bits) != arg) &&
|
||||
(arg & changeable_dir_g)) {
|
||||
/* Set bits in genconfig to set to output */
|
||||
if (arg & (1<<0)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g0dir);
|
||||
dir_g_out_bits |= (1<<0);
|
||||
dir_g_in_bits &= ~(1<<0);
|
||||
}
|
||||
if ((arg & 0x0000FF00) == 0x0000FF00) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g8_15dir);
|
||||
dir_g_out_bits |= 0x0000FF00;
|
||||
dir_g_in_bits &= ~0x0000FF00;
|
||||
}
|
||||
if ((arg & 0x00FF0000) == 0x00FF0000) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g16_23dir);
|
||||
dir_g_out_bits |= 0x00FF0000;
|
||||
dir_g_in_bits &= ~0x00FF0000;
|
||||
}
|
||||
if (arg & (1<<24)) {
|
||||
genconfig_shadow |= IO_MASK(R_GEN_CONFIG, g24dir);
|
||||
dir_g_out_bits |= (1<<24);
|
||||
dir_g_in_bits &= ~(1<<24);
|
||||
}
|
||||
D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
|
||||
"genconfig to 0x%08lX "
|
||||
"in_bits: 0x%08lX "
|
||||
"out_bits: 0x%08lX\n",
|
||||
(unsigned long)genconfig_shadow,
|
||||
dir_g_in_bits, dir_g_out_bits));
|
||||
*R_GEN_CONFIG = genconfig_shadow;
|
||||
/* Must be a >120 ns delay before writing this again */
|
||||
}
|
||||
return dir_g_out_bits & 0x7FFFFFFF;
|
||||
} /* setget_output */
|
||||
|
||||
static int
|
||||
|
@ -642,12 +509,11 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
unsigned long val;
|
||||
int ret = 0;
|
||||
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
|
||||
struct gpio_private *priv = file->private_data;
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock(&gpio_lock);
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
|
||||
|
@ -659,7 +525,6 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
}
|
||||
break;
|
||||
case IO_SETBITS:
|
||||
local_irq_save(flags);
|
||||
// set changeable bits with a 1 in arg
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->port = *priv->shadow |=
|
||||
|
@ -667,10 +532,8 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
*R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case IO_CLRBITS:
|
||||
local_irq_save(flags);
|
||||
// clear changeable bits with a 1 in arg
|
||||
if (USE_PORTS(priv)) {
|
||||
*priv->port = *priv->shadow &=
|
||||
|
@ -678,7 +541,6 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
*R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
// set alarm when bits with 1 in arg go high
|
||||
|
@ -698,6 +560,8 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
/* Must update gpio_some_alarms */
|
||||
struct gpio_private *p = alarmlist;
|
||||
int some_alarms;
|
||||
spin_lock_irq(&gpio_lock);
|
||||
p = alarmlist;
|
||||
some_alarms = 0;
|
||||
while (p) {
|
||||
if (p->highalarm | p->lowalarm) {
|
||||
|
@ -707,6 +571,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
p = p->next;
|
||||
}
|
||||
gpio_some_alarms = some_alarms;
|
||||
spin_unlock_irq(&gpio_lock);
|
||||
}
|
||||
break;
|
||||
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
|
||||
|
@ -766,7 +631,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
val = *R_PORT_G_DATA;
|
||||
}
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_READ_OUTBITS:
|
||||
|
@ -776,33 +641,32 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
} else if (priv->minor == GPIO_MINOR_G) {
|
||||
val = port_g_data_shadow;
|
||||
}
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
{
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
val = setget_input(priv, val);
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
|
||||
{
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
val = setget_output(priv, val);
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
default:
|
||||
|
@ -812,7 +676,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
ret = -EINVAL;
|
||||
} /* switch */
|
||||
|
||||
spin_unlock(&gpio_lock);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -824,18 +688,18 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
|||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_LEDACTIVE_SET:
|
||||
green = ((unsigned char) arg) & 1;
|
||||
red = (((unsigned char) arg) >> 1) & 1;
|
||||
LED_ACTIVE_SET_G(green);
|
||||
LED_ACTIVE_SET_R(red);
|
||||
green = ((unsigned char)arg) & 1;
|
||||
red = (((unsigned char)arg) >> 1) & 1;
|
||||
CRIS_LED_ACTIVE_SET_G(green);
|
||||
CRIS_LED_ACTIVE_SET_R(red);
|
||||
break;
|
||||
|
||||
case IO_LED_SETBIT:
|
||||
LED_BIT_SET(arg);
|
||||
CRIS_LED_BIT_SET(arg);
|
||||
break;
|
||||
|
||||
case IO_LED_CLRBIT:
|
||||
LED_BIT_CLR(arg);
|
||||
CRIS_LED_BIT_CLR(arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -845,7 +709,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations gpio_fops = {
|
||||
static const struct file_operations gpio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.poll = gpio_poll,
|
||||
.ioctl = gpio_ioctl,
|
||||
|
@ -854,16 +718,18 @@ const struct file_operations gpio_fops = {
|
|||
.release = gpio_release,
|
||||
};
|
||||
|
||||
|
||||
void ioif_watcher(const unsigned int gpio_in_available,
|
||||
const unsigned int gpio_out_available,
|
||||
const unsigned char pa_available,
|
||||
const unsigned char pb_available)
|
||||
static void ioif_watcher(const unsigned int gpio_in_available,
|
||||
const unsigned int gpio_out_available,
|
||||
const unsigned char pa_available,
|
||||
const unsigned char pb_available)
|
||||
{
|
||||
unsigned long int flags;
|
||||
D(printk("gpio.c: ioif_watcher called\n"));
|
||||
D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n",
|
||||
gpio_in_available, gpio_out_available, pa_available, pb_available));
|
||||
|
||||
D(printk(KERN_DEBUG "gpio.c: ioif_watcher called\n"));
|
||||
D(printk(KERN_DEBUG "gpio.c: G in: 0x%08x G out: 0x%08x "
|
||||
"PA: 0x%02x PB: 0x%02x\n",
|
||||
gpio_in_available, gpio_out_available,
|
||||
pa_available, pb_available));
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
|
@ -872,7 +738,7 @@ void ioif_watcher(const unsigned int gpio_in_available,
|
|||
|
||||
/* Initialise the dir_g_shadow etc. depending on genconfig */
|
||||
/* 0=input 1=output */
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out))
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out))
|
||||
dir_g_shadow |= (1 << 0);
|
||||
if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out))
|
||||
dir_g_shadow |= 0x0000FF00;
|
||||
|
@ -884,7 +750,8 @@ void ioif_watcher(const unsigned int gpio_in_available,
|
|||
changeable_dir_g = changeable_dir_g_mask;
|
||||
changeable_dir_g &= dir_g_out_bits;
|
||||
changeable_dir_g &= dir_g_in_bits;
|
||||
/* Correct the bits that can change direction */
|
||||
|
||||
/* Correct the bits that can change direction */
|
||||
dir_g_out_bits &= ~changeable_dir_g;
|
||||
dir_g_out_bits |= dir_g_shadow;
|
||||
dir_g_in_bits &= ~changeable_dir_g;
|
||||
|
@ -892,7 +759,8 @@ void ioif_watcher(const unsigned int gpio_in_available,
|
|||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
|
||||
printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX "
|
||||
"val: %08lX\n",
|
||||
dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
|
||||
printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",
|
||||
dir_g_shadow, changeable_dir_g);
|
||||
|
@ -900,16 +768,12 @@ void ioif_watcher(const unsigned int gpio_in_available,
|
|||
|
||||
/* main driver initialization routine, called from mem.c */
|
||||
|
||||
static __init int
|
||||
gpio_init(void)
|
||||
static int __init gpio_init(void)
|
||||
{
|
||||
int res;
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS)
|
||||
int i;
|
||||
#endif
|
||||
printk("gpio init\n");
|
||||
|
||||
/* do the formalities */
|
||||
|
||||
res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
|
||||
if (res < 0) {
|
||||
|
@ -919,43 +783,45 @@ gpio_init(void)
|
|||
|
||||
/* Clear all leds */
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS)
|
||||
LED_NETWORK_SET(0);
|
||||
LED_ACTIVE_SET(0);
|
||||
LED_DISK_READ(0);
|
||||
LED_DISK_WRITE(0);
|
||||
CRIS_LED_NETWORK_SET(0);
|
||||
CRIS_LED_ACTIVE_SET(0);
|
||||
CRIS_LED_DISK_READ(0);
|
||||
CRIS_LED_DISK_WRITE(0);
|
||||
|
||||
#if defined (CONFIG_ETRAX_CSP0_LEDS)
|
||||
for (i = 0; i < 32; i++) {
|
||||
LED_BIT_SET(i);
|
||||
}
|
||||
for (i = 0; i < 32; i++)
|
||||
CRIS_LED_BIT_SET(i);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* The I/O interface allocation watcher will be called when
|
||||
* registering it. */
|
||||
if (cris_io_interface_register_watcher(ioif_watcher)){
|
||||
printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n");
|
||||
printk(KERN_WARNING "gpio_init: Failed to install IO "
|
||||
"if allocator watcher\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 Axis Communications AB\n");
|
||||
printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001-2008 "
|
||||
"Axis Communications AB\n");
|
||||
/* We call etrax_gpio_wake_up_check() from timer interrupt and
|
||||
* from cpu_idle() in kernel/process.c
|
||||
* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
|
||||
* in some tests.
|
||||
*/
|
||||
if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED,"gpio poll", NULL)) {
|
||||
*/
|
||||
res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name);
|
||||
if (res) {
|
||||
printk(KERN_CRIT "err: timer0 irq for gpio\n");
|
||||
return res;
|
||||
}
|
||||
if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED,"gpio PA", NULL)) {
|
||||
res = request_irq(PA_IRQ_NBR, gpio_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name);
|
||||
if (res)
|
||||
printk(KERN_CRIT "err: PA irq for gpio\n");
|
||||
}
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* this makes sure that gpio_init is called during kernel boot */
|
||||
|
||||
module_init(gpio_init);
|
||||
|
||||
|
|
|
@ -6,85 +6,9 @@
|
|||
*! kernel modules (i2c_writereg/readreg) and from userspace using
|
||||
*! ioctl()'s
|
||||
*!
|
||||
*! Nov 30 1998 Torbjorn Eliasson Initial version.
|
||||
*! Bjorn Wesen Elinux kernel version.
|
||||
*! Jan 14 2000 Johan Adolfsson Fixed PB shadow register stuff -
|
||||
*! don't use PB_I2C if DS1302 uses same bits,
|
||||
*! use PB.
|
||||
*! $Log: i2c.c,v $
|
||||
*! Revision 1.13 2005/03/07 13:13:07 starvik
|
||||
*! Added spinlocks to protect states etc
|
||||
*!
|
||||
*! Revision 1.12 2005/01/05 06:11:22 starvik
|
||||
*! No need to do local_irq_disable after local_irq_save.
|
||||
*!
|
||||
*! Revision 1.11 2004/12/13 12:21:52 starvik
|
||||
*! Added I/O and DMA allocators from Linux 2.4
|
||||
*!
|
||||
*! Revision 1.9 2004/08/24 06:49:14 starvik
|
||||
*! Whitespace cleanup
|
||||
*!
|
||||
*! Revision 1.8 2004/06/08 08:48:26 starvik
|
||||
*! Removed unused code
|
||||
*!
|
||||
*! Revision 1.7 2004/05/28 09:26:59 starvik
|
||||
*! Modified I2C initialization to work in 2.6.
|
||||
*!
|
||||
*! Revision 1.6 2004/05/14 07:58:03 starvik
|
||||
*! Merge of changes from 2.4
|
||||
*!
|
||||
*! Revision 1.4 2002/12/11 13:13:57 starvik
|
||||
*! Added arch/ to v10 specific includes
|
||||
*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
|
||||
*!
|
||||
*! Revision 1.3 2002/11/20 11:56:11 starvik
|
||||
*! Merge of Linux 2.5.48
|
||||
*!
|
||||
*! Revision 1.2 2002/11/18 13:16:06 starvik
|
||||
*! Linux 2.5 port of latest 2.4 drivers
|
||||
*!
|
||||
*! Revision 1.9 2002/10/31 15:32:26 starvik
|
||||
*! Update Port B register and shadow even when running with hardware support
|
||||
*! to avoid glitches when reading bits
|
||||
*! Never set direction to out in i2c_inbyte
|
||||
*! Removed incorrect clock toggling at end of i2c_inbyte
|
||||
*!
|
||||
*! Revision 1.8 2002/08/13 06:31:53 starvik
|
||||
*! Made SDA and SCL line configurable
|
||||
*! Modified i2c_inbyte to work with PCF8563
|
||||
*!
|
||||
*! Revision 1.7 2001/04/04 13:11:36 markusl
|
||||
*! Updated according to review remarks
|
||||
*!
|
||||
*! Revision 1.6 2001/03/19 12:43:00 markusl
|
||||
*! Made some symbols unstatic (used by the eeprom driver)
|
||||
*!
|
||||
*! Revision 1.5 2001/02/27 13:52:48 bjornw
|
||||
*! malloc.h -> slab.h
|
||||
*!
|
||||
*! Revision 1.4 2001/02/15 07:17:40 starvik
|
||||
*! Corrected usage if port_pb_i2c_shadow
|
||||
*!
|
||||
*! Revision 1.3 2001/01/26 17:55:13 bjornw
|
||||
*! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it
|
||||
*! magically. Config.in needs to set it for the options that need it, like
|
||||
*! Dallas 1302 support. Actually, it should be default since it screws up
|
||||
*! the PB bits even if you don't use I2C..
|
||||
*! * Include linux/config.h to get the above
|
||||
*!
|
||||
*! Revision 1.2 2001/01/18 15:49:30 bjornw
|
||||
*! 2.4 port of I2C including some cleanups (untested of course)
|
||||
*!
|
||||
*! Revision 1.1 2001/01/18 15:35:25 bjornw
|
||||
*! Verbatim copy of the Etrax i2c driver, 2.0 elinux version
|
||||
*!
|
||||
*!
|
||||
*! ---------------------------------------------------------------------------
|
||||
*!
|
||||
*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
|
||||
*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
|
||||
*!
|
||||
*!***************************************************************************/
|
||||
/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */
|
||||
|
||||
/****************** INCLUDE FILES SECTION ***********************************/
|
||||
|
||||
|
@ -622,7 +546,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
|||
* last received byte needs to be nacked
|
||||
* instead of acked
|
||||
*/
|
||||
i2c_sendack();
|
||||
i2c_sendnack();
|
||||
/*
|
||||
* end sequence
|
||||
*/
|
||||
|
@ -708,6 +632,7 @@ i2c_init(void)
|
|||
if (!first) {
|
||||
return res;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
/* Setup and enable the Port B I2C interface */
|
||||
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
* low detector are also provided. All address and data are transferred
|
||||
* serially via two-line bidirectional I2C-bus. Maximum bus speed is
|
||||
* 400 kbits/s. The built-in word address register is incremented
|
||||
* automatically after each written or read bute.
|
||||
* automatically after each written or read byte.
|
||||
*
|
||||
* Copyright (c) 2002, Axis Communications AB
|
||||
* Copyright (c) 2002-2007, Axis Communications AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Tobias Anderberg <tobiasa@axis.com>.
|
||||
*
|
||||
* $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -27,19 +26,19 @@
|
|||
#include <linux/ioctl.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/svinto.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#define PCF8563_MAJOR 121 /* Local major number. */
|
||||
#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */
|
||||
#define PCF8563_MAJOR 121 /* Local major number. */
|
||||
#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */
|
||||
#define PCF8563_NAME "PCF8563"
|
||||
#define DRIVER_VERSION "$Revision: 1.11 $"
|
||||
#define DRIVER_VERSION "$Revision: 1.24 $"
|
||||
|
||||
/* I2C bus slave registers. */
|
||||
#define RTC_I2C_READ 0xa3
|
||||
|
@ -49,71 +48,88 @@
|
|||
#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
|
||||
#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
|
||||
|
||||
static DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */
|
||||
|
||||
static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
|
||||
|
||||
static const unsigned char days_in_month[] =
|
||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
|
||||
|
||||
/* Cache VL bit value read at driver init since writing the RTC_SECOND
|
||||
* register clears the VL status.
|
||||
*/
|
||||
static int voltage_low;
|
||||
|
||||
static const struct file_operations pcf8563_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = pcf8563_ioctl,
|
||||
};
|
||||
|
||||
unsigned char
|
||||
pcf8563_readreg(int reg)
|
||||
pcf8563_readreg(int reg)
|
||||
{
|
||||
unsigned char res = i2c_readreg(RTC_I2C_READ, reg);
|
||||
unsigned char res = rtc_read(reg);
|
||||
|
||||
/* The PCF8563 does not return 0 for unimplemented bits */
|
||||
switch(reg)
|
||||
{
|
||||
case RTC_SECONDS:
|
||||
case RTC_MINUTES:
|
||||
res &= 0x7f;
|
||||
break;
|
||||
case RTC_HOURS:
|
||||
case RTC_DAY_OF_MONTH:
|
||||
res &= 0x3f;
|
||||
break;
|
||||
case RTC_MONTH:
|
||||
res = (res & 0x1f) - 1; /* PCF8563 returns month in range 1-12 */
|
||||
break;
|
||||
/* The PCF8563 does not return 0 for unimplemented bits. */
|
||||
switch (reg) {
|
||||
case RTC_SECONDS:
|
||||
case RTC_MINUTES:
|
||||
res &= 0x7F;
|
||||
break;
|
||||
case RTC_HOURS:
|
||||
case RTC_DAY_OF_MONTH:
|
||||
res &= 0x3F;
|
||||
break;
|
||||
case RTC_WEEKDAY:
|
||||
res &= 0x07;
|
||||
break;
|
||||
case RTC_MONTH:
|
||||
res &= 0x1F;
|
||||
break;
|
||||
case RTC_CONTROL1:
|
||||
res &= 0xA8;
|
||||
break;
|
||||
case RTC_CONTROL2:
|
||||
res &= 0x1F;
|
||||
break;
|
||||
case RTC_CLOCKOUT_FREQ:
|
||||
case RTC_TIMER_CONTROL:
|
||||
res &= 0x83;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
pcf8563_writereg(int reg, unsigned char val)
|
||||
pcf8563_writereg(int reg, unsigned char val)
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_RTC_READONLY
|
||||
if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR))
|
||||
return;
|
||||
#endif
|
||||
|
||||
rtc_write(reg, val);
|
||||
}
|
||||
|
||||
void
|
||||
get_rtc_time(struct rtc_time *tm)
|
||||
{
|
||||
tm->tm_sec = rtc_read(RTC_SECONDS);
|
||||
tm->tm_min = rtc_read(RTC_MINUTES);
|
||||
tm->tm_sec = rtc_read(RTC_SECONDS);
|
||||
tm->tm_min = rtc_read(RTC_MINUTES);
|
||||
tm->tm_hour = rtc_read(RTC_HOURS);
|
||||
tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH);
|
||||
tm->tm_mon = rtc_read(RTC_MONTH);
|
||||
tm->tm_wday = rtc_read(RTC_WEEKDAY);
|
||||
tm->tm_mon = rtc_read(RTC_MONTH);
|
||||
tm->tm_year = rtc_read(RTC_YEAR);
|
||||
|
||||
if (tm->tm_sec & 0x80)
|
||||
printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
|
||||
if (tm->tm_sec & 0x80) {
|
||||
printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time "
|
||||
"information is no longer guaranteed!\n", PCF8563_NAME);
|
||||
}
|
||||
|
||||
tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
|
||||
tm->tm_sec &= 0x7f;
|
||||
tm->tm_min &= 0x7f;
|
||||
tm->tm_hour &= 0x3f;
|
||||
tm->tm_mday &= 0x3f;
|
||||
tm->tm_mon &= 0x1f;
|
||||
tm->tm_year = BCD_TO_BIN(tm->tm_year) +
|
||||
((tm->tm_mon & 0x80) ? 100 : 0);
|
||||
tm->tm_sec &= 0x7F;
|
||||
tm->tm_min &= 0x7F;
|
||||
tm->tm_hour &= 0x3F;
|
||||
tm->tm_mday &= 0x3F;
|
||||
tm->tm_wday &= 0x07; /* Not coded in BCD. */
|
||||
tm->tm_mon &= 0x1F;
|
||||
|
||||
BCD_TO_BIN(tm->tm_sec);
|
||||
BCD_TO_BIN(tm->tm_min);
|
||||
|
@ -126,17 +142,24 @@ get_rtc_time(struct rtc_time *tm)
|
|||
int __init
|
||||
pcf8563_init(void)
|
||||
{
|
||||
int ret;
|
||||
static int res;
|
||||
static int first = 1;
|
||||
|
||||
if ((ret = i2c_init())) {
|
||||
printk(KERN_CRIT "pcf8563_init: failed to init i2c\n");
|
||||
return ret;
|
||||
if (!first)
|
||||
return res;
|
||||
first = 0;
|
||||
|
||||
/* Initiate the i2c protocol. */
|
||||
res = i2c_init();
|
||||
if (res < 0) {
|
||||
printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* First of all we need to reset the chip. This is done by
|
||||
* clearing control1, control2 and clk freq, clear the
|
||||
* Voltage Low bit, and resetting all alarms.
|
||||
* clearing control1, control2 and clk freq and resetting
|
||||
* all alarms.
|
||||
*/
|
||||
if (rtc_write(RTC_CONTROL1, 0x00) < 0)
|
||||
goto err;
|
||||
|
@ -147,34 +170,36 @@ pcf8563_init(void)
|
|||
if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0)
|
||||
goto err;
|
||||
|
||||
/* Clear the VL bit in the seconds register. */
|
||||
ret = rtc_read(RTC_SECONDS);
|
||||
|
||||
if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0)
|
||||
if (rtc_write(RTC_TIMER_CONTROL, 0x03) < 0)
|
||||
goto err;
|
||||
|
||||
|
||||
/* Reset the alarms. */
|
||||
if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0)
|
||||
if (rtc_write(RTC_MINUTE_ALARM, 0x80) < 0)
|
||||
goto err;
|
||||
|
||||
if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0)
|
||||
|
||||
if (rtc_write(RTC_HOUR_ALARM, 0x80) < 0)
|
||||
goto err;
|
||||
|
||||
if (rtc_write(RTC_DAY_ALARM, 0x00) < 0)
|
||||
|
||||
if (rtc_write(RTC_DAY_ALARM, 0x80) < 0)
|
||||
goto err;
|
||||
|
||||
if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
|
||||
|
||||
if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0)
|
||||
goto err;
|
||||
|
||||
/* Check for low voltage, and warn about it.. */
|
||||
if (rtc_read(RTC_SECONDS) & 0x80)
|
||||
printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME);
|
||||
|
||||
return 0;
|
||||
|
||||
/* Check for low voltage, and warn about it. */
|
||||
if (rtc_read(RTC_SECONDS) & 0x80) {
|
||||
voltage_low = 1;
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
|
||||
"date/time information is no longer guaranteed!\n",
|
||||
PCF8563_NAME);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
err:
|
||||
printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
|
||||
return -1;
|
||||
res = -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
void __exit
|
||||
|
@ -187,8 +212,8 @@ pcf8563_exit(void)
|
|||
* ioctl calls for this driver. Why return -ENOTTY upon error? Because
|
||||
* POSIX says so!
|
||||
*/
|
||||
int
|
||||
pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
/* Some sanity checks. */
|
||||
if (_IOC_TYPE(cmd) != RTC_MAGIC)
|
||||
|
@ -198,124 +223,146 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
|
|||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_RD_TIME:
|
||||
{
|
||||
struct rtc_time tm;
|
||||
case RTC_RD_TIME:
|
||||
{
|
||||
struct rtc_time tm;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
get_rtc_time(&tm);
|
||||
mutex_lock(&rtc_lock);
|
||||
memset(&tm, 0, sizeof tm);
|
||||
get_rtc_time(&tm);
|
||||
|
||||
if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
|
||||
spin_unlock(&rtc_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case RTC_SET_TIME:
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_RTC_READONLY
|
||||
return -EPERM;
|
||||
#else
|
||||
int leap;
|
||||
int century;
|
||||
struct rtc_time tm;
|
||||
|
||||
memset(&tm, 0, sizeof (struct rtc_time));
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Convert from struct tm to struct rtc_time. */
|
||||
tm.tm_year += 1900;
|
||||
tm.tm_mon += 1;
|
||||
|
||||
leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0;
|
||||
|
||||
/* Perform some sanity checks. */
|
||||
if ((tm.tm_year < 1970) ||
|
||||
(tm.tm_mon > 12) ||
|
||||
(tm.tm_mday == 0) ||
|
||||
(tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
|
||||
(tm.tm_hour >= 24) ||
|
||||
(tm.tm_min >= 60) ||
|
||||
(tm.tm_sec >= 60))
|
||||
return -EINVAL;
|
||||
|
||||
century = (tm.tm_year >= 2000) ? 0x80 : 0;
|
||||
tm.tm_year = tm.tm_year % 100;
|
||||
|
||||
BIN_TO_BCD(tm.tm_year);
|
||||
BIN_TO_BCD(tm.tm_mday);
|
||||
BIN_TO_BCD(tm.tm_hour);
|
||||
BIN_TO_BCD(tm.tm_min);
|
||||
BIN_TO_BCD(tm.tm_sec);
|
||||
tm.tm_mon |= century;
|
||||
|
||||
spin_lock(&rtc_lock);
|
||||
|
||||
rtc_write(RTC_YEAR, tm.tm_year);
|
||||
rtc_write(RTC_MONTH, tm.tm_mon);
|
||||
rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
|
||||
rtc_write(RTC_HOURS, tm.tm_hour);
|
||||
rtc_write(RTC_MINUTES, tm.tm_min);
|
||||
rtc_write(RTC_SECONDS, tm.tm_sec);
|
||||
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return 0;
|
||||
#endif /* !CONFIG_ETRAX_RTC_READONLY */
|
||||
}
|
||||
|
||||
case RTC_VLOW_RD:
|
||||
{
|
||||
int vl_bit = 0;
|
||||
|
||||
if (rtc_read(RTC_SECONDS) & 0x80) {
|
||||
vl_bit = 1;
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
|
||||
"date/time information is no longer guaranteed!\n",
|
||||
PCF8563_NAME);
|
||||
}
|
||||
if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
if (copy_to_user((struct rtc_time *) arg, &tm,
|
||||
sizeof tm)) {
|
||||
spin_unlock(&rtc_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
case RTC_VLOW_SET:
|
||||
{
|
||||
/* Clear the VL bit in the seconds register */
|
||||
int ret = rtc_read(RTC_SECONDS);
|
||||
mutex_unlock(&rtc_lock);
|
||||
|
||||
rtc_write(RTC_SECONDS, (ret & 0x7F));
|
||||
return 0;
|
||||
}
|
||||
case RTC_SET_TIME:
|
||||
{
|
||||
int leap;
|
||||
int year;
|
||||
int century;
|
||||
struct rtc_time tm;
|
||||
|
||||
return 0;
|
||||
memset(&tm, 0, sizeof tm);
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EPERM;
|
||||
|
||||
if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm))
|
||||
return -EFAULT;
|
||||
|
||||
/* Convert from struct tm to struct rtc_time. */
|
||||
tm.tm_year += 1900;
|
||||
tm.tm_mon += 1;
|
||||
|
||||
/*
|
||||
* Check if tm.tm_year is a leap year. A year is a leap
|
||||
* year if it is divisible by 4 but not 100, except
|
||||
* that years divisible by 400 _are_ leap years.
|
||||
*/
|
||||
year = tm.tm_year;
|
||||
leap = (tm.tm_mon == 2) &&
|
||||
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
|
||||
|
||||
/* Perform some sanity checks. */
|
||||
if ((tm.tm_year < 1970) ||
|
||||
(tm.tm_mon > 12) ||
|
||||
(tm.tm_mday == 0) ||
|
||||
(tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
|
||||
(tm.tm_wday >= 7) ||
|
||||
(tm.tm_hour >= 24) ||
|
||||
(tm.tm_min >= 60) ||
|
||||
(tm.tm_sec >= 60))
|
||||
return -EINVAL;
|
||||
|
||||
century = (tm.tm_year >= 2000) ? 0x80 : 0;
|
||||
tm.tm_year = tm.tm_year % 100;
|
||||
|
||||
BIN_TO_BCD(tm.tm_year);
|
||||
BIN_TO_BCD(tm.tm_mon);
|
||||
BIN_TO_BCD(tm.tm_mday);
|
||||
BIN_TO_BCD(tm.tm_hour);
|
||||
BIN_TO_BCD(tm.tm_min);
|
||||
BIN_TO_BCD(tm.tm_sec);
|
||||
tm.tm_mon |= century;
|
||||
|
||||
mutex_lock(&rtc_lock);
|
||||
|
||||
rtc_write(RTC_YEAR, tm.tm_year);
|
||||
rtc_write(RTC_MONTH, tm.tm_mon);
|
||||
rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
|
||||
rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
|
||||
rtc_write(RTC_HOURS, tm.tm_hour);
|
||||
rtc_write(RTC_MINUTES, tm.tm_min);
|
||||
rtc_write(RTC_SECONDS, tm.tm_sec);
|
||||
|
||||
mutex_unlock(&rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_VL_READ:
|
||||
if (voltage_low) {
|
||||
printk(KERN_ERR "%s: RTC Voltage Low - "
|
||||
"reliable date/time information is no "
|
||||
"longer guaranteed!\n", PCF8563_NAME);
|
||||
}
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
if (copy_to_user((int *) arg, &voltage_low, sizeof(int)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case RTC_VL_CLR:
|
||||
{
|
||||
/* Clear the VL bit in the seconds register in case
|
||||
* the time has not been set already (which would
|
||||
* have cleared it). This does not really matter
|
||||
* because of the cached voltage_low value but do it
|
||||
* anyway for consistency. */
|
||||
|
||||
int ret = rtc_read(RTC_SECONDS);
|
||||
|
||||
rtc_write(RTC_SECONDS, (ret & 0x7F));
|
||||
|
||||
/* Clear the cached value. */
|
||||
voltage_low = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init
|
||||
pcf8563_register(void)
|
||||
static int __init pcf8563_register(void)
|
||||
{
|
||||
pcf8563_init();
|
||||
if (pcf8563_init() < 0) {
|
||||
printk(KERN_INFO "%s: Unable to initialize Real-Time Clock "
|
||||
"Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
|
||||
printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n",
|
||||
PCF8563_NAME, PCF8563_MAJOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
|
||||
return 0;
|
||||
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME,
|
||||
DRIVER_VERSION);
|
||||
|
||||
/* Check for low voltage, and warn about it. */
|
||||
if (voltage_low) {
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
|
||||
"information is no longer guaranteed!\n", PCF8563_NAME);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(pcf8563_register);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
/* Serialport functions for debugging
|
||||
*
|
||||
* Copyright (c) 2000 Axis Communications AB
|
||||
* Copyright (c) 2000-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen
|
||||
*
|
||||
|
@ -11,96 +11,6 @@
|
|||
* enableDebugIRQ()
|
||||
* init_etrax_debug()
|
||||
*
|
||||
* $Log: debugport.c,v $
|
||||
* Revision 1.27 2005/06/10 10:34:14 starvik
|
||||
* Real console support
|
||||
*
|
||||
* Revision 1.26 2005/06/07 07:06:07 starvik
|
||||
* Added LF->CR translation to make ETRAX customers happy.
|
||||
*
|
||||
* Revision 1.25 2005/03/08 08:56:47 mikaelam
|
||||
* Do only set index as port->index if port is defined, otherwise use the index from the command line
|
||||
*
|
||||
* Revision 1.24 2005/01/19 10:26:33 mikaelam
|
||||
* Return the cris serial driver in console device driver callback function
|
||||
*
|
||||
* Revision 1.23 2005/01/14 10:12:17 starvik
|
||||
* KGDB on separate port.
|
||||
* Console fixes from 2.4.
|
||||
*
|
||||
* Revision 1.22 2005/01/11 16:06:13 starvik
|
||||
* typo
|
||||
*
|
||||
* Revision 1.21 2005/01/11 13:49:14 starvik
|
||||
* Added raw_printk to be used where we don't trust the console.
|
||||
*
|
||||
* Revision 1.20 2004/12/27 11:18:32 starvik
|
||||
* Merge of Linux 2.6.10 (not functional yet).
|
||||
*
|
||||
* Revision 1.19 2004/10/21 07:26:16 starvik
|
||||
* Made it possible to specify console settings on kernel command line.
|
||||
*
|
||||
* Revision 1.18 2004/10/19 13:07:37 starvik
|
||||
* Merge of Linux 2.6.9
|
||||
*
|
||||
* Revision 1.17 2004/09/29 10:33:46 starvik
|
||||
* Resolved a dealock when printing debug from kernel.
|
||||
*
|
||||
* Revision 1.16 2004/08/24 06:12:19 starvik
|
||||
* Whitespace cleanup
|
||||
*
|
||||
* Revision 1.15 2004/08/16 12:37:19 starvik
|
||||
* Merge of Linux 2.6.8
|
||||
*
|
||||
* Revision 1.14 2004/05/17 13:11:29 starvik
|
||||
* Disable DMA until real serial driver is up
|
||||
*
|
||||
* Revision 1.13 2004/05/14 07:58:01 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.12 2003/09/11 07:29:49 starvik
|
||||
* Merge of Linux 2.6.0-test5
|
||||
*
|
||||
* Revision 1.11 2003/07/07 09:53:36 starvik
|
||||
* Revert all the 2.5.74 merge changes to make the console work again
|
||||
*
|
||||
* Revision 1.9 2003/02/17 17:07:23 starvik
|
||||
* Solved the problem with corrupted debug output (from Linux 2.4)
|
||||
* * Wait until DMA, FIFO and pipe is empty before and after transmissions
|
||||
* * Buffer data until a FIFO flush can be triggered.
|
||||
*
|
||||
* Revision 1.8 2003/01/22 06:48:36 starvik
|
||||
* Fixed warnings issued by GCC 3.2.1
|
||||
*
|
||||
* Revision 1.7 2002/12/12 08:26:32 starvik
|
||||
* Don't use C-comments inside CVS comments
|
||||
*
|
||||
* Revision 1.6 2002/12/11 15:42:02 starvik
|
||||
* Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
|
||||
*
|
||||
* Revision 1.5 2002/11/20 06:58:03 starvik
|
||||
* Compiles with kgdb
|
||||
*
|
||||
* Revision 1.4 2002/11/19 14:35:24 starvik
|
||||
* Changes from linux 2.4
|
||||
* Changed struct initializer syntax to the currently preferred notation
|
||||
*
|
||||
* Revision 1.3 2002/11/06 09:47:03 starvik
|
||||
* Modified for new interrupt macros
|
||||
*
|
||||
* Revision 1.2 2002/01/21 15:21:50 bjornw
|
||||
* Update for kdev_t changes
|
||||
*
|
||||
* Revision 1.6 2001/04/17 13:58:39 orjanf
|
||||
* * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
|
||||
*
|
||||
* Revision 1.5 2001/03/26 14:22:05 bjornw
|
||||
* Namechange of some config options
|
||||
*
|
||||
* Revision 1.4 2000/10/06 12:37:26 bjornw
|
||||
* Use physical addresses when talking to DMA
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
|
@ -112,6 +22,8 @@
|
|||
#include <asm/arch/svinto.h>
|
||||
#include <asm/io.h> /* Get SIMCOUT. */
|
||||
|
||||
extern void reset_watchdog(void);
|
||||
|
||||
struct dbg_port
|
||||
{
|
||||
unsigned int index;
|
||||
|
@ -188,7 +100,9 @@ struct dbg_port ports[]=
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETRAX_SERIAL
|
||||
extern struct tty_driver *serial_driver;
|
||||
#endif
|
||||
|
||||
struct dbg_port* port =
|
||||
#if defined(CONFIG_ETRAX_DEBUG_PORT0)
|
||||
|
@ -368,11 +282,12 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
|
|||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* Send data */
|
||||
for (i = 0; i < len; i++) {
|
||||
/* LF -> CRLF */
|
||||
|
@ -386,26 +301,16 @@ console_write_direct(struct console *co, const char *buf, unsigned int len)
|
|||
;
|
||||
*port->write = buf[i];
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
int raw_printk(const char *fmt, ...)
|
||||
{
|
||||
static char buf[1024];
|
||||
int printed_len;
|
||||
static int first = 1;
|
||||
if (first) {
|
||||
/* Force reinitialization of the port to get manual mode. */
|
||||
port->started = 0;
|
||||
start_port(port);
|
||||
first = 0;
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
console_write_direct(NULL, buf, strlen(buf));
|
||||
return printed_len;
|
||||
/*
|
||||
* Feed the watchdog, otherwise it will reset the chip during boot.
|
||||
* The time to send an ordinary boot message line (10-90 chars)
|
||||
* varies between 1-8ms at 115200. What makes up for the additional
|
||||
* 90ms that allows the watchdog to bite?
|
||||
*/
|
||||
reset_watchdog();
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -500,6 +405,7 @@ console_setup(struct console *co, char *options)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This is a dummy serial device that throws away anything written to it.
|
||||
* This is used when no debug output is wanted.
|
||||
*/
|
||||
|
@ -555,7 +461,13 @@ etrax_console_device(struct console* co, int *index)
|
|||
{
|
||||
if (port)
|
||||
*index = port->index;
|
||||
else
|
||||
*index = 0;
|
||||
#ifdef CONFIG_ETRAX_SERIAL
|
||||
return port ? serial_driver : &dummy_driver;
|
||||
#else
|
||||
return &dummy_driver;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct console sercons = {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* Wrapper for DMA channel allocator that updates DMA client muxing.
|
||||
* Copyright 2004, Axis Communications AB
|
||||
* $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $
|
||||
* Copyright 2004-2007, Axis Communications AB
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -1,252 +1,9 @@
|
|||
/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* linux/arch/cris/entry.S
|
||||
*
|
||||
* Copyright (C) 2000, 2001, 2002 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (bjornw@axis.com)
|
||||
*
|
||||
* $Log: entry.S,v $
|
||||
* Revision 1.28 2005/06/20 05:06:30 starvik
|
||||
* Remove unnecessary diff to kernel.org tree
|
||||
*
|
||||
* Revision 1.27 2005/03/04 08:16:16 starvik
|
||||
* Merge of Linux 2.6.11.
|
||||
*
|
||||
* Revision 1.26 2005/01/11 13:49:47 starvik
|
||||
* Added NMI handler.
|
||||
*
|
||||
* Revision 1.25 2004/12/27 11:18:32 starvik
|
||||
* Merge of Linux 2.6.10 (not functional yet).
|
||||
*
|
||||
* Revision 1.24 2004/12/22 10:41:23 starvik
|
||||
* Updates to make v10 compile with the latest SMP aware generic code (even
|
||||
* though v10 will never have SMP).
|
||||
*
|
||||
* Revision 1.23 2004/10/19 13:07:37 starvik
|
||||
* Merge of Linux 2.6.9
|
||||
*
|
||||
* Revision 1.22 2004/06/21 10:29:55 starvik
|
||||
* Merge of Linux 2.6.7
|
||||
*
|
||||
* Revision 1.21 2004/06/09 05:30:27 starvik
|
||||
* Clean up multiple interrupt handling.
|
||||
* Prevent interrupts from interrupting each other.
|
||||
* Handle all active interrupts.
|
||||
*
|
||||
* Revision 1.20 2004/06/08 08:55:32 starvik
|
||||
* Removed unused code
|
||||
*
|
||||
* Revision 1.19 2004/06/04 11:56:15 starvik
|
||||
* Implemented page table lookup for refills in assembler for improved performance.
|
||||
*
|
||||
* Revision 1.18 2004/05/11 12:28:25 starvik
|
||||
* Merge of Linux 2.6.6
|
||||
*
|
||||
* Revision 1.17 2003/09/11 07:29:49 starvik
|
||||
* Merge of Linux 2.6.0-test5
|
||||
*
|
||||
* Revision 1.16 2003/07/04 08:27:41 starvik
|
||||
* Merge of Linux 2.5.74
|
||||
*
|
||||
* Revision 1.15 2003/04/09 07:32:55 starvik
|
||||
* resume should return task_struct, not thread_info
|
||||
*
|
||||
* Revision 1.14 2003/04/09 05:20:44 starvik
|
||||
* Merge of Linux 2.5.67
|
||||
*
|
||||
* Revision 1.13 2002/12/11 15:42:02 starvik
|
||||
* Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
|
||||
*
|
||||
* Revision 1.12 2002/12/10 09:00:10 starvik
|
||||
* Merge of Linux 2.5.51
|
||||
*
|
||||
* Revision 1.11 2002/12/05 07:53:10 starvik
|
||||
* Corrected constants used with btstq
|
||||
*
|
||||
* Revision 1.10 2002/11/27 08:45:10 starvik
|
||||
* pid is in task_struct, not thread_info
|
||||
*
|
||||
* Revision 1.9 2002/11/26 09:52:05 starvik
|
||||
* Added preemptive kernel scheduling (if CONFIG_PREEMPT)
|
||||
*
|
||||
* Revision 1.8 2002/11/20 11:56:11 starvik
|
||||
* Merge of Linux 2.5.48
|
||||
*
|
||||
* Revision 1.7 2002/11/18 13:02:42 starvik
|
||||
* Added fourth parameter to do_notify_resume
|
||||
* Minor cleanup
|
||||
*
|
||||
* Revision 1.6 2002/11/11 10:37:50 starvik
|
||||
* Use new asm-offset defines
|
||||
* Modified for new location of current->work etc
|
||||
* Removed SYMBOL_NAME from syscalls
|
||||
* Added some new syscalls
|
||||
*
|
||||
* Revision 1.5 2002/11/05 06:45:11 starvik
|
||||
* Merge of Linux 2.5.45
|
||||
*
|
||||
* Revision 1.4 2002/02/05 15:41:31 bjornw
|
||||
* Rewritten to conform better to current 2.5 code (similar to arch/i386)
|
||||
*
|
||||
* Revision 1.3 2002/01/21 15:22:20 bjornw
|
||||
* NICE_DOGGY fix from 2.4 arch/cris
|
||||
*
|
||||
* Revision 1.37 2001/12/07 17:03:55 bjornw
|
||||
* Call a c-hook called watchdog_bite_hook instead of show_registers directly
|
||||
*
|
||||
* Revision 1.36 2001/11/22 13:36:36 bjornw
|
||||
* * In ret_from_intr, check regs->dccr for usermode reentrance instead of
|
||||
* DCCR explicitly (because the latter might not reflect current reality)
|
||||
* * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before
|
||||
* since $r9 is call-clobbered and is potentially needed afterwards
|
||||
*
|
||||
* Revision 1.35 2001/10/30 17:10:15 bjornw
|
||||
* Add some syscalls
|
||||
*
|
||||
* Revision 1.34 2001/10/01 14:45:03 bjornw
|
||||
* Removed underscores and added register prefixes
|
||||
*
|
||||
* Revision 1.33 2001/08/21 13:48:01 jonashg
|
||||
* Added fix by HP to avoid oops when doing a hard_reset_now.
|
||||
*
|
||||
* Revision 1.32 2001/08/14 04:32:02 hp
|
||||
* In _resume, add comment why R9 is saved; don't sound like it's call-saved.
|
||||
*
|
||||
* Revision 1.31 2001/07/25 16:07:42 bjornw
|
||||
* softirq_active/mask -> softirq_pending only
|
||||
*
|
||||
* Revision 1.30 2001/07/05 01:03:32 hp
|
||||
* - include asm/errno.h to get ENOSYS.
|
||||
* - Use ENOSYS, not local constant LENOSYS; tweak comments.
|
||||
* - Explain why .include, not #include is used.
|
||||
* - Make oops-register-dump if watchdog bits and it's not expected.
|
||||
* - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
|
||||
* - Use correct section attribute for section .rodata.
|
||||
* - Adjust sys_ni_syscall fill number.
|
||||
*
|
||||
* Revision 1.29 2001/06/25 14:07:00 hp
|
||||
* Fix review comment.
|
||||
* * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
|
||||
* magic numbers. Add comment that -traditional must not be used.
|
||||
* * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
|
||||
* Correct and update comment.
|
||||
* * Makefile (.S.o): Don't use -traditional. Add comment why the
|
||||
* toplevel rule can't be used (now that there's a reason).
|
||||
*
|
||||
* Revision 1.28 2001/06/21 02:00:40 hp
|
||||
* * entry.S: Include asm/unistd.h.
|
||||
* (_sys_call_table): Use section .rodata, not .data.
|
||||
* (_kernel_thread): Move from...
|
||||
* * process.c: ... here.
|
||||
* * entryoffsets.c (VAL): Break out from...
|
||||
* (OF): Use VAL.
|
||||
* (LCLONE_VM): New asmified value from CLONE_VM.
|
||||
*
|
||||
* Revision 1.27 2001/05/29 11:25:27 markusl
|
||||
* In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
|
||||
*
|
||||
* Revision 1.26 2001/05/15 15:46:03 bjornw
|
||||
* Include config.h now that we use some CONFIG_ options
|
||||
*
|
||||
* Revision 1.25 2001/05/15 05:38:47 hp
|
||||
* Tweaked code in _ret_from_sys_call
|
||||
*
|
||||
* Revision 1.24 2001/05/15 05:27:49 hp
|
||||
* Save r9 in r1 over function call rather than on stack.
|
||||
*
|
||||
* Revision 1.23 2001/05/15 05:10:00 hp
|
||||
* Generate entry.S structure offsets from C
|
||||
*
|
||||
* Revision 1.22 2001/04/17 13:58:39 orjanf
|
||||
* * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
|
||||
*
|
||||
* Revision 1.21 2001/04/17 11:33:29 orjanf
|
||||
* Updated according to review:
|
||||
* * Included asm/sv_addr_ag.h to get macro for internal register.
|
||||
* * Corrected comment regarding system call argument passing.
|
||||
* * Removed comment about instruction being in a delay slot.
|
||||
* * Added comment about SYMBOL_NAME macro.
|
||||
*
|
||||
* Revision 1.20 2001/04/12 08:51:07 hp
|
||||
* - Add entry for sys_fcntl64. In fact copy last piece from i386 including ...
|
||||
* - .rept to fill table to safe state with sys_ni_syscall.
|
||||
*
|
||||
* Revision 1.19 2001/04/04 09:43:32 orjanf
|
||||
* * Moved do_sigtrap from traps.c to entry.S.
|
||||
* * LTASK_PID need not be global anymore.
|
||||
*
|
||||
* Revision 1.18 2001/03/26 09:25:02 markusl
|
||||
* Updated after review, should now handle USB interrupts correctly.
|
||||
*
|
||||
* Revision 1.17 2001/03/21 16:12:55 bjornw
|
||||
* * Always make room for the cpu status record in the frame, in order to
|
||||
* use the same framelength and layout for both mmu busfaults and normal
|
||||
* irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore.
|
||||
* * Fixed bug with using addq for popping the stack in the epilogue - it
|
||||
* destroyed the flag register. Use instructions that don't affect the
|
||||
* flag register instead.
|
||||
* * Removed write to R_PORT_PA_DATA during spurious_interrupt
|
||||
*
|
||||
* Revision 1.16 2001/03/20 19:43:02 bjornw
|
||||
* * Get rid of esp0 setting
|
||||
* * Give a 7th argument to a systemcall - the stackframe
|
||||
*
|
||||
* Revision 1.15 2001/03/05 13:14:30 bjornw
|
||||
* Spelling fix
|
||||
*
|
||||
* Revision 1.14 2001/02/23 08:36:36 perf
|
||||
* New ABI; syscallnr=r9, arg5=mof, arg6=srp.
|
||||
* Corrected tracesys call check.
|
||||
*
|
||||
* Revision 1.13 2001/02/15 08:40:55 perf
|
||||
* H-P by way of perf;
|
||||
* - (_system_call): Don't read system call function address into r1.
|
||||
* - (RBFExit): There is no such thing as a null pop. Adjust sp by addq.
|
||||
* - (_system_call): Don't use r10 and don't save and restore it.
|
||||
* - (THREAD_ESP0): New constant.
|
||||
* - (_system_call): Inline set_esp0.
|
||||
*
|
||||
* Revision 1.12 2001/01/31 17:56:25 orjanf
|
||||
* Added definition of LTASK_PID and made it global.
|
||||
*
|
||||
* Revision 1.11 2001/01/10 21:13:29 bjornw
|
||||
* SYMBOL_NAME is defined incorrectly for the compiler options we currently use
|
||||
*
|
||||
* Revision 1.10 2000/12/18 23:47:56 bjornw
|
||||
* * Added syscall trace support (ptrace), completely untested of course
|
||||
* * Removed redundant check for NULL entries in syscall_table
|
||||
*
|
||||
* Revision 1.9 2000/11/21 16:40:51 bjornw
|
||||
* * New frame type used when an SBFS frame needs to be popped without
|
||||
* actually restarting the instruction
|
||||
* * Enable interrupts in signal_return (they did so in x86, I hope it's a good
|
||||
* idea)
|
||||
*
|
||||
* Revision 1.8 2000/11/17 16:53:35 bjornw
|
||||
* Added detection of frame-type in Rexit, so that mmu_bus_fault can
|
||||
* use ret_from_intr in the return-path to check for signals (like SEGV)
|
||||
* and other foul things that might have occurred during the fault.
|
||||
*
|
||||
* Revision 1.7 2000/10/06 15:04:28 bjornw
|
||||
* Include mof in register savings
|
||||
*
|
||||
* Revision 1.6 2000/09/12 16:02:44 bjornw
|
||||
* Linux-2.4.0-test7 derived updates
|
||||
*
|
||||
* Revision 1.5 2000/08/17 15:35:15 bjornw
|
||||
* 2.4.0-test6 changed local_irq_count and friends API
|
||||
*
|
||||
* Revision 1.4 2000/08/02 13:59:30 bjornw
|
||||
* Removed olduname and uname from the syscall list
|
||||
*
|
||||
* Revision 1.3 2000/07/31 13:32:58 bjornw
|
||||
* * Export ret_from_intr
|
||||
* * _resume updated (prev/last tjohejsan)
|
||||
* * timer_interrupt obsolete
|
||||
* * SIGSEGV detection in mmu_bus_fault temporarily disabled
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1167,9 +924,11 @@ sys_call_table:
|
|||
.long sys_epoll_pwait
|
||||
.long sys_utimensat /* 320 */
|
||||
.long sys_signalfd
|
||||
.long sys_ni_syscall
|
||||
.long sys_timerfd_create
|
||||
.long sys_eventfd
|
||||
.long sys_fallocate
|
||||
.long sys_timerfd_settime /* 325 */
|
||||
.long sys_timerfd_gettime
|
||||
|
||||
/*
|
||||
* NOTE!! This doesn't have to be exact - we just have
|
||||
|
|
|
@ -31,15 +31,12 @@
|
|||
|
||||
#define DEBUG_LOG_INCLUDED
|
||||
#define FAST_TIMER_LOG
|
||||
//#define FAST_TIMER_TEST
|
||||
/* #define FAST_TIMER_TEST */
|
||||
|
||||
#define FAST_TIMER_SANITY_CHECKS
|
||||
|
||||
#ifdef FAST_TIMER_SANITY_CHECKS
|
||||
#define SANITYCHECK(x) x
|
||||
static int sanity_failed;
|
||||
#else
|
||||
#define SANITYCHECK(x)
|
||||
#endif
|
||||
|
||||
#define D1(x)
|
||||
|
@ -226,23 +223,19 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
do_gettimeofday_fast(&t->tv_set);
|
||||
tmp = fast_timer_list;
|
||||
|
||||
SANITYCHECK({ /* Check so this is not in the list already... */
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (tmp == t)
|
||||
{
|
||||
printk(KERN_WARNING
|
||||
"timer name: %s data: 0x%08lX already in list!\n", name, data);
|
||||
sanity_failed++;
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
tmp = fast_timer_list;
|
||||
});
|
||||
#ifdef FAST_TIMER_SANITY_CHECKS
|
||||
/* Check so this is not in the list already... */
|
||||
while (tmp != NULL) {
|
||||
if (tmp == t) {
|
||||
printk(KERN_WARNING "timer name: %s data: "
|
||||
"0x%08lX already in list!\n", name, data);
|
||||
sanity_failed++;
|
||||
goto done;
|
||||
} else
|
||||
tmp = tmp->next;
|
||||
}
|
||||
tmp = fast_timer_list;
|
||||
#endif
|
||||
|
||||
t->delay_us = delay_us;
|
||||
t->function = function;
|
||||
|
|
|
@ -1,186 +1,10 @@
|
|||
/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* Head of the kernel - alter with care
|
||||
*
|
||||
* Copyright (C) 2000, 2001 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (bjornw@axis.com)
|
||||
*
|
||||
* $Log: head.S,v $
|
||||
* Revision 1.10 2005/06/20 05:12:54 starvik
|
||||
* Remove unnecessary diff to kernel.org tree
|
||||
*
|
||||
* Revision 1.9 2004/12/13 12:21:51 starvik
|
||||
* Added I/O and DMA allocators from Linux 2.4
|
||||
*
|
||||
* Revision 1.8 2004/11/22 11:41:14 starvik
|
||||
* Kernel command line may be supplied to kernel. Not used by Axis but may
|
||||
* be used by customers.
|
||||
*
|
||||
* Revision 1.7 2004/05/14 07:58:01 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.6 2003/04/28 05:31:46 starvik
|
||||
* Added section attributes
|
||||
*
|
||||
* Revision 1.5 2002/12/11 15:42:02 starvik
|
||||
* Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c
|
||||
*
|
||||
* Revision 1.4 2002/11/07 09:00:44 starvik
|
||||
* Names changed for init sections
|
||||
* init_task_union -> init_thread_union
|
||||
*
|
||||
* Revision 1.3 2002/02/05 15:38:23 bjornw
|
||||
* Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it...
|
||||
*
|
||||
* Revision 1.2 2001/12/18 13:35:19 bjornw
|
||||
* Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15).
|
||||
*
|
||||
* Revision 1.43 2001/11/08 15:09:43 starvik
|
||||
* Only start MII clock if Ethernet is configured
|
||||
*
|
||||
* Revision 1.42 2001/11/08 14:37:34 starvik
|
||||
* Start MII clock early to make sure that it is running at tranceiver reset
|
||||
*
|
||||
* Revision 1.41 2001/10/29 14:55:58 pkj
|
||||
* Corrected pa$r0 to par0.
|
||||
*
|
||||
* Revision 1.40 2001/10/03 14:59:57 pkj
|
||||
* Added support for resetting the Bluetooth hardware.
|
||||
*
|
||||
* Revision 1.39 2001/10/01 14:45:03 bjornw
|
||||
* Removed underscores and added register prefixes
|
||||
*
|
||||
* Revision 1.38 2001/09/21 07:14:11 jonashg
|
||||
* Made root filesystem (cramfs) use mtdblock driver when booting from flash.
|
||||
*
|
||||
* Revision 1.37 2001/09/11 13:44:29 orjanf
|
||||
* Decouple usage of serial ports for debug and kgdb.
|
||||
*
|
||||
* Revision 1.36 2001/06/29 12:39:31 pkj
|
||||
* Added support for mirroring the first flash to just below the
|
||||
* second one, to make them look consecutive to cramfs.
|
||||
*
|
||||
* Revision 1.35 2001/06/25 14:07:00 hp
|
||||
* Fix review comment.
|
||||
* * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
|
||||
* magic numbers. Add comment that -traditional must not be used.
|
||||
* * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
|
||||
* Correct and update comment.
|
||||
* * Makefile (.S.o): Don't use -traditional. Add comment why the
|
||||
* toplevel rule can't be used (now that there's a reason).
|
||||
*
|
||||
* Revision 1.34 2001/05/15 07:08:14 hp
|
||||
* Tweak "notice" to reflect that both r8 r9 are used
|
||||
*
|
||||
* Revision 1.33 2001/05/15 06:40:05 hp
|
||||
* Put bulk of code in .text.init, data in .data.init
|
||||
*
|
||||
* Revision 1.32 2001/05/15 06:18:56 hp
|
||||
* Execute review comment: s/bcc/bhs/g; s/bcs/blo/g
|
||||
*
|
||||
* Revision 1.31 2001/05/15 06:08:40 hp
|
||||
* Add sentence about autodetecting the bit31-MMU-bug
|
||||
*
|
||||
* Revision 1.30 2001/05/15 06:00:05 hp
|
||||
* Update comment: LOW_MAP is not forced on xsim anymore.
|
||||
*
|
||||
* Revision 1.29 2001/04/18 12:51:59 orjanf
|
||||
* * Reverted review change regarding the use of bcs/bcc.
|
||||
* * Removed non-working LED-clearing code.
|
||||
*
|
||||
* Revision 1.28 2001/04/17 13:58:39 orjanf
|
||||
* * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
|
||||
*
|
||||
* Revision 1.27 2001/04/17 11:42:35 orjanf
|
||||
* Changed according to review:
|
||||
* * Added comment explaining memory map bug.
|
||||
* * Changed bcs and bcc to blo and bhs, respectively.
|
||||
* * Removed mentioning of Stallone and Olga boards.
|
||||
*
|
||||
* Revision 1.26 2001/04/06 12:31:07 jonashg
|
||||
* Check for cramfs in flash before RAM instead of RAM before flash.
|
||||
*
|
||||
* Revision 1.25 2001/04/04 06:23:53 starvik
|
||||
* Initialize DRAM if not already initialized
|
||||
*
|
||||
* Revision 1.24 2001/04/03 11:12:00 starvik
|
||||
* Removed dram init (done by rescue or etrax100boot
|
||||
* Corrected include
|
||||
*
|
||||
* Revision 1.23 2001/04/03 09:53:03 starvik
|
||||
* Include hw_settings.S
|
||||
*
|
||||
* Revision 1.22 2001/03/26 14:23:26 bjornw
|
||||
* Namechange of some config options
|
||||
*
|
||||
* Revision 1.21 2001/03/08 12:14:41 bjornw
|
||||
* * Config name for ETRAX IDE was renamed
|
||||
* * Removed G27 auto-setting when JULIETTE is chosen (need to make this
|
||||
* a new config option later)
|
||||
*
|
||||
* Revision 1.20 2001/02/23 12:47:56 bjornw
|
||||
* MMU regs during LOW_MAP updated to reflect a newer reality
|
||||
*
|
||||
* Revision 1.19 2001/02/19 11:12:07 bjornw
|
||||
* Changed comment header format
|
||||
*
|
||||
* Revision 1.18 2001/02/15 07:25:38 starvik
|
||||
* Added support for synchronous serial ports
|
||||
*
|
||||
* Revision 1.17 2001/02/08 15:53:13 starvik
|
||||
* Last commit removed some important ifdefs
|
||||
*
|
||||
* Revision 1.16 2001/02/08 15:20:38 starvik
|
||||
* Include dram_init.S as inline
|
||||
*
|
||||
* Revision 1.15 2001/01/29 18:12:01 bjornw
|
||||
* Corrected some comments
|
||||
*
|
||||
* Revision 1.14 2001/01/29 13:11:29 starvik
|
||||
* Include dram_init.S (with DRAM/SDRAM initialization)
|
||||
*
|
||||
* Revision 1.13 2001/01/23 14:54:57 markusl
|
||||
* Updated for USB
|
||||
* i.e. added r_gen_config settings
|
||||
*
|
||||
* Revision 1.12 2001/01/19 16:16:29 perf
|
||||
* Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion.
|
||||
* Renamed serial options from ETRAX100 to ETRAX.
|
||||
*
|
||||
* Revision 1.11 2001/01/16 16:31:38 bjornw
|
||||
* * Changed name and semantics of running_from_flash to romfs_in_flash,
|
||||
* set by head.S to indicate to setup.c whether there is a cramfs image
|
||||
* after the kernels BSS or not. Should work for all three boot-cases
|
||||
* (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
|
||||
* and flash with cramfs in flash)
|
||||
*
|
||||
* Revision 1.10 2001/01/16 14:12:21 bjornw
|
||||
* * Check for cramfs start passed in r9 from the decompressor, if all other
|
||||
* cramfs options fail (if we boot from DRAM but don't find a cramfs image
|
||||
* after the kernel in DRAM, it is probably still in the flash)
|
||||
* * Check magic in cramfs detection when booting from flash directly
|
||||
*
|
||||
* Revision 1.9 2001/01/15 17:17:02 bjornw
|
||||
* * Corrected the code that detects the cramfs lengths
|
||||
* * Added a comment saying that the above does not work due to other
|
||||
* reasons..
|
||||
*
|
||||
* Revision 1.8 2001/01/15 16:27:51 jonashg
|
||||
* Made boot after flashing work.
|
||||
* * end destination is __vmlinux_end in RAM.
|
||||
* * _romfs_start moved because of virtual memory.
|
||||
*
|
||||
* Revision 1.7 2000/11/21 13:55:29 bjornw
|
||||
* Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
|
||||
*
|
||||
* Revision 1.6 2000/10/06 12:36:55 bjornw
|
||||
* Forgot swapper_pg_dir when changing memory map..
|
||||
*
|
||||
* Revision 1.5 2000/10/04 16:49:30 bjornw
|
||||
* * Fixed memory mapping in LX
|
||||
* * Check for cramfs instead of romfs
|
||||
*
|
||||
*/
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
|
@ -595,11 +419,17 @@ no_command_line:
|
|||
|
||||
moveq 0,$r0
|
||||
|
||||
;; Select or disable serial port 2
|
||||
#ifdef CONFIG_ETRAX_SERIAL_PORT2
|
||||
or.d IO_STATE (R_GEN_CONFIG, ser2, select),$r0
|
||||
#else
|
||||
or.d IO_STATE (R_GEN_CONFIG, ser2, disable),$r0
|
||||
#endif
|
||||
|
||||
;; Init interfaces (disable them).
|
||||
or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, ata, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, par0, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, ser2, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, mio, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, scsi1, disable) \
|
||||
| IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
|
||||
|
@ -801,6 +631,41 @@ no_command_line:
|
|||
| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0
|
||||
move.b $r0,[R_SERIAL1_TR_CTRL]
|
||||
|
||||
#ifdef CONFIG_ETRAX_SERIAL_PORT2
|
||||
;; setup the serial port 2 at 115200 baud for debug purposes
|
||||
|
||||
moveq IO_STATE (R_SERIAL2_XOFF, tx_stop, enable) \
|
||||
| IO_STATE (R_SERIAL2_XOFF, auto_xoff, disable) \
|
||||
| IO_FIELD (R_SERIAL2_XOFF, xoff_char, 0),$r0
|
||||
move.d $r0,[R_SERIAL2_XOFF]
|
||||
|
||||
; 115.2kbaud for both transmit and receive
|
||||
move.b IO_STATE (R_SERIAL2_BAUD, tr_baud, c115k2Hz) \
|
||||
| IO_STATE (R_SERIAL2_BAUD, rec_baud, c115k2Hz),$r0
|
||||
move.b $r0,[R_SERIAL2_BAUD]
|
||||
|
||||
; Set up and enable the serial2 receiver.
|
||||
move.b IO_STATE (R_SERIAL2_REC_CTRL, dma_err, stop) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rec_enable, enable) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rts_, active) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, sampling, middle) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rec_stick_par, normal) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rec_par, even) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rec_par_en, disable) \
|
||||
| IO_STATE (R_SERIAL2_REC_CTRL, rec_bitnr, rec_8bit),$r0
|
||||
move.b $r0,[R_SERIAL2_REC_CTRL]
|
||||
|
||||
; Set up and enable the serial2 transmitter.
|
||||
move.b IO_FIELD (R_SERIAL2_TR_CTRL, txd, 0) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, tr_enable, enable) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, auto_cts, disabled) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, stop_bits, one_bit) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, tr_stick_par, normal) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, tr_par, even) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, tr_par_en, disable) \
|
||||
| IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
|
||||
move.b $r0,[R_SERIAL2_TR_CTRL]
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_SERIAL_PORT3
|
||||
;; setup the serial port 3 at 115200 baud for debug purposes
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
/* IO interface mux allocator for ETRAX100LX.
|
||||
* Copyright 2004, Axis Communications AB
|
||||
* $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $
|
||||
* Copyright 2004-2007, Axis Communications AB
|
||||
*/
|
||||
|
||||
|
||||
/* C.f. ETRAX100LX Designer's Reference 20.9 */
|
||||
/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -45,17 +44,39 @@ struct watcher
|
|||
struct if_group
|
||||
{
|
||||
enum io_if_group group;
|
||||
unsigned char used;
|
||||
enum cris_io_interface owner;
|
||||
/* name - the name of the group 'A' to 'F' */
|
||||
char *name;
|
||||
/* used - a bit mask of all pins in the group in the order listed
|
||||
* in the tables in 19.9.1 to 19.9.6. Note that no
|
||||
* distinction is made between in, out and in/out pins. */
|
||||
unsigned int used;
|
||||
};
|
||||
|
||||
|
||||
struct interface
|
||||
{
|
||||
enum cris_io_interface ioif;
|
||||
/* name - the name of the interface */
|
||||
char *name;
|
||||
/* groups - OR'ed together io_if_group flags describing what pin groups
|
||||
* the interface uses pins in. */
|
||||
unsigned char groups;
|
||||
/* used - set when the interface is allocated. */
|
||||
unsigned char used;
|
||||
char *owner;
|
||||
/* group_a through group_f - bit masks describing what pins in the
|
||||
* pin groups the interface uses. */
|
||||
unsigned int group_a;
|
||||
unsigned int group_b;
|
||||
unsigned int group_c;
|
||||
unsigned int group_d;
|
||||
unsigned int group_e;
|
||||
unsigned int group_f;
|
||||
|
||||
/* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the
|
||||
* GPIO ports the interface uses. This could be reconstucted using
|
||||
* the group_X masks and a table of what pins the GPIO ports use,
|
||||
* but that would be messy. */
|
||||
unsigned int gpio_g_in;
|
||||
unsigned int gpio_g_out;
|
||||
unsigned char gpio_b;
|
||||
|
@ -64,26 +85,32 @@ struct interface
|
|||
static struct if_group if_groups[6] = {
|
||||
{
|
||||
.group = group_a,
|
||||
.name = "A",
|
||||
.used = 0,
|
||||
},
|
||||
{
|
||||
.group = group_b,
|
||||
.name = "B",
|
||||
.used = 0,
|
||||
},
|
||||
{
|
||||
.group = group_c,
|
||||
.name = "C",
|
||||
.used = 0,
|
||||
},
|
||||
{
|
||||
.group = group_d,
|
||||
.name = "D",
|
||||
.used = 0,
|
||||
},
|
||||
{
|
||||
.group = group_e,
|
||||
.name = "E",
|
||||
.used = 0,
|
||||
},
|
||||
{
|
||||
.group = group_f,
|
||||
.name = "F",
|
||||
.used = 0,
|
||||
}
|
||||
};
|
||||
|
@ -94,14 +121,32 @@ static struct interface interfaces[] = {
|
|||
/* Begin Non-multiplexed interfaces */
|
||||
{
|
||||
.ioif = if_eth,
|
||||
.name = "ethernet",
|
||||
.groups = 0,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0,
|
||||
.gpio_g_out = 0,
|
||||
.gpio_b = 0
|
||||
},
|
||||
{
|
||||
.ioif = if_serial_0,
|
||||
.name = "serial_0",
|
||||
.groups = 0,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0,
|
||||
.gpio_g_out = 0,
|
||||
.gpio_b = 0
|
||||
|
@ -109,172 +154,385 @@ static struct interface interfaces[] = {
|
|||
/* End Non-multiplexed interfaces */
|
||||
{
|
||||
.ioif = if_serial_1,
|
||||
.name = "serial_1",
|
||||
.groups = group_e,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0x0f,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_serial_2,
|
||||
.name = "serial_2",
|
||||
.groups = group_b,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0x0f,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x000000c0,
|
||||
.gpio_g_out = 0x000000c0,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_serial_3,
|
||||
.name = "serial_3",
|
||||
.groups = group_c,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0x0f,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0xc0000000,
|
||||
.gpio_g_out = 0xc0000000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_sync_serial_1,
|
||||
.groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3
|
||||
can be used simultaneously */
|
||||
.name = "sync_serial_1",
|
||||
.groups = group_e | group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0x0f,
|
||||
.group_f = 0x10,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0x10
|
||||
},
|
||||
{
|
||||
.ioif = if_sync_serial_3,
|
||||
.name = "sync_serial_3",
|
||||
.groups = group_c | group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0x0f,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0x80,
|
||||
|
||||
.gpio_g_in = 0xc0000000,
|
||||
.gpio_g_out = 0xc0000000,
|
||||
.gpio_b = 0x80
|
||||
},
|
||||
{
|
||||
.ioif = if_shared_ram,
|
||||
.name = "shared_ram",
|
||||
.groups = group_a,
|
||||
|
||||
.group_a = 0x7f8ff,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x0000ff3e,
|
||||
.gpio_g_out = 0x0000ff38,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_shared_ram_w,
|
||||
.name = "shared_ram_w",
|
||||
.groups = group_a | group_d,
|
||||
|
||||
.group_a = 0x7f8ff,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0xff,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x00ffff3e,
|
||||
.gpio_g_out = 0x00ffff38,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_par_0,
|
||||
.name = "par_0",
|
||||
.groups = group_a,
|
||||
|
||||
.group_a = 0x7fbff,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x0000ff3e,
|
||||
.gpio_g_out = 0x0000ff3e,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_par_1,
|
||||
.name = "par_1",
|
||||
.groups = group_d,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0x7feff,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x3eff0000,
|
||||
.gpio_g_out = 0x3eff0000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_par_w,
|
||||
.name = "par_w",
|
||||
.groups = group_a | group_d,
|
||||
|
||||
.group_a = 0x7fbff,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0xff,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x00ffff3e,
|
||||
.gpio_g_out = 0x00ffff3e,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_scsi8_0,
|
||||
.groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1
|
||||
can be used simultaneously */
|
||||
.name = "scsi8_0",
|
||||
.groups = group_a | group_b | group_f,
|
||||
|
||||
.group_a = 0x7ffff,
|
||||
.group_b = 0x0f,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0x10,
|
||||
|
||||
.gpio_g_in = 0x0000ffff,
|
||||
.gpio_g_out = 0x0000ffff,
|
||||
.gpio_b = 0x10
|
||||
},
|
||||
{
|
||||
.ioif = if_scsi8_1,
|
||||
.groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1
|
||||
can be used simultaneously */
|
||||
.name = "scsi8_1",
|
||||
.groups = group_c | group_d | group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0x0f,
|
||||
.group_d = 0x7ffff,
|
||||
.group_e = 0,
|
||||
.group_f = 0x80,
|
||||
|
||||
.gpio_g_in = 0xffff0000,
|
||||
.gpio_g_out = 0xffff0000,
|
||||
.gpio_b = 0x80
|
||||
},
|
||||
{
|
||||
.ioif = if_scsi_w,
|
||||
.name = "scsi_w",
|
||||
.groups = group_a | group_b | group_d | group_f,
|
||||
|
||||
.group_a = 0x7ffff,
|
||||
.group_b = 0x0f,
|
||||
.group_c = 0,
|
||||
.group_d = 0x601ff,
|
||||
.group_e = 0,
|
||||
.group_f = 0x90,
|
||||
|
||||
.gpio_g_in = 0x01ffffff,
|
||||
.gpio_g_out = 0x07ffffff,
|
||||
.gpio_b = 0x80
|
||||
},
|
||||
{
|
||||
.ioif = if_ata,
|
||||
.name = "ata",
|
||||
.groups = group_a | group_b | group_c | group_d,
|
||||
|
||||
.group_a = 0x7ffff,
|
||||
.group_b = 0x0f,
|
||||
.group_c = 0x0f,
|
||||
.group_d = 0x7cfff,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0xf9ffffff,
|
||||
.gpio_g_out = 0xffffffff,
|
||||
.gpio_b = 0x80
|
||||
},
|
||||
{
|
||||
.ioif = if_csp,
|
||||
.groups = group_f, /* if_csp and if_i2c can be used simultaneously */
|
||||
.name = "csp",
|
||||
.groups = group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0xfc,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0xfc
|
||||
},
|
||||
{
|
||||
.ioif = if_i2c,
|
||||
.groups = group_f, /* if_csp and if_i2c can be used simultaneously */
|
||||
.name = "i2c",
|
||||
.groups = group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0x03,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0x03
|
||||
},
|
||||
{
|
||||
.ioif = if_usb_1,
|
||||
.name = "usb_1",
|
||||
.groups = group_e | group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0x0f,
|
||||
.group_f = 0x2c,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0x2c
|
||||
},
|
||||
{
|
||||
.ioif = if_usb_2,
|
||||
.name = "usb_2",
|
||||
.groups = group_d,
|
||||
.gpio_g_in = 0x0e000000,
|
||||
.gpio_g_out = 0x3c000000,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0x33e00,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x3e000000,
|
||||
.gpio_g_out = 0x0c000000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
/* GPIO pins */
|
||||
{
|
||||
.ioif = if_gpio_grp_a,
|
||||
.name = "gpio_a",
|
||||
.groups = group_a,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x0000ff3f,
|
||||
.gpio_g_out = 0x0000ff3f,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_gpio_grp_b,
|
||||
.name = "gpio_b",
|
||||
.groups = group_b,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x000000c0,
|
||||
.gpio_g_out = 0x000000c0,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_gpio_grp_c,
|
||||
.name = "gpio_c",
|
||||
.groups = group_c,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0xc0000000,
|
||||
.gpio_g_out = 0xc0000000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_gpio_grp_d,
|
||||
.name = "gpio_d",
|
||||
.groups = group_d,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x3fff0000,
|
||||
.gpio_g_out = 0x3fff0000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_gpio_grp_e,
|
||||
.name = "gpio_e",
|
||||
.groups = group_e,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0x00
|
||||
},
|
||||
{
|
||||
.ioif = if_gpio_grp_f,
|
||||
.name = "gpio_f",
|
||||
.groups = group_f,
|
||||
|
||||
.group_a = 0,
|
||||
.group_b = 0,
|
||||
.group_c = 0,
|
||||
.group_d = 0,
|
||||
.group_e = 0,
|
||||
.group_f = 0,
|
||||
|
||||
.gpio_g_in = 0x00000000,
|
||||
.gpio_g_out = 0x00000000,
|
||||
.gpio_b = 0xff
|
||||
|
@ -284,11 +542,13 @@ static struct interface interfaces[] = {
|
|||
|
||||
static struct watcher *watchers = NULL;
|
||||
|
||||
/* The pins that are free to use in the GPIO ports. */
|
||||
static unsigned int gpio_in_pins = 0xffffffff;
|
||||
static unsigned int gpio_out_pins = 0xffffffff;
|
||||
static unsigned char gpio_pb_pins = 0xff;
|
||||
static unsigned char gpio_pa_pins = 0xff;
|
||||
|
||||
/* Identifiers for the owners of the GPIO pins. */
|
||||
static enum cris_io_interface gpio_pa_owners[8];
|
||||
static enum cris_io_interface gpio_pb_owners[8];
|
||||
static enum cris_io_interface gpio_pg_owners[32];
|
||||
|
@ -338,13 +598,15 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
|
|||
struct if_group *grp;
|
||||
unsigned char group_set;
|
||||
unsigned long flags;
|
||||
int res = 0;
|
||||
|
||||
(void)cris_io_interface_init();
|
||||
|
||||
DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id));
|
||||
|
||||
if ((ioif >= if_max_interfaces) || (ioif < 0)) {
|
||||
printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n",
|
||||
printk(KERN_CRIT "cris_request_io_interface: Bad interface "
|
||||
"%u submitted for %s\n",
|
||||
ioif,
|
||||
device_id);
|
||||
return -EINVAL;
|
||||
|
@ -353,59 +615,69 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
|
|||
local_irq_save(flags);
|
||||
|
||||
if (interfaces[ioif].used) {
|
||||
local_irq_restore(flags);
|
||||
printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n",
|
||||
printk(KERN_CRIT "cris_io_interface: Cannot allocate interface "
|
||||
"%s for %s, in use by %s\n",
|
||||
interfaces[ioif].name,
|
||||
device_id,
|
||||
interfaces[ioif].owner);
|
||||
return -EBUSY;
|
||||
res = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Check that all required groups are free before allocating, */
|
||||
/* Check that all required pins in the used groups are free
|
||||
* before allocating. */
|
||||
group_set = interfaces[ioif].groups;
|
||||
while (NULL != (grp = get_group(group_set))) {
|
||||
if (grp->used) {
|
||||
if (grp->group == group_f) {
|
||||
if ((if_sync_serial_1 == ioif) ||
|
||||
(if_sync_serial_3 == ioif)) {
|
||||
if ((grp->owner != if_sync_serial_1) &&
|
||||
(grp->owner != if_sync_serial_3)) {
|
||||
local_irq_restore(flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
} else if ((if_scsi8_0 == ioif) ||
|
||||
(if_scsi8_1 == ioif)) {
|
||||
if ((grp->owner != if_scsi8_0) &&
|
||||
(grp->owner != if_scsi8_1)) {
|
||||
local_irq_restore(flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
local_irq_restore(flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
unsigned int if_group_use = 0;
|
||||
|
||||
switch (grp->group) {
|
||||
case group_a:
|
||||
if_group_use = interfaces[ioif].group_a;
|
||||
break;
|
||||
case group_b:
|
||||
if_group_use = interfaces[ioif].group_b;
|
||||
break;
|
||||
case group_c:
|
||||
if_group_use = interfaces[ioif].group_c;
|
||||
break;
|
||||
case group_d:
|
||||
if_group_use = interfaces[ioif].group_d;
|
||||
break;
|
||||
case group_e:
|
||||
if_group_use = interfaces[ioif].group_e;
|
||||
break;
|
||||
case group_f:
|
||||
if_group_use = interfaces[ioif].group_f;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
if (if_group_use & grp->used) {
|
||||
printk(KERN_INFO "cris_request_io_interface: group "
|
||||
"%s needed by %s not available\n",
|
||||
grp->name, interfaces[ioif].name);
|
||||
res = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
group_set = clear_group_from_set(group_set, grp);
|
||||
}
|
||||
|
||||
/* Are the required GPIO pins available too? */
|
||||
if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) ||
|
||||
((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) ||
|
||||
((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) {
|
||||
local_irq_restore(flags);
|
||||
printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n",
|
||||
ioif);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* All needed I/O pins and pin groups are free, allocate. */
|
||||
group_set = interfaces[ioif].groups;
|
||||
while (NULL != (grp = get_group(group_set))) {
|
||||
grp->used = 1;
|
||||
grp->owner = ioif;
|
||||
group_set = clear_group_from_set(group_set, grp);
|
||||
if (((interfaces[ioif].gpio_g_in & gpio_in_pins) !=
|
||||
interfaces[ioif].gpio_g_in) ||
|
||||
((interfaces[ioif].gpio_g_out & gpio_out_pins) !=
|
||||
interfaces[ioif].gpio_g_out) ||
|
||||
((interfaces[ioif].gpio_b & gpio_pb_pins) !=
|
||||
interfaces[ioif].gpio_b)) {
|
||||
printk(KERN_CRIT "cris_request_io_interface: Could not get "
|
||||
"required pins for interface %u\n", ioif);
|
||||
res = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Check which registers need to be reconfigured. */
|
||||
gens = genconfig_shadow;
|
||||
gens_ii = gen_config_ii_shadow;
|
||||
|
||||
|
@ -495,9 +767,43 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
|
|||
set_gen_config = 0;
|
||||
break;
|
||||
default:
|
||||
panic("cris_request_io_interface: Bad interface %u submitted for %s\n",
|
||||
ioif,
|
||||
device_id);
|
||||
printk(KERN_INFO "cris_request_io_interface: Bad interface "
|
||||
"%u submitted for %s\n",
|
||||
ioif, device_id);
|
||||
res = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* All needed I/O pins and pin groups are free, allocate. */
|
||||
group_set = interfaces[ioif].groups;
|
||||
while (NULL != (grp = get_group(group_set))) {
|
||||
unsigned int if_group_use = 0;
|
||||
|
||||
switch (grp->group) {
|
||||
case group_a:
|
||||
if_group_use = interfaces[ioif].group_a;
|
||||
break;
|
||||
case group_b:
|
||||
if_group_use = interfaces[ioif].group_b;
|
||||
break;
|
||||
case group_c:
|
||||
if_group_use = interfaces[ioif].group_c;
|
||||
break;
|
||||
case group_d:
|
||||
if_group_use = interfaces[ioif].group_d;
|
||||
break;
|
||||
case group_e:
|
||||
if_group_use = interfaces[ioif].group_e;
|
||||
break;
|
||||
case group_f:
|
||||
if_group_use = interfaces[ioif].group_f;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
grp->used |= if_group_use;
|
||||
|
||||
group_set = clear_group_from_set(group_set, grp);
|
||||
}
|
||||
|
||||
interfaces[ioif].used = 1;
|
||||
|
@ -516,25 +822,28 @@ int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id
|
|||
*R_GEN_CONFIG_II = gen_config_ii_shadow;
|
||||
}
|
||||
|
||||
DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
gpio_in_pins, gpio_out_pins, gpio_pb_pins));
|
||||
DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
interfaces[ioif].gpio_g_in,
|
||||
interfaces[ioif].gpio_g_out,
|
||||
interfaces[ioif].gpio_b));
|
||||
DBG(printk(KERN_DEBUG "GPIO pins: available before: "
|
||||
"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
gpio_in_pins, gpio_out_pins, gpio_pb_pins));
|
||||
DBG(printk(KERN_DEBUG
|
||||
"grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
interfaces[ioif].gpio_g_in,
|
||||
interfaces[ioif].gpio_g_out,
|
||||
interfaces[ioif].gpio_b));
|
||||
|
||||
gpio_in_pins &= ~interfaces[ioif].gpio_g_in;
|
||||
gpio_out_pins &= ~interfaces[ioif].gpio_g_out;
|
||||
gpio_pb_pins &= ~interfaces[ioif].gpio_b;
|
||||
|
||||
DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
gpio_in_pins, gpio_out_pins, gpio_pb_pins));
|
||||
DBG(printk(KERN_DEBUG "GPIO pins: available after: "
|
||||
"g_in=0x%08x g_out=0x%08x pb=0x%02x\n",
|
||||
gpio_in_pins, gpio_out_pins, gpio_pb_pins));
|
||||
|
||||
exit:
|
||||
local_irq_restore(flags);
|
||||
|
||||
notify_watchers();
|
||||
|
||||
return 0;
|
||||
if (res == 0)
|
||||
notify_watchers();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
@ -560,43 +869,35 @@ void cris_free_io_interface(enum cris_io_interface ioif)
|
|||
}
|
||||
group_set = interfaces[ioif].groups;
|
||||
while (NULL != (grp = get_group(group_set))) {
|
||||
if (grp->group == group_f) {
|
||||
switch (ioif)
|
||||
{
|
||||
case if_sync_serial_1:
|
||||
if ((grp->owner == if_sync_serial_1) &&
|
||||
interfaces[if_sync_serial_3].used) {
|
||||
grp->owner = if_sync_serial_3;
|
||||
} else
|
||||
grp->used = 0;
|
||||
break;
|
||||
case if_sync_serial_3:
|
||||
if ((grp->owner == if_sync_serial_3) &&
|
||||
interfaces[if_sync_serial_1].used) {
|
||||
grp->owner = if_sync_serial_1;
|
||||
} else
|
||||
grp->used = 0;
|
||||
break;
|
||||
case if_scsi8_0:
|
||||
if ((grp->owner == if_scsi8_0) &&
|
||||
interfaces[if_scsi8_1].used) {
|
||||
grp->owner = if_scsi8_1;
|
||||
} else
|
||||
grp->used = 0;
|
||||
break;
|
||||
case if_scsi8_1:
|
||||
if ((grp->owner == if_scsi8_1) &&
|
||||
interfaces[if_scsi8_0].used) {
|
||||
grp->owner = if_scsi8_0;
|
||||
} else
|
||||
grp->used = 0;
|
||||
break;
|
||||
default:
|
||||
grp->used = 0;
|
||||
}
|
||||
} else {
|
||||
grp->used = 0;
|
||||
unsigned int if_group_use = 0;
|
||||
|
||||
switch (grp->group) {
|
||||
case group_a:
|
||||
if_group_use = interfaces[ioif].group_a;
|
||||
break;
|
||||
case group_b:
|
||||
if_group_use = interfaces[ioif].group_b;
|
||||
break;
|
||||
case group_c:
|
||||
if_group_use = interfaces[ioif].group_c;
|
||||
break;
|
||||
case group_d:
|
||||
if_group_use = interfaces[ioif].group_d;
|
||||
break;
|
||||
case group_e:
|
||||
if_group_use = interfaces[ioif].group_e;
|
||||
break;
|
||||
case group_f:
|
||||
if_group_use = interfaces[ioif].group_f;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
|
||||
if ((grp->used & if_group_use) != if_group_use)
|
||||
BUG_ON(1);
|
||||
grp->used = grp->used & ~if_group_use;
|
||||
|
||||
group_set = clear_group_from_set(group_set, grp);
|
||||
}
|
||||
interfaces[ioif].used = 0;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* linux/arch/cris/kernel/irq.c
|
||||
*
|
||||
* Copyright (c) 2000-2002 Axis Communications AB
|
||||
|
@ -18,10 +17,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
/* From kgdb.c. */
|
||||
extern void kgdb_init(void);
|
||||
extern void breakpoint(void);
|
||||
|
||||
#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
|
||||
#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
|
||||
|
||||
|
|
|
@ -17,66 +17,8 @@
|
|||
*! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.
|
||||
*! Jul 21 1999 Bjorn Wesen eLinux port
|
||||
*!
|
||||
*! $Log: kgdb.c,v $
|
||||
*! Revision 1.6 2005/01/14 10:12:17 starvik
|
||||
*! KGDB on separate port.
|
||||
*! Console fixes from 2.4.
|
||||
*!
|
||||
*! Revision 1.5 2004/10/07 13:59:08 starvik
|
||||
*! Corrected call to set_int_vector
|
||||
*!
|
||||
*! Revision 1.4 2003/04/09 05:20:44 starvik
|
||||
*! Merge of Linux 2.5.67
|
||||
*!
|
||||
*! Revision 1.3 2003/01/21 19:11:08 starvik
|
||||
*! Modified include path for new dir layout
|
||||
*!
|
||||
*! Revision 1.2 2002/11/19 14:35:24 starvik
|
||||
*! Changes from linux 2.4
|
||||
*! Changed struct initializer syntax to the currently preferred notation
|
||||
*!
|
||||
*! Revision 1.1 2001/12/17 13:59:27 bjornw
|
||||
*! Initial revision
|
||||
*!
|
||||
*! Revision 1.6 2001/10/09 13:10:03 matsfg
|
||||
*! Added $ on registers and removed some underscores
|
||||
*!
|
||||
*! Revision 1.5 2001/04/17 13:58:39 orjanf
|
||||
*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
|
||||
*!
|
||||
*! Revision 1.4 2001/02/23 13:45:19 bjornw
|
||||
*! config.h check
|
||||
*!
|
||||
*! Revision 1.3 2001/01/31 18:08:23 orjanf
|
||||
*! Removed kgdb_handle_breakpoint from being the break 8 handler.
|
||||
*!
|
||||
*! Revision 1.2 2001/01/12 14:22:25 orjanf
|
||||
*! Updated kernel debugging support to work with ETRAX 100LX.
|
||||
*!
|
||||
*! Revision 1.1 2000/07/10 16:25:21 bjornw
|
||||
*! Initial revision
|
||||
*!
|
||||
*! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw
|
||||
*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.
|
||||
*! Mostly copied from arch/etrax100 with appropriate renames of files.
|
||||
*! The mm/ subdir is copied from arch/i386.
|
||||
*! This does not compile yet at all.
|
||||
*!
|
||||
*!
|
||||
*! Revision 1.4 1999/07/22 17:25:25 bjornw
|
||||
*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.
|
||||
*!
|
||||
*! Revision 1.3 1999/07/21 19:51:18 bjornw
|
||||
*! Check if the interrupting char is a ctrl-C, ignore otherwise.
|
||||
*!
|
||||
*! Revision 1.2 1999/07/21 18:09:39 bjornw
|
||||
*! Ported to eLinux architecture, and added some kgdb documentation.
|
||||
*!
|
||||
*!
|
||||
*!---------------------------------------------------------------------------
|
||||
*!
|
||||
*! $Id: kgdb.c,v 1.6 2005/01/14 10:12:17 starvik Exp $
|
||||
*!
|
||||
*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
|
||||
*!
|
||||
*!**************************************************************************/
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* linux/arch/cris/kernel/process.c
|
||||
*
|
||||
* Copyright (C) 1995 Linus Torvalds
|
||||
|
|
|
@ -65,6 +65,7 @@ void
|
|||
ptrace_disable(struct task_struct *child)
|
||||
{
|
||||
/* Todo - pending singlesteps? */
|
||||
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* Various shadow registers. Defines for these are in include/asm-etrax100/io.h
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $
|
||||
/*
|
||||
* Helper functions for trap handlers
|
||||
*
|
||||
* linux/arch/cris/arch-v10/traps.c
|
||||
* Copyright (C) 2000-2007, Axis Communications AB.
|
||||
*
|
||||
* Heler functions for trap handlers
|
||||
*
|
||||
* Copyright (C) 2000-2002 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen
|
||||
* Hans-Peter Nilsson
|
||||
* Authors: Bjorn Wesen
|
||||
* Hans-Peter Nilsson
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -15,124 +12,119 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include <asm/arch/sv_addr_ag.h>
|
||||
|
||||
extern int raw_printk(const char *fmt, ...);
|
||||
|
||||
void
|
||||
show_registers(struct pt_regs * regs)
|
||||
void
|
||||
show_registers(struct pt_regs *regs)
|
||||
{
|
||||
/* We either use rdusp() - the USP register, which might not
|
||||
correspond to the current process for all cases we're called,
|
||||
or we use the current->thread.usp, which is not up to date for
|
||||
the current process. Experience shows we want the USP
|
||||
register. */
|
||||
/*
|
||||
* It's possible to use either the USP register or current->thread.usp.
|
||||
* USP might not correspond to the current process for all cases this
|
||||
* function is called, and current->thread.usp isn't up to date for the
|
||||
* current process. Experience shows that using USP is the way to go.
|
||||
*/
|
||||
unsigned long usp = rdusp();
|
||||
|
||||
raw_printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
|
||||
regs->irp, regs->srp, regs->dccr, usp, regs->mof );
|
||||
raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
|
||||
printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
|
||||
regs->irp, regs->srp, regs->dccr, usp, regs->mof);
|
||||
|
||||
printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
|
||||
|
||||
printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
|
||||
|
||||
printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
|
||||
regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
raw_printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n",
|
||||
regs->r12, regs->r13, regs->orig_r10, regs);
|
||||
raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
|
||||
raw_printk("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
|
||||
printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n",
|
||||
regs->r12, regs->r13, regs->orig_r10, (long unsigned)regs);
|
||||
|
||||
printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE);
|
||||
|
||||
printk("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
current->comm, current->pid, (unsigned long)current);
|
||||
|
||||
/*
|
||||
* When in-kernel, we also print out the stack and code at the
|
||||
* time of the fault..
|
||||
*/
|
||||
if (! user_mode(regs)) {
|
||||
int i;
|
||||
* When in-kernel, we also print out the stack and code at the
|
||||
* time of the fault..
|
||||
*/
|
||||
if (!user_mode(regs)) {
|
||||
int i;
|
||||
|
||||
show_stack(NULL, (unsigned long*)usp);
|
||||
show_stack(NULL, (unsigned long *)usp);
|
||||
|
||||
/* Dump kernel stack if the previous dump wasn't one. */
|
||||
/*
|
||||
* If the previous stack-dump wasn't a kernel one, dump the
|
||||
* kernel stack now.
|
||||
*/
|
||||
if (usp != 0)
|
||||
show_stack (NULL, NULL);
|
||||
show_stack(NULL, NULL);
|
||||
|
||||
raw_printk("\nCode: ");
|
||||
if(regs->irp < PAGE_OFFSET)
|
||||
goto bad;
|
||||
printk("\nCode: ");
|
||||
|
||||
/* Often enough the value at regs->irp does not point to
|
||||
the interesting instruction, which is most often the
|
||||
_previous_ instruction. So we dump at an offset large
|
||||
enough that instruction decoding should be in sync at
|
||||
the interesting point, but small enough to fit on a row
|
||||
(sort of). We point out the regs->irp location in a
|
||||
ksymoops-friendly way by wrapping the byte for that
|
||||
address in parentheses. */
|
||||
for(i = -12; i < 12; i++)
|
||||
{
|
||||
unsigned char c;
|
||||
if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
|
||||
bad:
|
||||
raw_printk(" Bad IP value.");
|
||||
break;
|
||||
}
|
||||
if (regs->irp < PAGE_OFFSET)
|
||||
goto bad_value;
|
||||
|
||||
/*
|
||||
* Quite often the value at regs->irp doesn't point to the
|
||||
* interesting instruction, which often is the previous
|
||||
* instruction. So dump at an offset large enough that the
|
||||
* instruction decoding should be in sync at the interesting
|
||||
* point, but small enough to fit on a row. The regs->irp
|
||||
* location is pointed out in a ksymoops-friendly way by
|
||||
* wrapping the byte for that address in parenthesises.
|
||||
*/
|
||||
for (i = -12; i < 12; i++) {
|
||||
unsigned char c;
|
||||
|
||||
if (__get_user(c, &((unsigned char *)regs->irp)[i])) {
|
||||
bad_value:
|
||||
printk(" Bad IP value.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
raw_printk("(%02x) ", c);
|
||||
printk("(%02x) ", c);
|
||||
else
|
||||
raw_printk("%02x ", c);
|
||||
}
|
||||
raw_printk("\n");
|
||||
}
|
||||
printk("%02x ", c);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Called from entry.S when the watchdog has bitten
|
||||
* We print out something resembling an oops dump, and if
|
||||
* we have the nice doggy development flag set, we halt here
|
||||
* instead of rebooting.
|
||||
*/
|
||||
|
||||
extern void reset_watchdog(void);
|
||||
extern void stop_watchdog(void);
|
||||
|
||||
|
||||
void
|
||||
watchdog_bite_hook(struct pt_regs *regs)
|
||||
arch_enable_nmi(void)
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
local_irq_disable();
|
||||
stop_watchdog();
|
||||
show_registers(regs);
|
||||
while(1) /* nothing */;
|
||||
#else
|
||||
show_registers(regs);
|
||||
#endif
|
||||
asm volatile ("setf m");
|
||||
}
|
||||
|
||||
/* This is normally the 'Oops' routine */
|
||||
void
|
||||
die_if_kernel(const char * str, struct pt_regs * regs, long err)
|
||||
extern void (*nmi_handler)(struct pt_regs *);
|
||||
void handle_nmi(struct pt_regs *regs)
|
||||
{
|
||||
if(user_mode(regs))
|
||||
if (nmi_handler)
|
||||
nmi_handler(regs);
|
||||
|
||||
/* Wait until nmi is no longer active. (We enable NMI immediately after
|
||||
returning from this function, and we don't want it happening while
|
||||
exiting from the NMI interrupt handler.) */
|
||||
while (*R_IRQ_MASK0_RD & IO_STATE(R_IRQ_MASK0_RD, nmi_pin, active))
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
void
|
||||
handle_BUG(struct pt_regs *regs)
|
||||
{
|
||||
struct bug_frame f;
|
||||
unsigned char c;
|
||||
unsigned long irp = regs->irp;
|
||||
|
||||
if (__copy_from_user(&f, (const void __user *)(irp - 8), sizeof f))
|
||||
return;
|
||||
if (f.prefix != BUG_PREFIX || f.magic != BUG_MAGIC)
|
||||
return;
|
||||
if (__get_user(c, f.filename))
|
||||
f.filename = "<bad filename>";
|
||||
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
/* This printout might take too long and trigger the
|
||||
* watchdog normally. If we're in the nice doggy
|
||||
* development mode, stop the watchdog during printout.
|
||||
*/
|
||||
stop_watchdog();
|
||||
#endif
|
||||
|
||||
raw_printk("%s: %04lx\n", str, err & 0xffff);
|
||||
|
||||
show_registers(regs);
|
||||
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
reset_watchdog();
|
||||
#endif
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
void arch_enable_nmi(void)
|
||||
{
|
||||
asm volatile("setf m");
|
||||
printk("kernel BUG at %s:%d!\n", f.filename, f.line);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: checksum.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
|
||||
/*
|
||||
* A fast checksum routine using movem
|
||||
* Copyright (c) 1998-2001 Axis Communications AB
|
||||
*
|
||||
|
@ -61,8 +61,6 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords
|
|||
|
||||
ax
|
||||
addq 0,$r12
|
||||
ax ; do it again, since we might have generated a carry
|
||||
addq 0,$r12
|
||||
|
||||
subq 10*4,$r11
|
||||
bge _mloop
|
||||
|
@ -88,10 +86,6 @@ _word_loop:
|
|||
lsrq 16,$r13 ; r13 = checksum >> 16
|
||||
and.d $r9,$r12 ; checksum = checksum & 0xffff
|
||||
add.d $r13,$r12 ; checksum += r13
|
||||
move.d $r12,$r13 ; do the same again, maybe we got a carry last add
|
||||
lsrq 16,$r13
|
||||
and.d $r9,$r12
|
||||
add.d $r13,$r12
|
||||
|
||||
_no_fold:
|
||||
cmpq 2,$r11
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $Id: checksumcopy.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
|
||||
/*
|
||||
* A fast checksum+copy routine using movem
|
||||
* Copyright (c) 1998, 2001 Axis Communications AB
|
||||
*
|
||||
|
@ -67,8 +67,6 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords
|
|||
|
||||
ax
|
||||
addq 0,$r13
|
||||
ax ; do it again, since we might have generated a carry
|
||||
addq 0,$r13
|
||||
|
||||
subq 10*4,$r12
|
||||
bge _mloop
|
||||
|
@ -91,10 +89,6 @@ _word_loop:
|
|||
lsrq 16,$r9 ; r0 = checksum >> 16
|
||||
and.d 0xffff,$r13 ; checksum = checksum & 0xffff
|
||||
add.d $r9,$r13 ; checksum += r0
|
||||
move.d $r13,$r9 ; do the same again, maybe we got a carry last add
|
||||
lsrq 16,$r9
|
||||
and.d 0xffff,$r13
|
||||
add.d $r9,$r13
|
||||
|
||||
_no_fold:
|
||||
cmpq 2,$r12
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: dram_init.S,v 1.4 2003/09/22 09:21:59 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* DRAM/SDRAM initialization - alter with care
|
||||
* This file is intended to be included from other assembler files
|
||||
*
|
||||
|
@ -8,60 +7,7 @@
|
|||
*
|
||||
* Copyright (C) 2000, 2001 Axis Communications AB
|
||||
*
|
||||
* Authors: Mikael Starvik (starvik@axis.com)
|
||||
*
|
||||
* $Log: dram_init.S,v $
|
||||
* Revision 1.4 2003/09/22 09:21:59 starvik
|
||||
* Decompresser is linked to 0x407xxxxx and sdram commands are at 0x000xxxxx
|
||||
* so we need to mask off 12 bits.
|
||||
*
|
||||
* Revision 1.3 2003/03/31 09:38:37 starvik
|
||||
* Corrected calculation of end of sdram init commands
|
||||
*
|
||||
* Revision 1.2 2002/11/19 13:33:29 starvik
|
||||
* Changes from Linux 2.4
|
||||
*
|
||||
* Revision 1.13 2002/10/30 07:42:28 starvik
|
||||
* Always read SDRAM command sequence from flash
|
||||
*
|
||||
* Revision 1.12 2002/08/09 11:37:37 orjanf
|
||||
* Added double initialization work-around for Samsung SDRAMs.
|
||||
*
|
||||
* Revision 1.11 2002/06/04 11:43:21 starvik
|
||||
* Check if mrs_data is specified in kernelconfig (necessary for MCM)
|
||||
*
|
||||
* Revision 1.10 2001/10/04 12:00:21 martinnn
|
||||
* Added missing underscores.
|
||||
*
|
||||
* Revision 1.9 2001/10/01 14:47:35 bjornw
|
||||
* Added register prefixes and removed underscores
|
||||
*
|
||||
* Revision 1.8 2001/05/15 07:12:45 hp
|
||||
* Copy warning from head.S about r8 and r9
|
||||
*
|
||||
* Revision 1.7 2001/04/18 12:05:39 bjornw
|
||||
* Fixed comments, and explicitly include config.h to be sure its there
|
||||
*
|
||||
* Revision 1.6 2001/04/10 06:20:16 starvik
|
||||
* Delay should be 200us, not 200ns
|
||||
*
|
||||
* Revision 1.5 2001/04/09 06:01:13 starvik
|
||||
* Added support for 100 MHz SDRAMs
|
||||
*
|
||||
* Revision 1.4 2001/03/26 14:24:01 bjornw
|
||||
* Namechange of some config options
|
||||
*
|
||||
* Revision 1.3 2001/03/23 08:29:41 starvik
|
||||
* Corrected calculation of mrs_data
|
||||
*
|
||||
* Revision 1.2 2001/02/08 15:20:00 starvik
|
||||
* Corrected SDRAM initialization
|
||||
* Should now be included as inline
|
||||
*
|
||||
* Revision 1.1 2001/01/29 13:08:02 starvik
|
||||
* Initial version
|
||||
* This file should be included from all assembler files that needs to
|
||||
* initialize DRAM/SDRAM.
|
||||
* Authors: Mikael Starvik (starvik@axis.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: old_checksum.c,v 1.3 2003/10/27 08:04:32 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* INET 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.
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* Low level bus fault handler
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2000, 2001 Axis Communications AB
|
||||
* Copyright (C) 2000-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen
|
||||
*
|
||||
* Authors: Bjorn Wesen
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
|
@ -60,7 +60,7 @@ handle_mmu_bus_fault(struct pt_regs *regs)
|
|||
#ifdef DEBUG
|
||||
page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
|
||||
acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
|
||||
inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
|
||||
inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
|
||||
index = IO_EXTRACT(R_TLB_SELECT, index, select);
|
||||
#endif
|
||||
miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
|
||||
|
@ -84,12 +84,13 @@ handle_mmu_bus_fault(struct pt_regs *regs)
|
|||
local_irq_disable();
|
||||
pmd = (pmd_t *)(pgd + pgd_index(address));
|
||||
if (pmd_none(*pmd))
|
||||
return;
|
||||
goto exit;
|
||||
pte = *pte_offset_kernel(pmd, address);
|
||||
if (!pte_present(pte))
|
||||
return;
|
||||
goto exit;
|
||||
*R_TLB_SELECT = select;
|
||||
*R_TLB_HI = cause;
|
||||
*R_TLB_LO = pte_val(pte);
|
||||
exit:
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* Low level TLB handling
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2000-2002 Axis Communications AB
|
||||
*
|
||||
* Copyright (C) 2000-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (bjornw@axis.com)
|
||||
*
|
||||
*/
|
||||
|
@ -39,7 +39,7 @@ flush_tlb_all(void)
|
|||
unsigned long flags;
|
||||
|
||||
/* the vpn of i & 0xf is so we dont write similar TLB entries
|
||||
* in the same 4-way entry group. details..
|
||||
* in the same 4-way entry group. details...
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -47,7 +47,7 @@ flush_tlb_all(void)
|
|||
*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
|
||||
*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
|
||||
IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
|
||||
|
||||
|
||||
*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
|
||||
IO_STATE(R_TLB_LO, valid, no ) |
|
||||
IO_STATE(R_TLB_LO, kernel,no ) |
|
||||
|
@ -71,10 +71,10 @@ flush_tlb_mm(struct mm_struct *mm)
|
|||
|
||||
if(page_id == NO_CONTEXT)
|
||||
return;
|
||||
|
||||
|
||||
/* mark the TLB entries that match the page_id as invalid.
|
||||
* here we could also check the _PAGE_GLOBAL bit and NOT flush
|
||||
* global pages. is it worth the extra I/O ?
|
||||
* global pages. is it worth the extra I/O ?
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -83,7 +83,7 @@ flush_tlb_mm(struct mm_struct *mm)
|
|||
if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
|
||||
*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
|
||||
IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
|
||||
|
||||
|
||||
*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
|
||||
IO_STATE(R_TLB_LO, valid, no ) |
|
||||
IO_STATE(R_TLB_LO, kernel,no ) |
|
||||
|
@ -96,9 +96,7 @@ flush_tlb_mm(struct mm_struct *mm)
|
|||
|
||||
/* invalidate a single page */
|
||||
|
||||
void
|
||||
flush_tlb_page(struct vm_area_struct *vma,
|
||||
unsigned long addr)
|
||||
void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
|
||||
{
|
||||
struct mm_struct *mm = vma->vm_mm;
|
||||
int page_id = mm->context.page_id;
|
||||
|
@ -113,7 +111,7 @@ flush_tlb_page(struct vm_area_struct *vma,
|
|||
addr &= PAGE_MASK; /* perhaps not necessary */
|
||||
|
||||
/* invalidate those TLB entries that match both the mm context
|
||||
* and the virtual address requested
|
||||
* and the virtual address requested
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -125,7 +123,7 @@ flush_tlb_page(struct vm_area_struct *vma,
|
|||
(tlb_hi & PAGE_MASK) == addr) {
|
||||
*R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
|
||||
addr; /* same addr as before works. */
|
||||
|
||||
|
||||
*R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
|
||||
IO_STATE(R_TLB_LO, valid, no ) |
|
||||
IO_STATE(R_TLB_LO, kernel,no ) |
|
||||
|
@ -144,7 +142,7 @@ dump_tlb_all(void)
|
|||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n");
|
||||
|
||||
local_save_flags(flags);
|
||||
|
@ -172,27 +170,29 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
|||
|
||||
/* called in schedule() just before actually doing the switch_to */
|
||||
|
||||
void
|
||||
switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
/* make sure we have a context */
|
||||
if (prev != next) {
|
||||
/* make sure we have a context */
|
||||
get_mmu_context(next);
|
||||
|
||||
get_mmu_context(next);
|
||||
/* remember the pgd for the fault handlers
|
||||
* this is similar to the pgd register in some other CPU's.
|
||||
* we need our own copy of it because current and active_mm
|
||||
* might be invalid at points where we still need to derefer
|
||||
* the pgd.
|
||||
*/
|
||||
|
||||
/* remember the pgd for the fault handlers
|
||||
* this is similar to the pgd register in some other CPU's.
|
||||
* we need our own copy of it because current and active_mm
|
||||
* might be invalid at points where we still need to derefer
|
||||
* the pgd.
|
||||
*/
|
||||
per_cpu(current_pgd, smp_processor_id()) = next->pgd;
|
||||
|
||||
per_cpu(current_pgd, smp_processor_id()) = next->pgd;
|
||||
/* switch context in the MMU */
|
||||
|
||||
/* switch context in the MMU */
|
||||
|
||||
D(printk("switching mmu_context to %d (%p)\n", next->context, next));
|
||||
D(printk(KERN_DEBUG "switching mmu_context to %d (%p)\n",
|
||||
next->context, next));
|
||||
|
||||
*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id);
|
||||
*R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT,
|
||||
page_id, next->context.page_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,73 @@
|
|||
if ETRAX_ARCH_V32
|
||||
|
||||
source arch/cris/arch-v32/mach-fs/Kconfig
|
||||
source arch/cris/arch-v32/mach-a3/Kconfig
|
||||
|
||||
source drivers/cpufreq/Kconfig
|
||||
|
||||
config ETRAX_DRAM_VIRTUAL_BASE
|
||||
hex
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "c0000000"
|
||||
|
||||
config ETRAX_LED1G
|
||||
string "First green LED bit"
|
||||
choice
|
||||
prompt "Nbr of Ethernet LED groups"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default ETRAX_NBR_LED_GRP_ONE
|
||||
help
|
||||
Select how many Ethernet LED groups that can be used. Usually one per Ethernet
|
||||
interface is a good choice.
|
||||
|
||||
config ETRAX_NBR_LED_GRP_ZERO
|
||||
bool "Use zero LED groups"
|
||||
help
|
||||
Select this if you do not want any Ethernet LEDs.
|
||||
|
||||
config ETRAX_NBR_LED_GRP_ONE
|
||||
bool "Use one LED group"
|
||||
help
|
||||
Select this if you want one Ethernet LED group. This LED group
|
||||
can be used for one or more Ethernet interfaces. However, it is
|
||||
recomended that each Ethernet interface use a dedicated LED group.
|
||||
|
||||
config ETRAX_NBR_LED_GRP_TWO
|
||||
bool "Use two LED groups"
|
||||
help
|
||||
Select this if you want two Ethernet LED groups. This is the
|
||||
best choice if you have more than one Ethernet interface and
|
||||
would like to have separate LEDs for the interfaces.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_LED_G_NET0
|
||||
string "Ethernet LED group 0 green LED bit"
|
||||
depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO)
|
||||
default "PA3"
|
||||
help
|
||||
Bit to use for the first green LED (network LED).
|
||||
Most Axis products use bit A3 here.
|
||||
Bit to use for the green LED in Ethernet LED group 0.
|
||||
|
||||
config ETRAX_LED1R
|
||||
string "First red LED bit"
|
||||
depends on ETRAX_ARCH_V32
|
||||
config ETRAX_LED_R_NET0
|
||||
string "Ethernet LED group 0 red LED bit"
|
||||
depends on ETRAX_ARCH_V32 && (ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO)
|
||||
default "PA4"
|
||||
help
|
||||
Bit to use for the first red LED (network LED).
|
||||
Most Axis products use bit A4 here.
|
||||
Bit to use for the red LED in Ethernet LED group 0.
|
||||
|
||||
config ETRAX_LED2G
|
||||
config ETRAX_LED_G_NET1
|
||||
string "Ethernet group 1 green LED bit"
|
||||
depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO
|
||||
default ""
|
||||
help
|
||||
Bit to use for the green LED in Ethernet LED group 1.
|
||||
|
||||
config ETRAX_LED_R_NET1
|
||||
string "Ethernet group 1 red LED bit"
|
||||
depends on ETRAX_ARCH_V32 && ETRAX_NBR_LED_GRP_TWO
|
||||
default ""
|
||||
help
|
||||
Bit to use for the red LED in Ethernet LED group 1.
|
||||
|
||||
config ETRAX_V32_LED2G
|
||||
string "Second green LED bit"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "PA5"
|
||||
|
@ -29,7 +75,7 @@ config ETRAX_LED2G
|
|||
Bit to use for the first green LED (status LED).
|
||||
Most Axis products use bit A5 here.
|
||||
|
||||
config ETRAX_LED2R
|
||||
config ETRAX_V32_LED2R
|
||||
string "Second red LED bit"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "PA6"
|
||||
|
@ -37,7 +83,7 @@ config ETRAX_LED2R
|
|||
Bit to use for the first red LED (network LED).
|
||||
Most Axis products use bit A6 here.
|
||||
|
||||
config ETRAX_LED3G
|
||||
config ETRAX_V32_LED3G
|
||||
string "Third green LED bit"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "PA7"
|
||||
|
@ -45,7 +91,7 @@ config ETRAX_LED3G
|
|||
Bit to use for the first green LED (drive/power LED).
|
||||
Most Axis products use bit A7 here.
|
||||
|
||||
config ETRAX_LED3R
|
||||
config ETRAX_V32_LED3R
|
||||
string "Third red LED bit"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "PA7"
|
||||
|
@ -53,39 +99,6 @@ config ETRAX_LED3R
|
|||
Bit to use for the first red LED (drive/power LED).
|
||||
Most Axis products use bit A7 here.
|
||||
|
||||
choice
|
||||
prompt "Product debug-port"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default ETRAX_DEBUG_PORT0
|
||||
|
||||
config ETRAX_DEBUG_PORT0
|
||||
bool "Serial-0"
|
||||
help
|
||||
Choose a serial port for the ETRAX debug console. Default to
|
||||
port 0.
|
||||
|
||||
config ETRAX_DEBUG_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for the console.
|
||||
|
||||
config ETRAX_DEBUG_PORT_NULL
|
||||
bool "disabled"
|
||||
help
|
||||
Disable serial-port debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Kernel GDB port"
|
||||
depends on ETRAX_KGDB
|
||||
|
@ -95,25 +108,11 @@ choice
|
|||
not be enabled under Drivers for built-in interfaces (as it has its
|
||||
own initialization code) and should not be the same as the debug port.
|
||||
|
||||
config ETRAX_KGDB_PORT0
|
||||
bool "Serial-0"
|
||||
config ETRAX_KGDB_PORT4
|
||||
bool "Serial-4"
|
||||
depends on ETRAX_SERIAL_PORTS = 5
|
||||
help
|
||||
Use serial port 0 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT1
|
||||
bool "Serial-1"
|
||||
help
|
||||
Use serial port 1 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT2
|
||||
bool "Serial-2"
|
||||
help
|
||||
Use serial port 2 for kernel debugging.
|
||||
|
||||
config ETRAX_KGDB_PORT3
|
||||
bool "Serial-3"
|
||||
help
|
||||
Use serial port 3 for kernel debugging.
|
||||
Use serial port 4 for kernel debugging.
|
||||
|
||||
endchoice
|
||||
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
#
|
||||
# arch/cris/arch-v32/boot/Makefile
|
||||
#
|
||||
target = $(target_boot_dir)
|
||||
src = $(src_boot_dir)
|
||||
|
||||
zImage: compressed/vmlinuz
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary -R .note -R .comment
|
||||
|
||||
compressed/vmlinuz: $(objtree)/vmlinux
|
||||
@$(MAKE) -f $(src)/compressed/Makefile $(objtree)/vmlinuz
|
||||
subdir- := compressed rescue
|
||||
targets := Image
|
||||
|
||||
clean:
|
||||
rm -f zImage tools/build compressed/vmlinux.out
|
||||
@$(MAKE) -f $(src)/compressed/Makefile clean
|
||||
$(obj)/Image: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@echo ' Kernel: $@ is ready'
|
||||
|
||||
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
|
||||
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
|
||||
$(Q)$(MAKE) $(build)=$(obj)/rescue $(obj)/rescue/rescue.bin
|
||||
|
||||
$(obj)/zImage: $(obj)/compressed/vmlinux
|
||||
@cp $< $@
|
||||
@echo ' Kernel: $@ is ready'
|
||||
|
|
|
@ -1,41 +1,30 @@
|
|||
#
|
||||
# lx25/arch/cris/arch-v32/boot/compressed/Makefile
|
||||
# arch/cris/arch-v32/boot/compressed/Makefile
|
||||
#
|
||||
# create a compressed vmlinux image from the original vmlinux files and romfs
|
||||
#
|
||||
|
||||
target = $(target_compressed_dir)
|
||||
src = $(src_compressed_dir)
|
||||
|
||||
CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
|
||||
CFLAGS = -O2
|
||||
asflags-y += -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
||||
ccflags-y += -O2 -I $(srctree)/include/asm/mach/ -I $(srctree)/include/asm/arch
|
||||
LD = gcc-cris -mlinux -march=v32 -nostdlib
|
||||
ldflags-y += -T $(obj)/decompress.ld
|
||||
obj-y = head.o misc.o
|
||||
OBJECTS = $(obj)/head.o $(obj)/misc.o
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
OBJECTS = $(target)/head.o $(target)/misc.o
|
||||
|
||||
# files to compress
|
||||
SYSTEM = $(objtree)/vmlinux.bin
|
||||
quiet_cmd_image = BUILD $@
|
||||
cmd_image = cat $(obj)/decompress.bin $(obj)/piggy.gz > $@
|
||||
|
||||
all: vmlinuz
|
||||
targets := vmlinux piggy.gz decompress.o decompress.bin
|
||||
|
||||
$(target)/decompress.bin: $(OBJECTS)
|
||||
$(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS)
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin
|
||||
$(obj)/decompress.o: $(OBJECTS) FORCE
|
||||
$(call if_changed,ld)
|
||||
|
||||
$(objtree)/vmlinuz: $(target) piggy.img $(target)/decompress.bin
|
||||
cat $(target)/decompress.bin piggy.img > $(objtree)/vmlinuz
|
||||
rm -f piggy.img
|
||||
cp $(objtree)/vmlinuz $(src)
|
||||
$(obj)/decompress.bin: $(obj)/decompress.o FORCE
|
||||
$(call if_changed,objcopy)
|
||||
|
||||
$(target)/head.o: $(src)/head.S
|
||||
$(CC) -D__ASSEMBLY__ -c $< -o $@
|
||||
|
||||
# gzip the kernel image
|
||||
|
||||
piggy.img: $(SYSTEM)
|
||||
cat $(SYSTEM) | gzip -f -9 > piggy.img
|
||||
|
||||
clean:
|
||||
rm -f piggy.img $(objtree)/vmlinuz vmlinuz.o decompress.o decompress.bin $(OBJECTS)
|
||||
$(obj)/vmlinux: $(obj)/piggy.gz $(obj)/decompress.bin FORCE
|
||||
$(call if_changed,image)
|
||||
|
||||
$(obj)/piggy.gz: $(obj)/../Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
Creation of the self-extracting compressed kernel image (vmlinuz)
|
||||
-----------------------------------------------------------------
|
||||
$Id: README,v 1.1 2003/08/21 09:37:03 johana Exp $
|
||||
|
||||
This can be slightly confusing because it's a process with many steps.
|
||||
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
* Code that sets up the DRAM registers, calls the
|
||||
* decompressor to unpack the piggybacked kernel, and jumps.
|
||||
*
|
||||
* Copyright (C) 1999 - 2003, Axis Communications AB
|
||||
* Copyright (C) 1999 - 2006, Axis Communications AB
|
||||
*/
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
#include <asm/arch/hwregs/asm/reg_map_asm.h>
|
||||
#include <asm/arch/hwregs/asm/gio_defs_asm.h>
|
||||
#include <asm/arch/hwregs/asm/config_defs_asm.h>
|
||||
#include <hwregs/asm/reg_map_asm.h>
|
||||
#include <asm/arch/mach/startup.inc>
|
||||
|
||||
#define RAM_INIT_MAGIC 0x56902387
|
||||
#define COMMAND_LINE_MAGIC 0x87109563
|
||||
|
@ -22,114 +21,49 @@ start:
|
|||
di
|
||||
|
||||
;; Start clocks for used blocks.
|
||||
move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
|
||||
move.d [$r1], $r0
|
||||
or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, bif, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
|
||||
move.d $r0, [$r1]
|
||||
START_CLOCKS
|
||||
|
||||
;; If booting from NAND flash we first have to copy some
|
||||
;; data from NAND flash to internal RAM to get the code
|
||||
;; that initializes the SDRAM. Lets copy 20 KB. This
|
||||
;; code executes at 0x38010000 if booting from NAND and
|
||||
;; we are guaranted that at least 0x200 bytes are good so
|
||||
;; lets start from there. The first 8192 bytes in the nand
|
||||
;; flash is spliced with zeroes and is thus 16384 bytes.
|
||||
move.d 0x38010200, $r10
|
||||
move.d 0x14200, $r11 ; Start offset in NAND flash 0x10200 + 16384
|
||||
move.d 0x5000, $r12 ; Length of copy
|
||||
|
||||
;; Before this code the tools add a partitiontable so the PC
|
||||
;; has an offset from the linked address.
|
||||
offset1:
|
||||
lapcq ., $r13 ; get PC
|
||||
add.d first_copy_complete-offset1, $r13
|
||||
|
||||
#include "../../lib/nand_init.S"
|
||||
|
||||
first_copy_complete:
|
||||
;; Initialze the DRAM registers.
|
||||
;; Initialize the DRAM registers.
|
||||
cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized?
|
||||
beq dram_init_finished
|
||||
nop
|
||||
|
||||
#include "../../lib/dram_init.S"
|
||||
#include "../../mach/dram_init.S"
|
||||
|
||||
dram_init_finished:
|
||||
lapcq ., $r13 ; get PC
|
||||
add.d second_copy_complete-dram_init_finished, $r13
|
||||
|
||||
move.d REG_ADDR(config, regi_config, r_bootsel), $r0
|
||||
move.d [$r0], $r0
|
||||
and.d REG_MASK(config, r_bootsel, boot_mode), $r0
|
||||
cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0
|
||||
bne second_copy_complete ; No NAND boot
|
||||
nop
|
||||
|
||||
;; Copy 2MB from NAND flash to SDRAM (at 2-4MB into the SDRAM)
|
||||
move.d 0x40204000, $r10
|
||||
move.d 0x8000, $r11
|
||||
move.d 0x200000, $r12
|
||||
ba copy_nand_to_ram
|
||||
nop
|
||||
second_copy_complete:
|
||||
|
||||
;; Initiate the PA port.
|
||||
move.d CONFIG_ETRAX_DEF_GIO_PA_OUT, $r0
|
||||
move.d REG_ADDR(gio, regi_gio, rw_pa_dout), $r1
|
||||
move.d $r0, [$r1]
|
||||
|
||||
move.d CONFIG_ETRAX_DEF_GIO_PA_OE, $r0
|
||||
move.d REG_ADDR(gio, regi_gio, rw_pa_oe), $r1
|
||||
move.d $r0, [$r1]
|
||||
|
||||
GIO_INIT
|
||||
;; Setup the stack to a suitably high address.
|
||||
;; We assume 8 MB is the minimum DRAM and put
|
||||
;; the SP at the top for now.
|
||||
|
||||
move.d 0x40800000, $sp
|
||||
|
||||
;; Figure out where the compressed piggyback image is
|
||||
;; in the flash (since we wont try to copy it to DRAM
|
||||
;; before unpacking). It is at _edata, but in flash.
|
||||
;; Figure out where the compressed piggyback image is.
|
||||
;; It is either in [NOR] flash (we don't want to copy it
|
||||
;; to DRAM before unpacking), or copied to DRAM
|
||||
;; by the [NAND] flash boot loader.
|
||||
;; The piggyback image is at _edata, but relative to where the
|
||||
;; image is actually located in memory, not where it is linked
|
||||
;; (the decompressor is linked at 0x40700000+ and runs there).
|
||||
;; Use (_edata - herami) as offset to the current PC.
|
||||
|
||||
move.d REG_ADDR(config, regi_config, r_bootsel), $r0
|
||||
move.d [$r0], $r0
|
||||
and.d REG_MASK(config, r_bootsel, boot_mode), $r0
|
||||
cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0
|
||||
beq hereami2
|
||||
nop
|
||||
hereami:
|
||||
lapcq ., $r5 ; get PC
|
||||
and.d 0x7fffffff, $r5 ; strip any non-cache bit
|
||||
move.d $r5, $r0 ; save for later - flash address of 'herami'
|
||||
move.d $r5, $r0 ; source address of 'herami'
|
||||
add.d _edata, $r5
|
||||
sub.d hereami, $r5 ; r5 = flash address of '_edata'
|
||||
move.d hereami, $r1 ; destination
|
||||
ba 2f
|
||||
nop
|
||||
hereami2:
|
||||
lapcq ., $r5 ; get PC
|
||||
and.d 0x00ffffff, $r5 ; strip any non-cache bit
|
||||
move.d $r5, $r6
|
||||
or.d 0x40200000, $r6
|
||||
move.d $r6, $r0 ; save for later - flash address of 'herami'
|
||||
add.d _edata, $r5
|
||||
sub.d hereami2, $r5 ; r5 = flash address of '_edata'
|
||||
add.d 0x40200000, $r5
|
||||
move.d hereami2, $r1 ; destination
|
||||
2:
|
||||
|
||||
;; Copy text+data to DRAM
|
||||
|
||||
move.d _edata, $r2 ; end destination
|
||||
1: move.w [$r0+], $r3
|
||||
move.w $r3, [$r1+]
|
||||
cmp.d $r2, $r1
|
||||
1: move.w [$r0+], $r3 ; from herami+ source
|
||||
move.w $r3, [$r1+] ; to hereami+ destination (linked address)
|
||||
cmp.d $r2, $r1 ; finish when destination == _edata
|
||||
bcs 1b
|
||||
nop
|
||||
|
||||
move.d input_data, $r0 ; for the decompressor
|
||||
move.d $r5, [$r0] ; for the decompressor
|
||||
|
||||
|
@ -144,16 +78,24 @@ hereami2:
|
|||
nop
|
||||
|
||||
;; Save command line magic and address.
|
||||
move.d _cmd_line_magic, $r12
|
||||
move.d $r10, [$r12]
|
||||
move.d _cmd_line_addr, $r12
|
||||
move.d $r11, [$r12]
|
||||
move.d _cmd_line_magic, $r0
|
||||
move.d $r10, [$r0]
|
||||
move.d _cmd_line_addr, $r0
|
||||
move.d $r11, [$r0]
|
||||
|
||||
;; Save boot source indicator
|
||||
move.d _boot_source, $r0
|
||||
move.d $r12, [$r0]
|
||||
|
||||
;; Do the decompression and save compressed size in _inptr
|
||||
|
||||
jsr decompress_kernel
|
||||
nop
|
||||
|
||||
;; Restore boot source indicator
|
||||
move.d _boot_source, $r12
|
||||
move.d [$r12], $r12
|
||||
|
||||
;; Restore command line magic and address.
|
||||
move.d _cmd_line_magic, $r10
|
||||
move.d [$r10], $r10
|
||||
|
@ -166,11 +108,10 @@ hereami2:
|
|||
move.d [$r0], $r9 ; flash address of compressed kernel
|
||||
move.d inptr, $r0
|
||||
add.d [$r0], $r9 ; size of compressed kernel
|
||||
cmp.d 0x40200000, $r9
|
||||
blo enter_kernel
|
||||
nop
|
||||
sub.d 0x40200000, $r9
|
||||
add.d 0x4000, $r9
|
||||
cmp.d 0x40000000, $r9 ; image in DRAM ?
|
||||
blo enter_kernel ; no, must be [NOR] flash, jump
|
||||
nop ; delay slot
|
||||
and.d 0x001fffff, $r9 ; assume compressed kernel was < 2M
|
||||
|
||||
enter_kernel:
|
||||
;; Enter the decompressed kernel
|
||||
|
@ -186,7 +127,7 @@ _cmd_line_magic:
|
|||
.dword 0
|
||||
_cmd_line_addr:
|
||||
.dword 0
|
||||
is_nand_boot:
|
||||
.dword 0
|
||||
_boot_source:
|
||||
.dword 0
|
||||
|
||||
#include "../../lib/hw_settings.S"
|
||||
#include "../../mach/hw_settings.S"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
/*
|
||||
* misc.c
|
||||
*
|
||||
* $Id: misc.c,v 1.8 2005/04/24 18:34:29 starvik Exp $
|
||||
*
|
||||
* This is a collection of several routines from gzip-1.0.3
|
||||
* adapted for Linux.
|
||||
*
|
||||
|
@ -22,9 +20,13 @@
|
|||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/ser_defs.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/ser_defs.h>
|
||||
#include <hwregs/pinmux_defs.h>
|
||||
#ifdef CONFIG_CRIS_MACH_ARTPEC3
|
||||
#include <hwregs/clkgen_defs.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* gzip declarations
|
||||
|
@ -85,7 +87,6 @@ static unsigned outcnt = 0; /* bytes in output buffer */
|
|||
# define Tracecv(c,x)
|
||||
#endif
|
||||
|
||||
static int fill_inbuf(void);
|
||||
static void flush_window(void);
|
||||
static void error(char *m);
|
||||
static void gzip_mark(void **);
|
||||
|
@ -186,6 +187,8 @@ memset(void* s, int c, size_t n)
|
|||
char *ss = (char*)s;
|
||||
|
||||
for (i=0;i<n;i++) ss[i] = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void*
|
||||
|
@ -196,6 +199,8 @@ memcpy(void* __dest, __const void* __src,
|
|||
char *d = (char *)__dest, *s = (char *)__src;
|
||||
|
||||
for (i=0;i<__n;i++) d[i] = s[i];
|
||||
|
||||
return __dest;
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
|
@ -225,15 +230,15 @@ flush_window()
|
|||
static void
|
||||
error(char *x)
|
||||
{
|
||||
puts("\n\n");
|
||||
puts("\r\n\n");
|
||||
puts(x);
|
||||
puts("\n\n -- System halted\n");
|
||||
puts("\r\n\n -- System halted\n");
|
||||
|
||||
while(1); /* Halt */
|
||||
}
|
||||
|
||||
void
|
||||
setup_normal_output_buffer()
|
||||
setup_normal_output_buffer(void)
|
||||
{
|
||||
output_data = (char *)KERNEL_LOAD_ADR;
|
||||
}
|
||||
|
@ -262,15 +267,17 @@ serial_setup(reg_scope_instances regi_ser)
|
|||
rec_baud = REG_RD(ser, regi_ser, rw_rec_baud_div);
|
||||
|
||||
tr_ctrl.stop_bits = 1; /* 2 stop bits. */
|
||||
tr_ctrl.en = 1; /* enable transmitter */
|
||||
rec_ctrl.en = 1; /* enabler receiver */
|
||||
|
||||
/*
|
||||
* The baudrate setup is a bit fishy, but in the end the transceiver is
|
||||
* set to 4800 and the receiver to 115200. The magic value is
|
||||
* 29.493 MHz.
|
||||
* The baudrate setup used to be a bit fishy, but now transmitter and
|
||||
* receiver are both set to the intended baud rate, 115200.
|
||||
* The magic value is 29.493 MHz.
|
||||
*/
|
||||
tr_ctrl.base_freq = regk_ser_f29_493;
|
||||
rec_ctrl.base_freq = regk_ser_f29_493;
|
||||
tr_baud.div = (29493000 / 8) / 4800;
|
||||
tr_baud.div = (29493000 / 8) / 115200;
|
||||
rec_baud.div = (29493000 / 8) / 115200;
|
||||
|
||||
REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
|
||||
|
@ -280,25 +287,52 @@ serial_setup(reg_scope_instances regi_ser)
|
|||
}
|
||||
|
||||
void
|
||||
decompress_kernel()
|
||||
decompress_kernel(void)
|
||||
{
|
||||
char revision;
|
||||
|
||||
/* input_data is set in head.S */
|
||||
inbuf = input_data;
|
||||
#if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
|
||||
defined(CONFIG_ETRAX_DEBUG_PORT2) || \
|
||||
defined(CONFIG_ETRAX_DEBUG_PORT3)
|
||||
reg_pinmux_rw_hwprot hwprot;
|
||||
|
||||
#ifdef CONFIG_CRIS_MACH_ARTPEC3
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl;
|
||||
|
||||
/* Enable corresponding clock region when serial 1..3 selected */
|
||||
|
||||
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
|
||||
#endif
|
||||
|
||||
/* pinmux setup for ports 1..3 */
|
||||
hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT0
|
||||
serial_setup(regi_ser0);
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT1
|
||||
hwprot.ser1 = regk_pinmux_yes;
|
||||
serial_setup(regi_ser1);
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT2
|
||||
hwprot.ser2 = regk_pinmux_yes;
|
||||
serial_setup(regi_ser2);
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT3
|
||||
hwprot.ser3 = regk_pinmux_yes;
|
||||
serial_setup(regi_ser3);
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_DEBUG_PORT1) || \
|
||||
defined(CONFIG_ETRAX_DEBUG_PORT2) || \
|
||||
defined(CONFIG_ETRAX_DEBUG_PORT3)
|
||||
REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
|
||||
#endif
|
||||
|
||||
/* input_data is set in head.S */
|
||||
inbuf = input_data;
|
||||
|
||||
setup_normal_output_buffer();
|
||||
|
||||
|
@ -307,11 +341,11 @@ decompress_kernel()
|
|||
__asm__ volatile ("move $vr,%0" : "=rm" (revision));
|
||||
if (revision < 32)
|
||||
{
|
||||
puts("You need an ETRAX FS to run Linux 2.6/crisv32.\n");
|
||||
puts("You need an ETRAX FS to run Linux 2.6/crisv32.\r\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
puts("Uncompressing Linux...\n");
|
||||
puts("Uncompressing Linux...\r\n");
|
||||
gunzip();
|
||||
puts("Done. Now booting the kernel.\n");
|
||||
puts("Done. Now booting the kernel.\r\n");
|
||||
}
|
||||
|
|
|
@ -1,36 +1,27 @@
|
|||
#
|
||||
# Makefile for rescue code
|
||||
# Makefile for rescue (bootstrap) code
|
||||
#
|
||||
target = $(target_rescue_dir)
|
||||
src = $(src_rescue_dir)
|
||||
|
||||
CC = gcc-cris -mlinux -march=v32 $(LINUXINCLUDE)
|
||||
CFLAGS = -O2
|
||||
ccflags-y += -O2 -I $(srctree)/include/asm/arch/mach/ \
|
||||
-I $(srctree)/include/asm/arch
|
||||
asflags-y += -I $(srctree)/include/asm/arch/mach/ -I $(srctree)/include/asm/arch
|
||||
LD = gcc-cris -mlinux -march=v32 -nostdlib
|
||||
ldflags-y += -T $(obj)/rescue.ld
|
||||
LDPOSTFLAGS = -lgcc
|
||||
OBJCOPY = objcopy-cris
|
||||
OBJCOPYFLAGS = -O binary --remove-section=.bss
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) = head.o
|
||||
OBJECT := $(obj)/head.o
|
||||
|
||||
all: $(target)/rescue.bin
|
||||
targets := rescue.o rescue.bin
|
||||
|
||||
rescue: rescue.bin
|
||||
# do nothing
|
||||
quiet_cmd_ldlibgcc = LD $@
|
||||
cmd_ldlibgcc = $(LD) $(LDFLAGS) $(filter-out FORCE,$^) $(LDPOSTFLAGS) -o $@
|
||||
|
||||
$(target)/rescue.bin: $(target) $(target)/head.o
|
||||
$(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin
|
||||
cp -p $(target)/rescue.bin $(objtree)
|
||||
$(obj)/rescue.o: $(OBJECTS) FORCE
|
||||
$(call if_changed,ldlibgcc)
|
||||
|
||||
$(target):
|
||||
mkdir -p $(target)
|
||||
|
||||
$(target)/head.o: $(src)/head.S
|
||||
$(CC) -D__ASSEMBLY__ -c $< -o $*.o
|
||||
|
||||
clean:
|
||||
rm -f $(target)/*.o $(target)/*.bin
|
||||
|
||||
fastdep:
|
||||
|
||||
modules:
|
||||
|
||||
modules-install:
|
||||
$(obj)/rescue.bin: $(obj)/rescue.o FORCE
|
||||
$(call if_changed,objcopy)
|
||||
cp -p $(obj)/rescue.bin $(objtree)
|
||||
|
|
|
@ -1,38 +1,26 @@
|
|||
/* $Id: head.S,v 1.4 2004/11/01 16:10:28 starvik Exp $
|
||||
/*
|
||||
* Just get started by jumping to CONFIG_ETRAX_PTABLE_SECTOR to start
|
||||
* kernel decompressor.
|
||||
*
|
||||
* In practice, this only works for NOR flash (or some convoluted RAM boot)
|
||||
* and hence is not really useful for Artpec-3, so it's Etrax FS / NOR only.
|
||||
*
|
||||
* This used to be the rescue code but now that is handled by the
|
||||
* RedBoot based RFL instead. Nothing to see here, move along.
|
||||
*/
|
||||
|
||||
#include <asm/arch/hwregs/reg_map_asm.h>
|
||||
#include <asm/arch/hwregs/config_defs_asm.h>
|
||||
#include <mach/startup.inc>
|
||||
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP
|
||||
|
||||
;; Code
|
||||
|
||||
.text
|
||||
start:
|
||||
|
||||
;; Start clocks for used blocks.
|
||||
move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
|
||||
move.d [$r1], $r0
|
||||
or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, bif, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
|
||||
move.d $r0, [$r1]
|
||||
START_CLOCKS
|
||||
|
||||
;; Copy 68KB NAND flash to Internal RAM (if NAND boot)
|
||||
move.d 0x38004000, $r10
|
||||
move.d 0x8000, $r11
|
||||
move.d 0x11000, $r12
|
||||
move.d copy_complete, $r13
|
||||
and.d 0x000fffff, $r13
|
||||
or.d 0x38000000, $r13
|
||||
|
||||
#include "../../lib/nand_init.S"
|
||||
|
||||
;; No NAND found
|
||||
move.d CONFIG_ETRAX_PTABLE_SECTOR, $r10
|
||||
jump $r10 ; Jump to decompresser
|
||||
jump $r10 ; Jump to decompressor
|
||||
nop
|
||||
|
||||
copy_complete:
|
||||
move.d 0x38000000 + CONFIG_ETRAX_PTABLE_SECTOR, $r10
|
||||
jump $r10 ; Jump to decompresser
|
||||
nop
|
||||
#endif
|
||||
|
|
|
@ -1,20 +1,43 @@
|
|||
/*#OUTPUT_FORMAT(elf32-us-cris) */
|
||||
OUTPUT_ARCH (crisv32)
|
||||
/* Now that NAND support has been stripped, this file could be simplified,
|
||||
* but it doesn't do any harm on the other hand so why bother. */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash : ORIGIN = 0x00000000,
|
||||
LENGTH = 0x00100000
|
||||
bootblk : ORIGIN = 0x38000000,
|
||||
LENGTH = 0x00004000
|
||||
intmem : ORIGIN = 0x38004000,
|
||||
LENGTH = 0x00005000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
stext = . ;
|
||||
_stext = . ;
|
||||
*(.text)
|
||||
etext = . ;
|
||||
} > flash
|
||||
*(.init.text)
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
_etext = . ;
|
||||
} > bootblk
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
edata = . ;
|
||||
} > flash
|
||||
_edata = . ;
|
||||
} > bootblk
|
||||
.bss :
|
||||
{
|
||||
_bss = . ;
|
||||
*(.bss)
|
||||
_end = ALIGN( 0x10 ) ;
|
||||
} > intmem
|
||||
|
||||
/* Get rid of stuff from EXPORT_SYMBOL(foo). */
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(__ksymtab_strings)
|
||||
*(__ksymtab)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,64 +4,102 @@ config ETRAX_ETHERNET
|
|||
bool "Ethernet support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
select NET_ETHERNET
|
||||
select MII
|
||||
help
|
||||
This option enables the ETRAX FS built-in 10/100Mbit Ethernet
|
||||
controller.
|
||||
|
||||
config ETRAX_ETHERNET_HW_CSUM
|
||||
bool "Hardware accelerated ethernet checksum and scatter/gather"
|
||||
config ETRAX_NO_PHY
|
||||
bool "PHY not present"
|
||||
depends on ETRAX_ETHERNET
|
||||
depends on ETRAX_STREAMCOPROC
|
||||
default y
|
||||
default N
|
||||
help
|
||||
Hardware acceleration of checksumming and scatter/gather
|
||||
This option disables all MDIO communication with an ethernet
|
||||
transceiver connected to the MII interface. This option shall
|
||||
typically be enabled if the MII interface is connected to a
|
||||
switch. This option should normally be disabled. If enabled,
|
||||
speed and duplex will be locked to 100 Mbit and full duplex.
|
||||
|
||||
config ETRAX_ETHERNET_IFACE0
|
||||
depends on ETRAX_ETHERNET
|
||||
bool "Enable network interface 0"
|
||||
|
||||
config ETRAX_ETHERNET_IFACE1
|
||||
depends on ETRAX_ETHERNET
|
||||
depends on (ETRAX_ETHERNET && ETRAXFS)
|
||||
bool "Enable network interface 1 (uses DMA6 and DMA7)"
|
||||
|
||||
config ETRAX_ETHERNET_GBIT
|
||||
depends on (ETRAX_ETHERNET && CRIS_MACH_ARTPEC3)
|
||||
bool "Enable gigabit Ethernet support"
|
||||
|
||||
choice
|
||||
prompt "Network LED behavior"
|
||||
depends on ETRAX_ETHERNET
|
||||
default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
prompt "Eth0 led group"
|
||||
depends on ETRAX_ETHERNET_IFACE0
|
||||
default ETRAX_ETH0_USE_LEDGRP0
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_LINK
|
||||
bool "LED_on_when_link"
|
||||
config ETRAX_ETH0_USE_LEDGRP0
|
||||
bool "Use LED grp 0"
|
||||
depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
Use LED grp 0 for eth0
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
|
||||
config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY
|
||||
bool "LED_on_when_activity"
|
||||
config ETRAX_ETH0_USE_LEDGRP1
|
||||
bool "Use LED grp 1"
|
||||
depends on ETRAX_NBR_LED_GRP_TWO
|
||||
help
|
||||
Selecting LED_on_when_link will light the LED when there is a
|
||||
connection and will flash off when there is activity.
|
||||
Use LED grp 1 for eth0
|
||||
|
||||
Selecting LED_on_when_activity will light the LED only when
|
||||
there is activity.
|
||||
config ETRAX_ETH0_USE_LEDGRPNULL
|
||||
bool "Use no LEDs for eth0"
|
||||
help
|
||||
Use no LEDs for eth0
|
||||
endchoice
|
||||
|
||||
This setting will also affect the behaviour of other activity LEDs
|
||||
e.g. Bluetooth.
|
||||
choice
|
||||
prompt "Eth1 led group"
|
||||
depends on ETRAX_ETHERNET_IFACE1
|
||||
default ETRAX_ETH1_USE_LEDGRP1
|
||||
|
||||
config ETRAX_ETH1_USE_LEDGRP0
|
||||
bool "Use LED grp 0"
|
||||
depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
|
||||
help
|
||||
Use LED grp 0 for eth1
|
||||
|
||||
config ETRAX_ETH1_USE_LEDGRP1
|
||||
bool "Use LED grp 1"
|
||||
depends on ETRAX_NBR_LED_GRP_TWO
|
||||
help
|
||||
Use LED grp 1 for eth1
|
||||
|
||||
config ETRAX_ETH1_USE_LEDGRPNULL
|
||||
bool "Use no LEDs for eth1"
|
||||
help
|
||||
Use no LEDs for eth1
|
||||
endchoice
|
||||
|
||||
config ETRAXFS_SERIAL
|
||||
bool "Serial-port support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
select SERIAL_CORE
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Enables the ETRAX FS serial driver for ser0 (ttyS0)
|
||||
You probably want this enabled.
|
||||
|
||||
config ETRAX_RS485
|
||||
bool "RS-485 support"
|
||||
depends on ETRAXFS_SERIAL
|
||||
help
|
||||
Enables support for RS-485 serial communication.
|
||||
|
||||
config ETRAX_RS485_DISABLE_RECEIVER
|
||||
bool "Disable serial receiver"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
It is necessary to disable the serial receiver to avoid serial
|
||||
loopback. Not all products are able to do this in software only.
|
||||
|
||||
config ETRAX_SERIAL_PORT0
|
||||
bool "Serial port 0 enabled"
|
||||
depends on ETRAXFS_SERIAL
|
||||
|
@ -72,50 +110,28 @@ config ETRAX_SERIAL_PORT0
|
|||
ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA in channel "
|
||||
prompt "Ser0 default port type "
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_IN
|
||||
default ETRAX_SERIAL_PORT0_TYPE_232
|
||||
help
|
||||
What DMA channel to use for ser0.
|
||||
Type of serial port.
|
||||
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_IN
|
||||
bool "Ser0 uses no DMA for input"
|
||||
config ETRAX_SERIAL_PORT0_TYPE_232
|
||||
bool "Ser0 is a RS-232 port"
|
||||
help
|
||||
Do not use DMA for ser0 input.
|
||||
Configure serial port 0 to be a RS-232 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
bool "Ser0 uses DMA7 for input"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
config ETRAX_SERIAL_PORT0_TYPE_485HD
|
||||
bool "Ser0 is a half duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Enables the DMA7 input channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
Configure serial port 0 to be a half duplex (two wires) RS-485 port.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser0 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
default ETRAX_SERIAL_PORT0_NO_DMA_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT0_NO_DMA_OUT
|
||||
bool "Ser0 uses no DMA for output"
|
||||
config ETRAX_SERIAL_PORT0_TYPE_485FD
|
||||
bool "Ser0 is a full duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Do not use DMA for ser0 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT0_DMA6_OUT
|
||||
bool "Ser0 uses DMA6 for output"
|
||||
depends on ETRAX_SERIAL_PORT0
|
||||
help
|
||||
Enables the DMA6 output channel for ser0 (ttyS0).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
Configure serial port 0 to be a full duplex (four wires) RS-485 port.
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER0_DTR_BIT
|
||||
|
@ -141,52 +157,28 @@ config ETRAX_SERIAL_PORT1
|
|||
Enables the ETRAX FS serial driver for ser1 (ttyS1).
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA in channel "
|
||||
prompt "Ser1 default port type"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_IN
|
||||
default ETRAX_SERIAL_PORT1_TYPE_232
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
Type of serial port.
|
||||
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_IN
|
||||
bool "Ser1 uses no DMA for input"
|
||||
config ETRAX_SERIAL_PORT1_TYPE_232
|
||||
bool "Ser1 is a RS-232 port"
|
||||
help
|
||||
Do not use DMA for ser1 input.
|
||||
Configure serial port 1 to be a RS-232 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA5_IN
|
||||
bool "Ser1 uses DMA5 for input"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
config ETRAX_SERIAL_PORT1_TYPE_485HD
|
||||
bool "Ser1 is a half duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Enables the DMA5 input channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
Configure serial port 1 to be a half duplex (two wires) RS-485 port.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser1 DMA out channel "
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
default ETRAX_SERIAL_PORT1_NO_DMA_OUT
|
||||
config ETRAX_SERIAL_PORT1_TYPE_485FD
|
||||
bool "Ser1 is a full duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
What DMA channel to use for ser1.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_NO_DMA_OUT
|
||||
bool "Ser1 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser1 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT1_DMA4_OUT
|
||||
bool "Ser1 uses DMA4 for output"
|
||||
depends on ETRAX_SERIAL_PORT1
|
||||
help
|
||||
Enables the DMA4 output channel for ser1 (ttyS1).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want this on, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
Configure serial port 1 to be a full duplex (four wires) RS-485 port.
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER1_DTR_BIT
|
||||
|
@ -212,51 +204,30 @@ config ETRAX_SERIAL_PORT2
|
|||
Enables the ETRAX FS serial driver for ser2 (ttyS2).
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA in channel "
|
||||
prompt "Ser2 default port type"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_IN
|
||||
default ETRAX_SERIAL_PORT2_TYPE_232
|
||||
help
|
||||
What DMA channel to use for ser2.
|
||||
What DMA channel to use for ser2
|
||||
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_IN
|
||||
bool "Ser2 uses no DMA for input"
|
||||
config ETRAX_SERIAL_PORT2_TYPE_232
|
||||
bool "Ser2 is a RS-232 port"
|
||||
help
|
||||
Do not use DMA for ser2 input.
|
||||
Configure serial port 2 to be a RS-232 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA3_IN
|
||||
bool "Ser2 uses DMA3 for input"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
config ETRAX_SERIAL_PORT2_TYPE_485HD
|
||||
bool "Ser2 is a half duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Enables the DMA3 input channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
Configure serial port 2 to be a half duplex (two wires) RS-485 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_TYPE_485FD
|
||||
bool "Ser2 is a full duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Configure serial port 2 to be a full duplex (four wires) RS-485 port.
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser2 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
default ETRAX_SERIAL_PORT2_NO_DMA_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT2_NO_DMA_OUT
|
||||
bool "Ser2 uses no DMA for output"
|
||||
help
|
||||
Do not use DMA for ser2 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT2_DMA2_OUT
|
||||
bool "Ser2 uses DMA2 for output"
|
||||
depends on ETRAX_SERIAL_PORT2
|
||||
help
|
||||
Enables the DMA2 output channel for ser2 (ttyS2).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER2_DTR_BIT
|
||||
string "Ser 2 DTR bit (empty = not used)"
|
||||
|
@ -281,50 +252,28 @@ config ETRAX_SERIAL_PORT3
|
|||
Enables the ETRAX FS serial driver for ser3 (ttyS3).
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA in channel "
|
||||
prompt "Ser3 default port type"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_IN
|
||||
default ETRAX_SERIAL_PORT3_TYPE_232
|
||||
help
|
||||
What DMA channel to use for ser3.
|
||||
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_IN
|
||||
bool "Ser3 uses no DMA for input"
|
||||
config ETRAX_SERIAL_PORT3_TYPE_232
|
||||
bool "Ser3 is a RS-232 port"
|
||||
help
|
||||
Do not use DMA for ser3 input.
|
||||
Configure serial port 3 to be a RS-232 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA9_IN
|
||||
bool "Ser3 uses DMA9 for input"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
config ETRAX_SERIAL_PORT3_TYPE_485HD
|
||||
bool "Ser3 is a half duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Enables the DMA9 input channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiving data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
Configure serial port 3 to be a half duplex (two wires) RS-485 port.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser3 DMA out channel"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
default ETRAX_SERIAL_PORT3_NO_DMA_OUT
|
||||
|
||||
config ETRAX_SERIAL_PORT3_NO_DMA_OUT
|
||||
bool "Ser3 uses no DMA for output"
|
||||
config ETRAX_SERIAL_PORT3_TYPE_485FD
|
||||
bool "Ser3 is a full duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Do not use DMA for ser3 output.
|
||||
|
||||
config ETRAX_SERIAL_PORT3_DMA8_OUT
|
||||
bool "Ser3 uses DMA8 for output"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
help
|
||||
Enables the DMA8 output channel for ser3 (ttyS3).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when transmitting data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
Configure serial port 3 to be a full duplex (four wires) RS-485 port.
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER3_DTR_BIT
|
||||
|
@ -343,9 +292,81 @@ config ETRAX_SER3_CD_BIT
|
|||
string "Ser 3 CD bit (empty = not used)"
|
||||
depends on ETRAX_SERIAL_PORT3
|
||||
|
||||
config ETRAX_SERIAL_PORT4
|
||||
bool "Serial port 4 enabled"
|
||||
depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
|
||||
help
|
||||
Enables the ETRAX FS serial driver for ser4 (ttyS4).
|
||||
|
||||
choice
|
||||
prompt "Ser4 default port type"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
default ETRAX_SERIAL_PORT4_TYPE_232
|
||||
help
|
||||
What DMA channel to use for ser4.
|
||||
|
||||
config ETRAX_SERIAL_PORT4_TYPE_232
|
||||
bool "Ser4 is a RS-232 port"
|
||||
help
|
||||
Configure serial port 4 to be a RS-232 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT4_TYPE_485HD
|
||||
bool "Ser4 is a half duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Configure serial port 4 to be a half duplex (two wires) RS-485 port.
|
||||
|
||||
config ETRAX_SERIAL_PORT4_TYPE_485FD
|
||||
bool "Ser4 is a full duplex RS-485 port"
|
||||
depends on ETRAX_RS485
|
||||
help
|
||||
Configure serial port 4 to be a full duplex (four wires) RS-485 port.
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Ser4 DMA in channel "
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
default ETRAX_SERIAL_PORT4_NO_DMA_IN
|
||||
help
|
||||
What DMA channel to use for ser4.
|
||||
|
||||
|
||||
config ETRAX_SERIAL_PORT4_NO_DMA_IN
|
||||
bool "Ser4 uses no DMA for input"
|
||||
help
|
||||
Do not use DMA for ser4 input.
|
||||
|
||||
config ETRAX_SERIAL_PORT4_DMA9_IN
|
||||
bool "Ser4 uses DMA9 for input"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
help
|
||||
Enables the DMA9 input channel for ser4 (ttyS4).
|
||||
If you do not enable DMA, an interrupt for each character will be
|
||||
used when receiveing data.
|
||||
Normally you want to use DMA, unless you use the DMA channel for
|
||||
something else.
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_SER4_DTR_BIT
|
||||
string "Ser 4 DTR bit (empty = not used)"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
|
||||
config ETRAX_SER4_RI_BIT
|
||||
string "Ser 4 RI bit (empty = not used)"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
|
||||
config ETRAX_SER4_DSR_BIT
|
||||
string "Ser 4 DSR bit (empty = not used)"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
|
||||
config ETRAX_SER3_CD_BIT
|
||||
string "Ser 4 CD bit (empty = not used)"
|
||||
depends on ETRAX_SERIAL_PORT4
|
||||
|
||||
config ETRAX_RS485
|
||||
bool "RS-485 support"
|
||||
depends on ETRAX_SERIAL
|
||||
depends on ETRAXFS_SERIAL
|
||||
help
|
||||
Enables support for RS-485 serial communication. For a primer on
|
||||
RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
|
||||
|
@ -356,22 +377,6 @@ config ETRAX_RS485_DISABLE_RECEIVER
|
|||
help
|
||||
It is necessary to disable the serial receiver to avoid serial
|
||||
loopback. Not all products are able to do this in software only.
|
||||
Axis 2400/2401 must disable receiver.
|
||||
|
||||
config ETRAX_AXISFLASHMAP
|
||||
bool "Axis flash-map support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
select MTD
|
||||
select MTD_CFI
|
||||
select MTD_CFI_AMDSTD
|
||||
select MTD_CHAR
|
||||
select MTD_BLOCK
|
||||
select MTD_PARTITIONS
|
||||
select MTD_CONCAT
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
This option enables MTD mapping of flash devices. Needed to use
|
||||
flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL
|
||||
bool "Synchronous serial-port support"
|
||||
|
@ -394,7 +399,7 @@ config ETRAX_SYNCHRONOUS_SERIAL0_DMA
|
|||
|
||||
config ETRAX_SYNCHRONOUS_SERIAL_PORT1
|
||||
bool "Synchronous serial port 1 enabled"
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL
|
||||
depends on ETRAX_SYNCHRONOUS_SERIAL && ETRAXFS
|
||||
help
|
||||
Enabled synchronous serial port 1.
|
||||
|
||||
|
@ -405,6 +410,31 @@ config ETRAX_SYNCHRONOUS_SERIAL1_DMA
|
|||
A synchronous serial port can run in manual or DMA mode.
|
||||
Selecting this option will make it run in DMA mode.
|
||||
|
||||
config ETRAX_AXISFLASHMAP
|
||||
bool "Axis flash-map support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
select MTD
|
||||
select MTD_CFI
|
||||
select MTD_CFI_AMDSTD
|
||||
select MTD_JEDECPROBE
|
||||
select MTD_CHAR
|
||||
select MTD_BLOCK
|
||||
select MTD_PARTITIONS
|
||||
select MTD_CONCAT
|
||||
select MTD_COMPLEX_MAPPINGS
|
||||
help
|
||||
This option enables MTD mapping of flash devices. Needed to use
|
||||
flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_AXISFLASHMAP_MTD0WHOLE
|
||||
bool "MTD0 is whole boot flash device"
|
||||
depends on ETRAX_AXISFLASHMAP
|
||||
default N
|
||||
help
|
||||
When this option is not set, mtd0 refers to the first partition
|
||||
on the boot flash device. When set, mtd0 refers to the whole
|
||||
device, with mtd1 referring to the first partition etc.
|
||||
|
||||
config ETRAX_PTABLE_SECTOR
|
||||
int "Byte-offset of partition table sector"
|
||||
depends on ETRAX_AXISFLASHMAP
|
||||
|
@ -425,42 +455,32 @@ config ETRAX_NANDFLASH
|
|||
This option enables MTD mapping of NAND flash devices. Needed to use
|
||||
NAND flash memories. If unsure, say Y.
|
||||
|
||||
config ETRAX_NANDBOOT
|
||||
bool "Boot from NAND flash"
|
||||
depends on ETRAX_NANDFLASH
|
||||
help
|
||||
This options enables booting from NAND flash devices.
|
||||
Say Y if your boot code, kernel and root file system is in
|
||||
NAND flash. Say N if they are in NOR flash.
|
||||
|
||||
config ETRAX_I2C
|
||||
bool "I2C driver"
|
||||
depends on ETRAX_ARCH_V32
|
||||
help
|
||||
This option enabled the I2C driver used by e.g. the RTC driver.
|
||||
This option enables the I2C driver used by e.g. the RTC driver.
|
||||
|
||||
config ETRAX_I2C_DATA_PORT
|
||||
config ETRAX_V32_I2C_DATA_PORT
|
||||
string "I2C data pin"
|
||||
depends on ETRAX_I2C
|
||||
help
|
||||
The pin to use for I2C data.
|
||||
|
||||
config ETRAX_I2C_CLK_PORT
|
||||
config ETRAX_V32_I2C_CLK_PORT
|
||||
string "I2C clock pin"
|
||||
depends on ETRAX_I2C
|
||||
help
|
||||
The pin to use for I2C clock.
|
||||
|
||||
config ETRAX_RTC
|
||||
bool "Real Time Clock support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
help
|
||||
Enabled RTC support.
|
||||
|
||||
choice
|
||||
prompt "RTC chip"
|
||||
depends on ETRAX_RTC
|
||||
default ETRAX_PCF8563
|
||||
|
||||
config ETRAX_PCF8563
|
||||
bool "PCF8563"
|
||||
help
|
||||
Philips PCF8563 RTC
|
||||
|
||||
endchoice
|
||||
|
||||
config ETRAX_GPIO
|
||||
bool "GPIO support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
|
@ -476,33 +496,36 @@ config ETRAX_GPIO
|
|||
Remember that you need to setup the port directions appropriately in
|
||||
the General configuration.
|
||||
|
||||
config ETRAX_PA_BUTTON_BITMASK
|
||||
hex "PA-buttons bitmask"
|
||||
config ETRAX_VIRTUAL_GPIO
|
||||
bool "Virtual GPIO support"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x02"
|
||||
help
|
||||
This is a bitmask (8 bits) with information about what bits on PA
|
||||
that are used for buttons.
|
||||
Most products has a so called TEST button on PA1, if that is true
|
||||
use 0x02 here.
|
||||
Use 00 if there are no buttons on PA.
|
||||
If the bitmask is <> 00 a button driver will be included in the gpio
|
||||
driver. ETRAX general I/O support must be enabled.
|
||||
Enables the virtual Etrax general port device (major 120, minor 6).
|
||||
It uses an I/O expander for the I2C-bus.
|
||||
|
||||
config ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN
|
||||
int "Virtual GPIO interrupt pin on PA pin"
|
||||
range 0 7
|
||||
depends on ETRAX_VIRTUAL_GPIO
|
||||
help
|
||||
The pin to use on PA for virtual gpio interrupt.
|
||||
|
||||
config ETRAX_PA_CHANGEABLE_DIR
|
||||
hex "PA user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00"
|
||||
default "0x00" if ETRAXFS
|
||||
default "0x00000000" if !ETRAXFS
|
||||
help
|
||||
This is a bitmask (8 bits) with information of what bits in PA that a
|
||||
user can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 0x00 here, but it depends on your hardware.
|
||||
You probably want 0 here, but it depends on your hardware.
|
||||
|
||||
config ETRAX_PA_CHANGEABLE_BITS
|
||||
hex "PA user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00"
|
||||
default "0x00" if ETRAXFS
|
||||
default "0x00000000" if !ETRAXFS
|
||||
help
|
||||
This is a bitmask (8 bits) with information of what bits in PA
|
||||
that a user can change the value on using ioctl's.
|
||||
|
@ -511,17 +534,19 @@ config ETRAX_PA_CHANGEABLE_BITS
|
|||
config ETRAX_PB_CHANGEABLE_DIR
|
||||
hex "PB user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00000"
|
||||
default "0x00000" if ETRAXFS
|
||||
default "0x00000000" if !ETRAXFS
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PB
|
||||
that a user can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 0x00000 here, but it depends on your hardware.
|
||||
You probably want 0 here, but it depends on your hardware.
|
||||
|
||||
config ETRAX_PB_CHANGEABLE_BITS
|
||||
hex "PB user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00000"
|
||||
default "0x00000" if ETRAXFS
|
||||
default "0x00000000" if !ETRAXFS
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PB
|
||||
that a user can change the value on using ioctl's.
|
||||
|
@ -530,17 +555,19 @@ config ETRAX_PB_CHANGEABLE_BITS
|
|||
config ETRAX_PC_CHANGEABLE_DIR
|
||||
hex "PC user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00000"
|
||||
default "0x00000" if ETRAXFS
|
||||
default "0x00000000" if !ETRAXFS
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PC
|
||||
that a user can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 0x00000 here, but it depends on your hardware.
|
||||
You probably want 0 here, but it depends on your hardware.
|
||||
|
||||
config ETRAX_PC_CHANGEABLE_BITS
|
||||
hex "PC user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
default "0x00000"
|
||||
default "0x00000" if ETRAXFS
|
||||
default "0x00000000" if ETRAXFS
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PC
|
||||
that a user can change the value on using ioctl's.
|
||||
|
@ -548,7 +575,7 @@ config ETRAX_PC_CHANGEABLE_BITS
|
|||
|
||||
config ETRAX_PD_CHANGEABLE_DIR
|
||||
hex "PD user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
depends on ETRAX_GPIO && ETRAXFS
|
||||
default "0x00000"
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PD
|
||||
|
@ -558,7 +585,7 @@ config ETRAX_PD_CHANGEABLE_DIR
|
|||
|
||||
config ETRAX_PD_CHANGEABLE_BITS
|
||||
hex "PD user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
depends on ETRAX_GPIO && ETRAXFS
|
||||
default "0x00000"
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PD
|
||||
|
@ -567,7 +594,7 @@ config ETRAX_PD_CHANGEABLE_BITS
|
|||
|
||||
config ETRAX_PE_CHANGEABLE_DIR
|
||||
hex "PE user changeable dir mask"
|
||||
depends on ETRAX_GPIO
|
||||
depends on ETRAX_GPIO && ETRAXFS
|
||||
default "0x00000"
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PE
|
||||
|
@ -577,20 +604,36 @@ config ETRAX_PE_CHANGEABLE_DIR
|
|||
|
||||
config ETRAX_PE_CHANGEABLE_BITS
|
||||
hex "PE user changeable bits mask"
|
||||
depends on ETRAX_GPIO
|
||||
depends on ETRAX_GPIO && ETRAXFS
|
||||
default "0x00000"
|
||||
help
|
||||
This is a bitmask (18 bits) with information of what bits in PE
|
||||
that a user can change the value on using ioctl's.
|
||||
Bit set = changeable.
|
||||
|
||||
config ETRAX_PV_CHANGEABLE_DIR
|
||||
hex "PV user changeable dir mask"
|
||||
depends on ETRAX_VIRTUAL_GPIO
|
||||
default "0x0000"
|
||||
help
|
||||
This is a bitmask (16 bits) with information of what bits in PV
|
||||
that a user can change direction on using ioctl's.
|
||||
Bit set = changeable.
|
||||
You probably want 0x0000 here, but it depends on your hardware.
|
||||
|
||||
config ETRAX_PV_CHANGEABLE_BITS
|
||||
hex "PV user changeable bits mask"
|
||||
depends on ETRAX_VIRTUAL_GPIO
|
||||
default "0x0000"
|
||||
help
|
||||
This is a bitmask (16 bits) with information of what bits in PV
|
||||
that a user can change the value on using ioctl's.
|
||||
Bit set = changeable.
|
||||
|
||||
config ETRAX_CARDBUS
|
||||
bool "Cardbus support"
|
||||
depends on ETRAX_ARCH_V32
|
||||
select PCCARD
|
||||
select CARDBUS
|
||||
select HOTPLUG
|
||||
select PCCARD_NONSTATIC
|
||||
help
|
||||
Enabled the ETRAX Cardbus driver.
|
||||
|
||||
|
@ -613,4 +656,202 @@ config ETRAX_STREAMCOPROC
|
|||
This option enables a driver for the stream co-processor
|
||||
for cryptographic operations.
|
||||
|
||||
source drivers/mmc/Kconfig
|
||||
|
||||
config ETRAX_MMC_IOP
|
||||
tristate "MMC/SD host driver using IO-processor"
|
||||
depends on ETRAX_ARCH_V32 && MMC
|
||||
help
|
||||
This option enables the SD/MMC host controller interface.
|
||||
The host controller is implemented using the built in
|
||||
IO-Processor. Only the SPU is used in this implementation.
|
||||
|
||||
config ETRAX_SPI_MMC
|
||||
# Make this one of several "choices" (possible simultaneously but
|
||||
# suggested uniquely) when an IOP driver emerges for "real" MMC/SD
|
||||
# protocol support.
|
||||
tristate
|
||||
depends on !ETRAX_MMC_IOP
|
||||
default MMC
|
||||
select SPI
|
||||
select MMC_SPI
|
||||
select ETRAX_SPI_MMC_BOARD
|
||||
|
||||
# For the parts that can't be a module (due to restrictions in
|
||||
# framework elsewhere).
|
||||
config ETRAX_SPI_MMC_BOARD
|
||||
boolean
|
||||
default n
|
||||
|
||||
# While the board info is MMC_SPI only, the drivers are written to be
|
||||
# independent of MMC_SPI, so we'll keep SPI non-dependent on the
|
||||
# MMC_SPI config choices (well, except for a single depends-on-line
|
||||
# for the board-info file until a separate non-MMC SPI board file
|
||||
# emerges).
|
||||
# FIXME: When that happens, we'll need to be able to ask for and
|
||||
# configure non-MMC SPI ports together with MMC_SPI ports (if multiple
|
||||
# SPI ports are enabled).
|
||||
|
||||
config SPI_ETRAX_SSER
|
||||
tristate
|
||||
depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
|
||||
select SPI_BITBANG
|
||||
help
|
||||
This enables using an synchronous serial (sser) port as a
|
||||
SPI master controller on Axis ETRAX FS and later. The
|
||||
driver can be configured to use any sser port.
|
||||
|
||||
config SPI_ETRAX_GPIO
|
||||
tristate
|
||||
depends on SPI_MASTER && ETRAX_ARCH_V32 && EXPERIMENTAL
|
||||
select SPI_BITBANG
|
||||
help
|
||||
This enables using GPIO pins port as a SPI master controller
|
||||
on Axis ETRAX FS and later. The driver can be configured to
|
||||
use any GPIO pins.
|
||||
|
||||
config ETRAX_SPI_SSER0
|
||||
tristate "SPI using synchronous serial port 0 (sser0)"
|
||||
depends on ETRAX_SPI_MMC
|
||||
default m if MMC_SPI=m
|
||||
default y if MMC_SPI=y
|
||||
default y if MMC_SPI=n
|
||||
select SPI_ETRAX_SSER
|
||||
help
|
||||
Say Y for an MMC/SD socket connected to synchronous serial port 0,
|
||||
or for devices using the SPI protocol on that port. Say m if you
|
||||
want to build it as a module, which will be named spi_crisv32_sser.
|
||||
(You need to select MMC separately.)
|
||||
|
||||
config ETRAX_SPI_SSER0_DMA
|
||||
bool "DMA for SPI on sser0 enabled"
|
||||
depends on ETRAX_SPI_SSER0
|
||||
depends on !ETRAX_SERIAL_PORT1_DMA4_OUT && !ETRAX_SERIAL_PORT1_DMA5_IN
|
||||
default y
|
||||
help
|
||||
Say Y if using DMA (dma4/dma5) for SPI on synchronous serial port 0.
|
||||
|
||||
config ETRAX_SPI_MMC_CD_SSER0_PIN
|
||||
string "MMC/SD card detect pin for SPI on sser0"
|
||||
depends on ETRAX_SPI_SSER0 && MMC_SPI
|
||||
default "pd11"
|
||||
help
|
||||
The pin to use for SD/MMC card detect. This pin should be pulled up
|
||||
and grounded when a card is present. If defined as " " (space), no
|
||||
pin is selected. A card must then always be inserted for proper
|
||||
action.
|
||||
|
||||
config ETRAX_SPI_MMC_WP_SSER0_PIN
|
||||
string "MMC/SD card write-protect pin for SPI on sser0"
|
||||
depends on ETRAX_SPI_SSER0 && MMC_SPI
|
||||
default "pd10"
|
||||
help
|
||||
The pin to use for the SD/MMC write-protect signal for a memory
|
||||
card. If defined as " " (space), the card is considered writable.
|
||||
|
||||
config ETRAX_SPI_SSER1
|
||||
tristate "SPI using synchronous serial port 1 (sser1)"
|
||||
depends on ETRAX_SPI_MMC
|
||||
default m if MMC_SPI=m && ETRAX_SPI_SSER0=n
|
||||
default y if MMC_SPI=y && ETRAX_SPI_SSER0=n
|
||||
default y if MMC_SPI=n && ETRAX_SPI_SSER0=n
|
||||
select SPI_ETRAX_SSER
|
||||
help
|
||||
Say Y for an MMC/SD socket connected to synchronous serial port 1,
|
||||
or for devices using the SPI protocol on that port. Say m if you
|
||||
want to build it as a module, which will be named spi_crisv32_sser.
|
||||
(You need to select MMC separately.)
|
||||
|
||||
config ETRAX_SPI_SSER1_DMA
|
||||
bool "DMA for SPI on sser1 enabled"
|
||||
depends on ETRAX_SPI_SSER1 && !ETRAX_ETHERNET_IFACE1
|
||||
depends on !ETRAX_SERIAL_PORT0_DMA6_OUT && !ETRAX_SERIAL_PORT0_DMA7_IN
|
||||
default y
|
||||
help
|
||||
Say Y if using DMA (dma6/dma7) for SPI on synchronous serial port 1.
|
||||
|
||||
config ETRAX_SPI_MMC_CD_SSER1_PIN
|
||||
string "MMC/SD card detect pin for SPI on sser1"
|
||||
depends on ETRAX_SPI_SSER1 && MMC_SPI
|
||||
default "pd12"
|
||||
help
|
||||
The pin to use for SD/MMC card detect. This pin should be pulled up
|
||||
and grounded when a card is present. If defined as " " (space), no
|
||||
pin is selected. A card must then always be inserted for proper
|
||||
action.
|
||||
|
||||
config ETRAX_SPI_MMC_WP_SSER1_PIN
|
||||
string "MMC/SD card write-protect pin for SPI on sser1"
|
||||
depends on ETRAX_SPI_SSER1 && MMC_SPI
|
||||
default "pd9"
|
||||
help
|
||||
The pin to use for the SD/MMC write-protect signal for a memory
|
||||
card. If defined as " " (space), the card is considered writable.
|
||||
|
||||
config ETRAX_SPI_GPIO
|
||||
tristate "Bitbanged SPI using gpio pins"
|
||||
depends on ETRAX_SPI_MMC
|
||||
select SPI_ETRAX_GPIO
|
||||
default m if MMC_SPI=m && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
|
||||
default y if MMC_SPI=y && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
|
||||
default y if MMC_SPI=n && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n
|
||||
help
|
||||
Say Y for an MMC/SD socket connected to general I/O pins (but not
|
||||
a complete synchronous serial ports), or for devices using the SPI
|
||||
protocol on general I/O pins. Slow and slows down the system.
|
||||
Say m to build it as a module, which will be called spi_crisv32_gpio.
|
||||
(You need to select MMC separately.)
|
||||
|
||||
# The default match that of sser0, only because that's how it was tested.
|
||||
config ETRAX_SPI_CS_PIN
|
||||
string "SPI chip select pin"
|
||||
depends on ETRAX_SPI_GPIO
|
||||
default "pc3"
|
||||
help
|
||||
The pin to use for SPI chip select.
|
||||
|
||||
config ETRAX_SPI_CLK_PIN
|
||||
string "SPI clock pin"
|
||||
depends on ETRAX_SPI_GPIO
|
||||
default "pc1"
|
||||
help
|
||||
The pin to use for the SPI clock.
|
||||
|
||||
config ETRAX_SPI_DATAIN_PIN
|
||||
string "SPI MISO (data in) pin"
|
||||
depends on ETRAX_SPI_GPIO
|
||||
default "pc16"
|
||||
help
|
||||
The pin to use for SPI data in from the device.
|
||||
|
||||
config ETRAX_SPI_DATAOUT_PIN
|
||||
string "SPI MOSI (data out) pin"
|
||||
depends on ETRAX_SPI_GPIO
|
||||
default "pc0"
|
||||
help
|
||||
The pin to use for SPI data out to the device.
|
||||
|
||||
config ETRAX_SPI_MMC_CD_GPIO_PIN
|
||||
string "MMC/SD card detect pin for SPI using gpio (space for none)"
|
||||
depends on ETRAX_SPI_GPIO && MMC_SPI
|
||||
default "pd11"
|
||||
help
|
||||
The pin to use for SD/MMC card detect. This pin should be pulled up
|
||||
and grounded when a card is present. If defined as " " (space), no
|
||||
pin is selected. A card must then always be inserted for proper
|
||||
action.
|
||||
|
||||
config ETRAX_SPI_MMC_WP_GPIO_PIN
|
||||
string "MMC/SD card write-protect pin for SPI using gpio (space for none)"
|
||||
depends on ETRAX_SPI_GPIO && MMC_SPI
|
||||
default "pd10"
|
||||
help
|
||||
The pin to use for the SD/MMC write-protect signal for a memory
|
||||
card. If defined as " " (space), the card is considered writable.
|
||||
|
||||
# Avoid choices causing non-working configs by conditionalizing the inclusion.
|
||||
if ETRAX_SPI_MMC
|
||||
source drivers/spi/Kconfig
|
||||
endif
|
||||
|
||||
endif
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
obj-$(CONFIG_ETRAX_STREAMCOPROC) += cryptocop.o
|
||||
obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
|
||||
obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
||||
obj-$(CONFIG_ETRAXFS) += mach-fs/
|
||||
obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/
|
||||
obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o
|
||||
obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o
|
||||
obj-$(CONFIG_ETRAX_I2C) += i2c.o
|
||||
obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
|
||||
obj-$(CONFIG_PCI) += pci/
|
||||
obj-$(CONFIG_ETRAX_SPI_MMC_BOARD) += board_mmcspi.o
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Physical mapping layer for MTD using the Axis partitiontable format
|
||||
*
|
||||
* Copyright (c) 2001, 2002, 2003 Axis Communications AB
|
||||
* Copyright (c) 2001-2007 Axis Communications AB
|
||||
*
|
||||
* This file is under the GPL.
|
||||
*
|
||||
|
@ -10,9 +10,6 @@
|
|||
* tells us what other partitions to define. If there isn't, we use a default
|
||||
* partition split defined below.
|
||||
*
|
||||
* Copy of os/lx25/arch/cris/arch-v10/drivers/axisflashmap.c 1.5
|
||||
* with minor changes.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -27,7 +24,8 @@
|
|||
#include <linux/mtd/mtdram.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
#include <asm/arch/hwregs/config_defs.h>
|
||||
#include <linux/cramfs_fs.h>
|
||||
|
||||
#include <asm/axisflashmap.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
|
@ -37,16 +35,24 @@
|
|||
#define FLASH_UNCACHED_ADDR KSEG_E
|
||||
#define FLASH_CACHED_ADDR KSEG_F
|
||||
|
||||
#define PAGESIZE (512)
|
||||
|
||||
#if CONFIG_ETRAX_FLASH_BUSWIDTH==1
|
||||
#define flash_data __u8
|
||||
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2
|
||||
#define flash_data __u16
|
||||
#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4
|
||||
#define flash_data __u16
|
||||
#define flash_data __u32
|
||||
#endif
|
||||
|
||||
/* From head.S */
|
||||
extern unsigned long romfs_start, romfs_length, romfs_in_flash;
|
||||
extern unsigned long romfs_in_flash; /* 1 when romfs_start, _length in flash */
|
||||
extern unsigned long romfs_start, romfs_length;
|
||||
extern unsigned long nand_boot; /* 1 when booted from nand flash */
|
||||
|
||||
struct partition_name {
|
||||
char name[6];
|
||||
};
|
||||
|
||||
/* The master mtd for the entire flash. */
|
||||
struct mtd_info* axisflash_mtd = NULL;
|
||||
|
@ -112,32 +118,20 @@ static struct map_info map_cse1 = {
|
|||
.map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE
|
||||
};
|
||||
|
||||
/* If no partition-table was found, we use this default-set. */
|
||||
#define MAX_PARTITIONS 7
|
||||
#define NUM_DEFAULT_PARTITIONS 3
|
||||
#define MAX_PARTITIONS 7
|
||||
#ifdef CONFIG_ETRAX_NANDBOOT
|
||||
#define NUM_DEFAULT_PARTITIONS 4
|
||||
#define DEFAULT_ROOTFS_PARTITION_NO 2
|
||||
#define DEFAULT_MEDIA_SIZE 0x2000000 /* 32 megs */
|
||||
#else
|
||||
#define NUM_DEFAULT_PARTITIONS 3
|
||||
#define DEFAULT_ROOTFS_PARTITION_NO (-1)
|
||||
#define DEFAULT_MEDIA_SIZE 0x800000 /* 8 megs */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the
|
||||
* size of one flash block and "filesystem"-partition needs 5 blocks to be able
|
||||
* to use JFFS.
|
||||
*/
|
||||
static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
|
||||
{
|
||||
.name = "boot firmware",
|
||||
.size = CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "kernel",
|
||||
.size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR),
|
||||
.offset = CONFIG_ETRAX_PTABLE_SECTOR
|
||||
},
|
||||
{
|
||||
.name = "filesystem",
|
||||
.size = 5 * CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR)
|
||||
}
|
||||
};
|
||||
#if (MAX_PARTITIONS < NUM_DEFAULT_PARTITIONS)
|
||||
#error MAX_PARTITIONS must be >= than NUM_DEFAULT_PARTITIONS
|
||||
#endif
|
||||
|
||||
/* Initialize the ones normally used. */
|
||||
static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
|
||||
|
@ -178,6 +172,56 @@ static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
/* If no partition-table was found, we use this default-set.
|
||||
* Default flash size is 8MB (NOR). CONFIG_ETRAX_PTABLE_SECTOR is most
|
||||
* likely the size of one flash block and "filesystem"-partition needs
|
||||
* to be >=5 blocks to be able to use JFFS.
|
||||
*/
|
||||
static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
|
||||
{
|
||||
.name = "boot firmware",
|
||||
.size = CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = 0
|
||||
},
|
||||
{
|
||||
.name = "kernel",
|
||||
.size = 10 * CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = CONFIG_ETRAX_PTABLE_SECTOR
|
||||
},
|
||||
#define FILESYSTEM_SECTOR (11 * CONFIG_ETRAX_PTABLE_SECTOR)
|
||||
#ifdef CONFIG_ETRAX_NANDBOOT
|
||||
{
|
||||
.name = "rootfs",
|
||||
.size = 10 * CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
.offset = FILESYSTEM_SECTOR
|
||||
},
|
||||
#undef FILESYSTEM_SECTOR
|
||||
#define FILESYSTEM_SECTOR (21 * CONFIG_ETRAX_PTABLE_SECTOR)
|
||||
#endif
|
||||
{
|
||||
.name = "rwfs",
|
||||
.size = DEFAULT_MEDIA_SIZE - FILESYSTEM_SECTOR,
|
||||
.offset = FILESYSTEM_SECTOR
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
|
||||
/* Main flash device */
|
||||
static struct mtd_partition main_partition = {
|
||||
.name = "main",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Auxilliary partition if we find another flash */
|
||||
static struct mtd_partition aux_partition = {
|
||||
.name = "aux",
|
||||
.size = 0,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
/*
|
||||
* Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash
|
||||
* chips in that order (because the amd_flash-driver is faster).
|
||||
|
@ -191,7 +235,7 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
|
|||
map_cs->name, map_cs->size, map_cs->map_priv_1);
|
||||
|
||||
#ifdef CONFIG_MTD_CFI
|
||||
mtd_cs = do_map_probe("cfi_probe", map_cs);
|
||||
mtd_cs = do_map_probe("cfi_probe", map_cs);
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_JEDECPROBE
|
||||
if (!mtd_cs)
|
||||
|
@ -204,7 +248,7 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
|
|||
/*
|
||||
* Probe each chip select individually for flash chips. If there are chips on
|
||||
* both cse0 and cse1, the mtd_info structs will be concatenated to one struct
|
||||
* so that MTD partitions can cross chip boundaries.
|
||||
* so that MTD partitions can cross chip boundries.
|
||||
*
|
||||
* The only known restriction to how you can mount your chips is that each
|
||||
* chip select must hold similar flash chips. But you need external hardware
|
||||
|
@ -216,9 +260,8 @@ static struct mtd_info *flash_probe(void)
|
|||
{
|
||||
struct mtd_info *mtd_cse0;
|
||||
struct mtd_info *mtd_cse1;
|
||||
struct mtd_info *mtd_nand = NULL;
|
||||
struct mtd_info *mtd_total;
|
||||
struct mtd_info *mtds[3];
|
||||
struct mtd_info *mtds[2];
|
||||
int count = 0;
|
||||
|
||||
if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL)
|
||||
|
@ -226,12 +269,7 @@ static struct mtd_info *flash_probe(void)
|
|||
if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL)
|
||||
mtds[count++] = mtd_cse1;
|
||||
|
||||
#ifdef CONFIG_ETRAX_NANDFLASH
|
||||
if ((mtd_nand = crisv32_nand_flash_probe()) != NULL)
|
||||
mtds[count++] = mtd_nand;
|
||||
#endif
|
||||
|
||||
if (!mtd_cse0 && !mtd_cse1 && !mtd_nand) {
|
||||
if (!mtd_cse0 && !mtd_cse1) {
|
||||
/* No chip found. */
|
||||
return NULL;
|
||||
}
|
||||
|
@ -245,9 +283,7 @@ static struct mtd_info *flash_probe(void)
|
|||
* So we use the MTD concatenation layer instead of further
|
||||
* complicating the probing procedure.
|
||||
*/
|
||||
mtd_total = mtd_concat_create(mtds,
|
||||
count,
|
||||
"cse0+cse1+nand");
|
||||
mtd_total = mtd_concat_create(mtds, count, "cse0+cse1");
|
||||
#else
|
||||
printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
|
||||
"(mis)configuration!\n", map_cse0.name, map_cse1.name);
|
||||
|
@ -255,61 +291,162 @@ static struct mtd_info *flash_probe(void)
|
|||
#endif
|
||||
if (!mtd_total) {
|
||||
printk(KERN_ERR "%s and %s: Concatenation failed!\n",
|
||||
map_cse0.name, map_cse1.name);
|
||||
map_cse0.name, map_cse1.name);
|
||||
|
||||
/* The best we can do now is to only use what we found
|
||||
* at cse0.
|
||||
*/
|
||||
* at cse0. */
|
||||
mtd_total = mtd_cse0;
|
||||
map_destroy(mtd_cse1);
|
||||
}
|
||||
} else {
|
||||
mtd_total = mtd_cse0? mtd_cse0 : mtd_cse1 ? mtd_cse1 : mtd_nand;
|
||||
|
||||
}
|
||||
} else
|
||||
mtd_total = mtd_cse0 ? mtd_cse0 : mtd_cse1;
|
||||
|
||||
return mtd_total;
|
||||
}
|
||||
|
||||
extern unsigned long crisv32_nand_boot;
|
||||
extern unsigned long crisv32_nand_cramfs_offset;
|
||||
|
||||
/*
|
||||
* Probe the flash chip(s) and, if it succeeds, read the partition-table
|
||||
* and register the partitions with MTD.
|
||||
*/
|
||||
static int __init init_axis_flash(void)
|
||||
{
|
||||
struct mtd_info *mymtd;
|
||||
struct mtd_info *main_mtd;
|
||||
struct mtd_info *aux_mtd = NULL;
|
||||
int err = 0;
|
||||
int pidx = 0;
|
||||
struct partitiontable_head *ptable_head = NULL;
|
||||
struct partitiontable_entry *ptable;
|
||||
int use_default_ptable = 1; /* Until proven otherwise. */
|
||||
const char *pmsg = KERN_INFO " /dev/flash%d at 0x%08x, size 0x%08x\n";
|
||||
static char page[512];
|
||||
int ptable_ok = 0;
|
||||
static char page[PAGESIZE];
|
||||
size_t len;
|
||||
int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */
|
||||
int part;
|
||||
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
mymtd = flash_probe();
|
||||
mymtd->read(mymtd, CONFIG_ETRAX_PTABLE_SECTOR, 512, &len, page);
|
||||
ptable_head = (struct partitiontable_head *)(page + PARTITION_TABLE_OFFSET);
|
||||
/* We need a root fs. If it resides in RAM, we need to use an
|
||||
* MTDRAM device, so it must be enabled in the kernel config,
|
||||
* but its size must be configured as 0 so as not to conflict
|
||||
* with our usage.
|
||||
*/
|
||||
#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
|
||||
if (!romfs_in_flash && !nand_boot) {
|
||||
printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
|
||||
"device; configure CONFIG_MTD_MTDRAM with size = 0!\n");
|
||||
panic("This kernel cannot boot from RAM!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mymtd) {
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
main_mtd = flash_probe();
|
||||
if (main_mtd)
|
||||
printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
|
||||
main_mtd->name, main_mtd->size);
|
||||
|
||||
#ifdef CONFIG_ETRAX_NANDFLASH
|
||||
aux_mtd = crisv32_nand_flash_probe();
|
||||
if (aux_mtd)
|
||||
printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n",
|
||||
aux_mtd->name, aux_mtd->size);
|
||||
|
||||
#ifdef CONFIG_ETRAX_NANDBOOT
|
||||
{
|
||||
struct mtd_info *tmp_mtd;
|
||||
|
||||
printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, "
|
||||
"making NAND flash primary device.\n");
|
||||
tmp_mtd = main_mtd;
|
||||
main_mtd = aux_mtd;
|
||||
aux_mtd = tmp_mtd;
|
||||
}
|
||||
#endif /* CONFIG_ETRAX_NANDBOOT */
|
||||
#endif /* CONFIG_ETRAX_NANDFLASH */
|
||||
|
||||
if (!main_mtd && !aux_mtd) {
|
||||
/* There's no reason to use this module if no flash chip can
|
||||
* be identified. Make sure that's understood.
|
||||
*/
|
||||
printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
|
||||
} else {
|
||||
printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n",
|
||||
mymtd->name, mymtd->size);
|
||||
axisflash_mtd = mymtd;
|
||||
}
|
||||
|
||||
if (mymtd) {
|
||||
mymtd->owner = THIS_MODULE;
|
||||
#if 0 /* Dump flash memory so we can see what is going on */
|
||||
if (main_mtd) {
|
||||
int sectoraddr, i;
|
||||
for (sectoraddr = 0; sectoraddr < 2*65536+4096;
|
||||
sectoraddr += PAGESIZE) {
|
||||
main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len,
|
||||
page);
|
||||
printk(KERN_INFO
|
||||
"Sector at %d (length %d):\n",
|
||||
sectoraddr, len);
|
||||
for (i = 0; i < PAGESIZE; i += 16) {
|
||||
printk(KERN_INFO
|
||||
"%02x %02x %02x %02x "
|
||||
"%02x %02x %02x %02x "
|
||||
"%02x %02x %02x %02x "
|
||||
"%02x %02x %02x %02x\n",
|
||||
page[i] & 255, page[i+1] & 255,
|
||||
page[i+2] & 255, page[i+3] & 255,
|
||||
page[i+4] & 255, page[i+5] & 255,
|
||||
page[i+6] & 255, page[i+7] & 255,
|
||||
page[i+8] & 255, page[i+9] & 255,
|
||||
page[i+10] & 255, page[i+11] & 255,
|
||||
page[i+12] & 255, page[i+13] & 255,
|
||||
page[i+14] & 255, page[i+15] & 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (main_mtd) {
|
||||
main_mtd->owner = THIS_MODULE;
|
||||
axisflash_mtd = main_mtd;
|
||||
|
||||
loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR;
|
||||
|
||||
/* First partition (rescue) is always set to the default. */
|
||||
pidx++;
|
||||
#ifdef CONFIG_ETRAX_NANDBOOT
|
||||
/* We know where the partition table should be located,
|
||||
* it will be in first good block after that.
|
||||
*/
|
||||
int blockstat;
|
||||
do {
|
||||
blockstat = main_mtd->block_isbad(main_mtd,
|
||||
ptable_sector);
|
||||
if (blockstat < 0)
|
||||
ptable_sector = 0; /* read error */
|
||||
else if (blockstat)
|
||||
ptable_sector += main_mtd->erasesize;
|
||||
} while (blockstat && ptable_sector);
|
||||
#endif
|
||||
if (ptable_sector) {
|
||||
main_mtd->read(main_mtd, ptable_sector, PAGESIZE,
|
||||
&len, page);
|
||||
ptable_head = &((struct partitiontable *) page)->head;
|
||||
}
|
||||
|
||||
#if 0 /* Dump partition table so we can see what is going on */
|
||||
printk(KERN_INFO
|
||||
"axisflashmap: flash read %d bytes at 0x%08x, data: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
len, CONFIG_ETRAX_PTABLE_SECTOR,
|
||||
page[0] & 255, page[1] & 255,
|
||||
page[2] & 255, page[3] & 255,
|
||||
page[4] & 255, page[5] & 255,
|
||||
page[6] & 255, page[7] & 255);
|
||||
printk(KERN_INFO
|
||||
"axisflashmap: partition table offset %d, data: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
PARTITION_TABLE_OFFSET,
|
||||
page[PARTITION_TABLE_OFFSET+0] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+1] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+2] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+3] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+4] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+5] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+6] & 255,
|
||||
page[PARTITION_TABLE_OFFSET+7] & 255);
|
||||
#endif
|
||||
}
|
||||
pidx++; /* First partition is always set to the default. */
|
||||
|
||||
if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
|
||||
&& (ptable_head->size <
|
||||
|
@ -322,7 +459,6 @@ static int __init init_axis_flash(void)
|
|||
/* Looks like a start, sane length and end of a
|
||||
* partition table, lets check csum etc.
|
||||
*/
|
||||
int ptable_ok = 0;
|
||||
struct partitiontable_entry *max_addr =
|
||||
(struct partitiontable_entry *)
|
||||
((unsigned long)ptable_head + sizeof(*ptable_head) +
|
||||
|
@ -346,105 +482,171 @@ static int __init init_axis_flash(void)
|
|||
ptable_ok = (csum == ptable_head->checksum);
|
||||
|
||||
/* Read the entries and use/show the info. */
|
||||
printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n",
|
||||
printk(KERN_INFO "axisflashmap: "
|
||||
"Found a%s partition table at 0x%p-0x%p.\n",
|
||||
(ptable_ok ? " valid" : "n invalid"), ptable_head,
|
||||
max_addr);
|
||||
|
||||
/* We have found a working bootblock. Now read the
|
||||
* partition table. Scan the table. It ends when
|
||||
* there is 0xffffffff, that is, empty flash.
|
||||
* partition table. Scan the table. It ends with 0xffffffff.
|
||||
*/
|
||||
while (ptable_ok
|
||||
&& ptable->offset != 0xffffffff
|
||||
&& ptable->offset != PARTITIONTABLE_END_MARKER
|
||||
&& ptable < max_addr
|
||||
&& pidx < MAX_PARTITIONS) {
|
||||
&& pidx < MAX_PARTITIONS - 1) {
|
||||
|
||||
axis_partitions[pidx].offset = offset + ptable->offset + (crisv32_nand_boot ? 16384 : 0);
|
||||
axis_partitions[pidx].size = ptable->size;
|
||||
axis_partitions[pidx].offset = offset + ptable->offset;
|
||||
#ifdef CONFIG_ETRAX_NANDFLASH
|
||||
if (main_mtd->type == MTD_NANDFLASH) {
|
||||
axis_partitions[pidx].size =
|
||||
(((ptable+1)->offset ==
|
||||
PARTITIONTABLE_END_MARKER) ?
|
||||
main_mtd->size :
|
||||
((ptable+1)->offset + offset)) -
|
||||
(ptable->offset + offset);
|
||||
|
||||
printk(pmsg, pidx, axis_partitions[pidx].offset,
|
||||
axis_partitions[pidx].size);
|
||||
} else
|
||||
#endif /* CONFIG_ETRAX_NANDFLASH */
|
||||
axis_partitions[pidx].size = ptable->size;
|
||||
#ifdef CONFIG_ETRAX_NANDBOOT
|
||||
/* Save partition number of jffs2 ro partition.
|
||||
* Needed if RAM booting or root file system in RAM.
|
||||
*/
|
||||
if (!nand_boot &&
|
||||
ram_rootfs_partition < 0 && /* not already set */
|
||||
ptable->type == PARTITION_TYPE_JFFS2 &&
|
||||
(ptable->flags & PARTITION_FLAGS_READONLY_MASK) ==
|
||||
PARTITION_FLAGS_READONLY)
|
||||
ram_rootfs_partition = pidx;
|
||||
#endif /* CONFIG_ETRAX_NANDBOOT */
|
||||
pidx++;
|
||||
ptable++;
|
||||
}
|
||||
use_default_ptable = !ptable_ok;
|
||||
}
|
||||
|
||||
/* Decide whether to use default partition table. */
|
||||
/* Only use default table if we actually have a device (main_mtd) */
|
||||
|
||||
struct mtd_partition *partition = &axis_partitions[0];
|
||||
if (main_mtd && !ptable_ok) {
|
||||
memcpy(axis_partitions, axis_default_partitions,
|
||||
sizeof(axis_default_partitions));
|
||||
pidx = NUM_DEFAULT_PARTITIONS;
|
||||
ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO;
|
||||
}
|
||||
|
||||
/* Add artificial partitions for rootfs if necessary */
|
||||
if (romfs_in_flash) {
|
||||
/* Add an overlapping device for the root partition (romfs). */
|
||||
|
||||
/* rootfs is in directly accessible flash memory = NOR flash.
|
||||
Add an overlapping device for the rootfs partition. */
|
||||
printk(KERN_INFO "axisflashmap: Adding partition for "
|
||||
"overlapping root file system image\n");
|
||||
axis_partitions[pidx].size = romfs_length;
|
||||
axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
|
||||
axis_partitions[pidx].name = "romfs";
|
||||
if (crisv32_nand_boot) {
|
||||
char* data = kmalloc(1024, GFP_KERNEL);
|
||||
int len;
|
||||
int offset = crisv32_nand_cramfs_offset & ~(1024-1);
|
||||
char* tmp;
|
||||
|
||||
mymtd->read(mymtd, offset, 1024, &len, data);
|
||||
tmp = &data[crisv32_nand_cramfs_offset % 512];
|
||||
axis_partitions[pidx].size = *(unsigned*)(tmp + 4);
|
||||
axis_partitions[pidx].offset = crisv32_nand_cramfs_offset;
|
||||
kfree(data);
|
||||
} else {
|
||||
axis_partitions[pidx].size = romfs_length;
|
||||
axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
|
||||
}
|
||||
|
||||
axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
|
||||
|
||||
printk(KERN_INFO
|
||||
" Adding readonly flash partition for romfs image:\n");
|
||||
printk(pmsg, pidx, axis_partitions[pidx].offset,
|
||||
axis_partitions[pidx].size);
|
||||
ram_rootfs_partition = -1;
|
||||
pidx++;
|
||||
} else if (romfs_length && !nand_boot) {
|
||||
/* romfs exists in memory, but not in flash, so must be in RAM.
|
||||
* Configure an MTDRAM partition. */
|
||||
if (ram_rootfs_partition < 0) {
|
||||
/* None set yet, put it at the end */
|
||||
ram_rootfs_partition = pidx;
|
||||
pidx++;
|
||||
}
|
||||
printk(KERN_INFO "axisflashmap: Adding partition for "
|
||||
"root file system image in RAM\n");
|
||||
axis_partitions[ram_rootfs_partition].size = romfs_length;
|
||||
axis_partitions[ram_rootfs_partition].offset = romfs_start;
|
||||
axis_partitions[ram_rootfs_partition].name = "romfs";
|
||||
axis_partitions[ram_rootfs_partition].mask_flags |=
|
||||
MTD_WRITEABLE;
|
||||
}
|
||||
|
||||
if (mymtd) {
|
||||
if (use_default_ptable) {
|
||||
printk(KERN_INFO " Using default partition table.\n");
|
||||
err = add_mtd_partitions(mymtd, axis_default_partitions,
|
||||
NUM_DEFAULT_PARTITIONS);
|
||||
#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE
|
||||
if (main_mtd) {
|
||||
main_partition.size = main_mtd->size;
|
||||
err = add_mtd_partitions(main_mtd, &main_partition, 1);
|
||||
if (err)
|
||||
panic("axisflashmap: Could not initialize "
|
||||
"partition for whole main mtd device!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Now, register all partitions with mtd.
|
||||
* We do this one at a time so we can slip in an MTDRAM device
|
||||
* in the proper place if required. */
|
||||
|
||||
for (part = 0; part < pidx; part++) {
|
||||
if (part == ram_rootfs_partition) {
|
||||
/* add MTDRAM partition here */
|
||||
struct mtd_info *mtd_ram;
|
||||
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
|
||||
if (!mtd_ram)
|
||||
panic("axisflashmap: Couldn't allocate memory "
|
||||
"for mtd_info!\n");
|
||||
printk(KERN_INFO "axisflashmap: Adding RAM partition "
|
||||
"for rootfs image.\n");
|
||||
err = mtdram_init_device(mtd_ram,
|
||||
(void *)partition[part].offset,
|
||||
partition[part].size,
|
||||
partition[part].name);
|
||||
if (err)
|
||||
panic("axisflashmap: Could not initialize "
|
||||
"MTD RAM device!\n");
|
||||
/* JFFS2 likes to have an erasesize. Keep potential
|
||||
* JFFS2 rootfs happy by providing one. Since image
|
||||
* was most likely created for main mtd, use that
|
||||
* erasesize, if available. Otherwise, make a guess. */
|
||||
mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize :
|
||||
CONFIG_ETRAX_PTABLE_SECTOR);
|
||||
} else {
|
||||
err = add_mtd_partitions(mymtd, axis_partitions, pidx);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
panic("axisflashmap could not add MTD partitions!\n");
|
||||
err = add_mtd_partitions(main_mtd, &partition[part], 1);
|
||||
if (err)
|
||||
panic("axisflashmap: Could not add mtd "
|
||||
"partition %d\n", part);
|
||||
}
|
||||
}
|
||||
/* CONFIG_EXTRAXFS_SIM */
|
||||
#endif
|
||||
#endif /* CONFIG_EXTRAX_VCS_SIM */
|
||||
|
||||
if (!romfs_in_flash) {
|
||||
/* Create an RAM device for the root partition (romfs). */
|
||||
#ifdef CONFIG_ETRAX_VCS_SIM
|
||||
/* For simulator, always use a RAM partition.
|
||||
* The rootfs will be found after the kernel in RAM,
|
||||
* with romfs_start and romfs_end indicating location and size.
|
||||
*/
|
||||
struct mtd_info *mtd_ram;
|
||||
|
||||
#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0)
|
||||
/* No use trying to boot this kernel from RAM. Panic! */
|
||||
printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM "
|
||||
"device due to kernel (mis)configuration!\n");
|
||||
panic("This kernel cannot boot from RAM!\n");
|
||||
#else
|
||||
struct mtd_info *mtd_ram;
|
||||
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info),
|
||||
GFP_KERNEL);
|
||||
if (!mtd_ram) {
|
||||
panic("axisflashmap couldn't allocate memory for "
|
||||
"mtd_info!\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO " Adding RAM partition for romfs image:\n");
|
||||
printk(pmsg, pidx, romfs_start, romfs_length);
|
||||
|
||||
err = mtdram_init_device(mtd_ram, (void*)romfs_start,
|
||||
romfs_length, "romfs");
|
||||
if (err) {
|
||||
panic("axisflashmap could not initialize MTD RAM "
|
||||
"device!\n");
|
||||
}
|
||||
#endif
|
||||
mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
|
||||
if (!mtd_ram) {
|
||||
panic("axisflashmap: Couldn't allocate memory for "
|
||||
"mtd_info!\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
|
||||
"at %u, size %u\n",
|
||||
(unsigned) romfs_start, (unsigned) romfs_length);
|
||||
|
||||
err = mtdram_init_device(mtd_ram, (void *)romfs_start,
|
||||
romfs_length, "romfs");
|
||||
if (err) {
|
||||
panic("axisflashmap: Could not initialize MTD RAM "
|
||||
"device!\n");
|
||||
}
|
||||
#endif /* CONFIG_EXTRAX_VCS_SIM */
|
||||
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
if (aux_mtd) {
|
||||
aux_partition.size = aux_mtd->size;
|
||||
err = add_mtd_partitions(aux_mtd, &aux_partition, 1);
|
||||
if (err)
|
||||
panic("axisflashmap: Could not initialize "
|
||||
"aux mtd device!\n");
|
||||
|
||||
}
|
||||
#endif /* CONFIG_EXTRAX_VCS_SIM */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* $Id: cryptocop.c,v 1.13 2005/04/21 17:27:55 henriken Exp $
|
||||
*
|
||||
/*
|
||||
* Stream co-processor driver for the ETRAX FS
|
||||
*
|
||||
* Copyright (C) 2003-2005 Axis Communications AB
|
||||
* Copyright (C) 2003-2007 Axis Communications AB
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
@ -25,17 +24,29 @@
|
|||
#include <asm/signal.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <asm/arch/dma.h>
|
||||
#include <asm/arch/hwregs/dma.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
|
||||
#include <asm/arch/hwregs/strcop.h>
|
||||
#include <asm/arch/hwregs/strcop_defs.h>
|
||||
#include <asm/arch/cryptocop.h>
|
||||
#include <dma.h>
|
||||
#include <hwregs/dma.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
|
||||
#include <hwregs/strcop.h>
|
||||
#include <hwregs/strcop_defs.h>
|
||||
#include <cryptocop.h>
|
||||
|
||||
#ifdef CONFIG_ETRAXFS
|
||||
#define IN_DMA 9
|
||||
#define OUT_DMA 8
|
||||
#define IN_DMA_INST regi_dma9
|
||||
#define OUT_DMA_INST regi_dma8
|
||||
#define DMA_IRQ DMA9_INTR_VECT
|
||||
#else
|
||||
#define IN_DMA 3
|
||||
#define OUT_DMA 2
|
||||
#define IN_DMA_INST regi_dma3
|
||||
#define OUT_DMA_INST regi_dma2
|
||||
#define DMA_IRQ DMA3_INTR_VECT
|
||||
#endif
|
||||
|
||||
#define DESCR_ALLOC_PAD (31)
|
||||
|
||||
|
@ -1886,14 +1897,14 @@ static void cryptocop_do_tasklet(unsigned long unused)
|
|||
}
|
||||
|
||||
static irqreturn_t
|
||||
dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs)
|
||||
dma_done_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct cryptocop_prio_job *done_job;
|
||||
reg_dma_rw_ack_intr ack_intr = {
|
||||
.data = 1,
|
||||
};
|
||||
|
||||
REG_WR (dma, regi_dma9, rw_ack_intr, ack_intr);
|
||||
REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
|
||||
|
||||
DEBUG(printk("cryptocop DMA done\n"));
|
||||
|
||||
|
@ -1937,7 +1948,6 @@ dma_done_interrupt(int irq, void *dev_id, struct pt_regs * regs)
|
|||
static int init_cryptocop(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_intr_vect_rw_mask intr_mask;
|
||||
reg_dma_rw_cfg dma_cfg = {.en = 1};
|
||||
reg_dma_rw_intr_mask intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */
|
||||
reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 };
|
||||
|
@ -1950,10 +1960,14 @@ static int init_cryptocop(void)
|
|||
.en = 1
|
||||
};
|
||||
|
||||
if (request_irq(DMA9_INTR_VECT, dma_done_interrupt, 0, "stream co-processor DMA", NULL)) panic("request_irq stream co-processor irq dma9");
|
||||
if (request_irq(DMA_IRQ, dma_done_interrupt, 0,
|
||||
"stream co-processor DMA", NULL))
|
||||
panic("request_irq stream co-processor irq dma9");
|
||||
|
||||
(void)crisv32_request_dma(8, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
|
||||
(void)crisv32_request_dma(9, "strcop", DMA_PANIC_ON_ERROR, 0, dma_strp);
|
||||
(void)crisv32_request_dma(OUT_DMA, "strcop", DMA_PANIC_ON_ERROR,
|
||||
0, dma_strp);
|
||||
(void)crisv32_request_dma(IN_DMA, "strcop", DMA_PANIC_ON_ERROR,
|
||||
0, dma_strp);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
|
@ -1963,24 +1977,19 @@ static int init_cryptocop(void)
|
|||
strcop_cfg.en = 1;
|
||||
REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
|
||||
|
||||
/* Enable DMA9 interrupt */
|
||||
intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
|
||||
intr_mask.dma9 = 1;
|
||||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
|
||||
/* Enable DMAs. */
|
||||
REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
|
||||
REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
|
||||
REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
|
||||
REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
|
||||
|
||||
/* Set up wordsize = 4 for DMAs. */
|
||||
DMA_WR_CMD (regi_dma8, regk_dma_set_w_size4);
|
||||
DMA_WR_CMD (regi_dma9, regk_dma_set_w_size4);
|
||||
DMA_WR_CMD(OUT_DMA_INST, regk_dma_set_w_size4);
|
||||
DMA_WR_CMD(IN_DMA_INST, regk_dma_set_w_size4);
|
||||
|
||||
/* Enable interrupts. */
|
||||
REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
|
||||
REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
|
||||
|
||||
/* Clear intr ack. */
|
||||
REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
|
||||
REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
|
@ -1991,7 +2000,6 @@ static int init_cryptocop(void)
|
|||
static void release_cryptocop(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_intr_vect_rw_mask intr_mask;
|
||||
reg_dma_rw_cfg dma_cfg = {.en = 0};
|
||||
reg_dma_rw_intr_mask intr_mask_in = {0};
|
||||
reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 };
|
||||
|
@ -1999,26 +2007,21 @@ static void release_cryptocop(void)
|
|||
local_irq_save(flags);
|
||||
|
||||
/* Clear intr ack. */
|
||||
REG_WR(dma, regi_dma9, rw_ack_intr, ack_intr);
|
||||
|
||||
/* Disable DMA9 interrupt */
|
||||
intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
|
||||
intr_mask.dma9 = 0;
|
||||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
|
||||
|
||||
/* Disable DMAs. */
|
||||
REG_WR(dma, regi_dma9, rw_cfg, dma_cfg); /* input DMA */
|
||||
REG_WR(dma, regi_dma8, rw_cfg, dma_cfg); /* output DMA */
|
||||
REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
|
||||
REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
|
||||
|
||||
/* Disable interrupts. */
|
||||
REG_WR(dma, regi_dma9, rw_intr_mask, intr_mask_in);
|
||||
REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
free_irq(DMA9_INTR_VECT, NULL);
|
||||
free_irq(DMA_IRQ, NULL);
|
||||
|
||||
(void)crisv32_free_dma(8);
|
||||
(void)crisv32_free_dma(9);
|
||||
(void)crisv32_free_dma(OUT_DMA);
|
||||
(void)crisv32_free_dma(IN_DMA);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2076,13 +2079,13 @@ static void cryptocop_job_queue_close(void)
|
|||
reg_dma_rw_cfg dma_out_cfg, dma_in_cfg;
|
||||
|
||||
/* Stop DMA. */
|
||||
dma_out_cfg = REG_RD(dma, regi_dma8, rw_cfg);
|
||||
dma_out_cfg = REG_RD(dma, OUT_DMA_INST, rw_cfg);
|
||||
dma_out_cfg.en = regk_dma_no;
|
||||
REG_WR(dma, regi_dma8, rw_cfg, dma_out_cfg);
|
||||
REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_out_cfg);
|
||||
|
||||
dma_in_cfg = REG_RD(dma, regi_dma9, rw_cfg);
|
||||
dma_in_cfg = REG_RD(dma, IN_DMA_INST, rw_cfg);
|
||||
dma_in_cfg.en = regk_dma_no;
|
||||
REG_WR(dma, regi_dma9, rw_cfg, dma_in_cfg);
|
||||
REG_WR(dma, IN_DMA_INST, rw_cfg, dma_in_cfg);
|
||||
|
||||
/* Disble the cryptocop. */
|
||||
rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg);
|
||||
|
@ -2226,10 +2229,11 @@ static void cryptocop_start_job(void)
|
|||
&pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out)));
|
||||
|
||||
/* Start input DMA. */
|
||||
DMA_START_CONTEXT(regi_dma9, virt_to_phys(&pj->iop->ctx_in));
|
||||
flush_dma_context(&pj->iop->ctx_in);
|
||||
DMA_START_CONTEXT(IN_DMA_INST, virt_to_phys(&pj->iop->ctx_in));
|
||||
|
||||
/* Start output DMA. */
|
||||
DMA_START_CONTEXT(regi_dma8, virt_to_phys(&pj->iop->ctx_out));
|
||||
DMA_START_CONTEXT(OUT_DMA_INST, virt_to_phys(&pj->iop->ctx_out));
|
||||
|
||||
spin_unlock_irqrestore(&running_job_lock, running_job_flags);
|
||||
DEBUG(printk("cryptocop_start_job: exiting\n"));
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
*!
|
||||
*! ---------------------------------------------------------------------------
|
||||
*!
|
||||
*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
|
||||
*! (C) Copyright 1999-2007 Axis Communications AB, LUND, SWEDEN
|
||||
*!
|
||||
*!***************************************************************************/
|
||||
/* $Id: i2c.c,v 1.2 2005/05/09 15:29:49 starvik Exp $ */
|
||||
|
||||
/****************** INCLUDE FILES SECTION ***********************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -79,6 +79,8 @@ static const char i2c_name[] = "i2c";
|
|||
|
||||
#define i2c_delay(usecs) udelay(usecs)
|
||||
|
||||
static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */
|
||||
|
||||
/****************** VARIABLE SECTION ************************************/
|
||||
|
||||
static struct crisv32_iopin cris_i2c_clk;
|
||||
|
@ -252,6 +254,7 @@ i2c_getack(void)
|
|||
* generate ACK clock pulse
|
||||
*/
|
||||
i2c_clk(I2C_CLOCK_HIGH);
|
||||
#if 0
|
||||
/*
|
||||
* Use PORT PB instead of I2C
|
||||
* for input. (I2C not working)
|
||||
|
@ -264,6 +267,8 @@ i2c_getack(void)
|
|||
i2c_data(1);
|
||||
i2c_disable();
|
||||
i2c_dir_in();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* now wait for ack
|
||||
*/
|
||||
|
@ -271,11 +276,11 @@ i2c_getack(void)
|
|||
/*
|
||||
* check for ack
|
||||
*/
|
||||
if(i2c_getbit())
|
||||
if (i2c_getbit())
|
||||
ack = 0;
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
if(!ack){
|
||||
if(!i2c_getbit()) /* receiver pulled SDA low */
|
||||
if (!ack) {
|
||||
if (!i2c_getbit()) /* receiver pulld SDA low */
|
||||
ack = 1;
|
||||
i2c_delay(CLOCK_HIGH_TIME/2);
|
||||
}
|
||||
|
@ -285,6 +290,7 @@ i2c_getack(void)
|
|||
* before we enable our output. If we keep data high
|
||||
* and enable output, we would generate a stop condition.
|
||||
*/
|
||||
#if 0
|
||||
i2c_data(I2C_DATA_LOW);
|
||||
|
||||
/*
|
||||
|
@ -292,6 +298,7 @@ i2c_getack(void)
|
|||
*/
|
||||
i2c_enable();
|
||||
i2c_dir_out();
|
||||
#endif
|
||||
i2c_clk(I2C_CLOCK_LOW);
|
||||
i2c_delay(CLOCK_HIGH_TIME/4);
|
||||
/*
|
||||
|
@ -373,6 +380,121 @@ i2c_sendnack(void)
|
|||
i2c_dir_in();
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_write
|
||||
*#
|
||||
*# DESCRIPTION : Writes a value to an I2C device
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
int
|
||||
i2c_write(unsigned char theSlave, void *data, size_t nbytes)
|
||||
{
|
||||
int error, cntr = 3;
|
||||
unsigned char bytes_wrote = 0;
|
||||
unsigned char value;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&i2c_lock, flags);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
|
||||
i2c_start();
|
||||
/*
|
||||
* send slave address
|
||||
*/
|
||||
i2c_outbyte((theSlave & 0xfe));
|
||||
/*
|
||||
* wait for ack
|
||||
*/
|
||||
if (!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* send data
|
||||
*/
|
||||
for (bytes_wrote = 0; bytes_wrote < nbytes; bytes_wrote++) {
|
||||
memcpy(&value, data + bytes_wrote, sizeof value);
|
||||
i2c_outbyte(value);
|
||||
/*
|
||||
* now it's time to wait for ack
|
||||
*/
|
||||
if (!i2c_getack())
|
||||
error |= 4;
|
||||
}
|
||||
/*
|
||||
* end byte stream
|
||||
*/
|
||||
i2c_stop();
|
||||
|
||||
} while (error && cntr--);
|
||||
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
spin_unlock_irqrestore(&i2c_lock, flags);
|
||||
|
||||
return -error;
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_read
|
||||
*#
|
||||
*# DESCRIPTION : Reads a value from an I2C device
|
||||
*#
|
||||
*#--------------------------------------------------------------------------*/
|
||||
int
|
||||
i2c_read(unsigned char theSlave, void *data, size_t nbytes)
|
||||
{
|
||||
unsigned char b = 0;
|
||||
unsigned char bytes_read = 0;
|
||||
int error, cntr = 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&i2c_lock, flags);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
memset(data, 0, nbytes);
|
||||
/*
|
||||
* generate start condition
|
||||
*/
|
||||
i2c_start();
|
||||
/*
|
||||
* send slave address
|
||||
*/
|
||||
i2c_outbyte((theSlave | 0x01));
|
||||
/*
|
||||
* wait for ack
|
||||
*/
|
||||
if (!i2c_getack())
|
||||
error = 1;
|
||||
/*
|
||||
* fetch data
|
||||
*/
|
||||
for (bytes_read = 0; bytes_read < nbytes; bytes_read++) {
|
||||
b = i2c_inbyte();
|
||||
memcpy(data + bytes_read, &b, sizeof b);
|
||||
|
||||
if (bytes_read < (nbytes - 1))
|
||||
i2c_sendack();
|
||||
}
|
||||
/*
|
||||
* last received byte needs to be nacked
|
||||
* instead of acked
|
||||
*/
|
||||
i2c_sendnack();
|
||||
/*
|
||||
* end sequence
|
||||
*/
|
||||
i2c_stop();
|
||||
} while (error && cntr--);
|
||||
|
||||
spin_unlock_irqrestore(&i2c_lock, flags);
|
||||
|
||||
return -error;
|
||||
}
|
||||
|
||||
/*#---------------------------------------------------------------------------
|
||||
*#
|
||||
*# FUNCTION NAME: i2c_writereg
|
||||
|
@ -387,12 +509,10 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
|
|||
int error, cntr = 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&i2c_lock, flags);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
/*
|
||||
* we don't like to be interrupted
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
i2c_start();
|
||||
/*
|
||||
|
@ -427,15 +547,12 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
|
|||
* end byte stream
|
||||
*/
|
||||
i2c_stop();
|
||||
/*
|
||||
* enable interrupt again
|
||||
*/
|
||||
local_irq_restore(flags);
|
||||
|
||||
} while(error && cntr--);
|
||||
|
||||
i2c_delay(CLOCK_LOW_TIME);
|
||||
|
||||
spin_unlock_irqrestore(&i2c_lock, flags);
|
||||
|
||||
return -error;
|
||||
}
|
||||
|
||||
|
@ -453,12 +570,10 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
|||
int error, cntr = 3;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&i2c_lock, flags);
|
||||
|
||||
do {
|
||||
error = 0;
|
||||
/*
|
||||
* we don't like to be interrupted
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
/*
|
||||
* generate start condition
|
||||
*/
|
||||
|
@ -482,7 +597,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
|||
* now it's time to wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
error |= 2;
|
||||
/*
|
||||
* repeat start condition
|
||||
*/
|
||||
|
@ -496,7 +611,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
|||
* wait for ack
|
||||
*/
|
||||
if(!i2c_getack())
|
||||
error = 1;
|
||||
error |= 4;
|
||||
/*
|
||||
* fetch register
|
||||
*/
|
||||
|
@ -510,13 +625,11 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
|
|||
* end sequence
|
||||
*/
|
||||
i2c_stop();
|
||||
/*
|
||||
* enable interrupt again
|
||||
*/
|
||||
local_irq_restore(flags);
|
||||
|
||||
} while(error && cntr--);
|
||||
|
||||
spin_unlock_irqrestore(&i2c_lock, flags);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
@ -540,7 +653,7 @@ i2c_ioctl(struct inode *inode, struct file *file,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
|
||||
return -EINVAL;
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
|
@ -580,31 +693,52 @@ static const struct file_operations i2c_fops = {
|
|||
.release = i2c_release,
|
||||
};
|
||||
|
||||
int __init
|
||||
i2c_init(void)
|
||||
static int __init i2c_init(void)
|
||||
{
|
||||
static int res;
|
||||
static int first = 1;
|
||||
|
||||
if (!first)
|
||||
return res;
|
||||
|
||||
first = 0;
|
||||
|
||||
/* Setup and enable the DATA and CLK pins */
|
||||
|
||||
res = crisv32_io_get_name(&cris_i2c_data,
|
||||
CONFIG_ETRAX_V32_I2C_DATA_PORT);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
res = crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_V32_I2C_CLK_PORT);
|
||||
crisv32_io_set_dir(&cris_i2c_clk, crisv32_io_dir_out);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int __init i2c_register(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Setup and enable the Port B I2C interface */
|
||||
|
||||
crisv32_io_get_name(&cris_i2c_data, CONFIG_ETRAX_I2C_DATA_PORT);
|
||||
crisv32_io_get_name(&cris_i2c_clk, CONFIG_ETRAX_I2C_CLK_PORT);
|
||||
res = i2c_init();
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
/* register char device */
|
||||
|
||||
res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
|
||||
if(res < 0) {
|
||||
if (res < 0) {
|
||||
printk(KERN_ERR "i2c: couldn't get a major number.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
|
||||
printk(KERN_INFO
|
||||
"I2C driver v2.2, (c) 1999-2007 Axis Communications AB\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this makes sure that i2c_init is called during boot */
|
||||
|
||||
module_init(i2c_init);
|
||||
module_init(i2c_register);
|
||||
|
||||
/****************** END OF FILE i2c.c ********************************/
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
/* High level I2C actions */
|
||||
int __init i2c_init(void);
|
||||
int i2c_write(unsigned char theSlave, void *data, size_t nbytes);
|
||||
int i2c_read(unsigned char theSlave, void *data, size_t nbytes);
|
||||
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
|
||||
unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: iop_fw_load.c,v 1.4 2005/04/07 09:27:46 larsv Exp $
|
||||
*
|
||||
/*
|
||||
* Firmware loader for ETRAX FS IO-Processor
|
||||
*
|
||||
* Copyright (C) 2004 Axis Communications AB
|
||||
|
@ -11,12 +10,13 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/iop/iop_reg_space.h>
|
||||
#include <asm/arch/hwregs/iop/iop_mpu_macros.h>
|
||||
#include <asm/arch/hwregs/iop/iop_mpu_defs.h>
|
||||
#include <asm/arch/hwregs/iop/iop_spu_defs.h>
|
||||
#include <asm/arch/hwregs/iop/iop_sw_cpu_defs.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/iop/iop_reg_space.h>
|
||||
#include <hwregs/iop/iop_mpu_macros.h>
|
||||
#include <hwregs/iop/iop_mpu_defs.h>
|
||||
#include <hwregs/iop/iop_spu_defs.h>
|
||||
#include <hwregs/iop/iop_sw_cpu_defs.h>
|
||||
|
||||
#define IOP_TIMEOUT 100
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Makefile for Etrax-specific drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
|
@ -0,0 +1,984 @@
|
|||
/*
|
||||
* Artec-3 general port I/O device
|
||||
*
|
||||
* Copyright (c) 2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (initial version)
|
||||
* Ola Knutsson (LED handling)
|
||||
* Johan Adolfsson (read/set directions, write, port G,
|
||||
* port to ETRAX FS.
|
||||
* Ricard Wanderlof (PWM for Artpec-3)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/etraxgpio.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/gio_defs.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/mach/pinmux.h>
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
#include "../i2c.h"
|
||||
|
||||
#define VIRT_I2C_ADDR 0x40
|
||||
#endif
|
||||
|
||||
/* The following gio ports on ARTPEC-3 is available:
|
||||
* pa 32 bits
|
||||
* pb 32 bits
|
||||
* pc 16 bits
|
||||
* each port has a rw_px_dout, r_px_din and rw_px_oe register.
|
||||
*/
|
||||
|
||||
#define GPIO_MAJOR 120 /* experimental MAJOR number */
|
||||
|
||||
#define I2C_INTERRUPT_BITS 0x300 /* i2c0_done and i2c1_done bits */
|
||||
|
||||
#define D(x)
|
||||
|
||||
#if 0
|
||||
static int dp_cnt;
|
||||
#define DP(x) \
|
||||
do { \
|
||||
dp_cnt++; \
|
||||
if (dp_cnt % 1000 == 0) \
|
||||
x; \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
||||
static char gpio_name[] = "etrax gpio";
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
#endif
|
||||
static int gpio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off);
|
||||
static int gpio_open(struct inode *inode, struct file *filp);
|
||||
static int gpio_release(struct inode *inode, struct file *filp);
|
||||
static unsigned int gpio_poll(struct file *filp,
|
||||
struct poll_table_struct *wait);
|
||||
|
||||
/* private data per open() of this driver */
|
||||
|
||||
struct gpio_private {
|
||||
struct gpio_private *next;
|
||||
/* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */
|
||||
unsigned char clk_mask;
|
||||
unsigned char data_mask;
|
||||
unsigned char write_msb;
|
||||
unsigned char pad1;
|
||||
/* These fields are generic */
|
||||
unsigned long highalarm, lowalarm;
|
||||
wait_queue_head_t alarm_wq;
|
||||
int minor;
|
||||
};
|
||||
|
||||
static void gpio_set_alarm(struct gpio_private *priv);
|
||||
static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
|
||||
static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
|
||||
/* linked list of alarms to check for */
|
||||
|
||||
static struct gpio_private *alarmlist;
|
||||
|
||||
static int wanted_interrupts;
|
||||
|
||||
static DEFINE_SPINLOCK(gpio_lock);
|
||||
|
||||
#define NUM_PORTS (GPIO_MINOR_LAST+1)
|
||||
#define GIO_REG_RD_ADDR(reg) \
|
||||
(unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
|
||||
#define GIO_REG_WR_ADDR(reg) \
|
||||
(unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg)
|
||||
static unsigned long led_dummy;
|
||||
static unsigned long port_d_dummy; /* Only input on Artpec-3 */
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static unsigned long port_e_dummy; /* Non existent on Artpec-3 */
|
||||
static unsigned long virtual_dummy;
|
||||
static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;
|
||||
static unsigned short cached_virtual_gpio_read;
|
||||
#endif
|
||||
|
||||
static unsigned long *data_out[NUM_PORTS] = {
|
||||
GIO_REG_WR_ADDR(rw_pa_dout),
|
||||
GIO_REG_WR_ADDR(rw_pb_dout),
|
||||
&led_dummy,
|
||||
GIO_REG_WR_ADDR(rw_pc_dout),
|
||||
&port_d_dummy,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&port_e_dummy,
|
||||
&virtual_dummy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long *data_in[NUM_PORTS] = {
|
||||
GIO_REG_RD_ADDR(r_pa_din),
|
||||
GIO_REG_RD_ADDR(r_pb_din),
|
||||
&led_dummy,
|
||||
GIO_REG_RD_ADDR(r_pc_din),
|
||||
GIO_REG_RD_ADDR(r_pd_din),
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&port_e_dummy,
|
||||
&virtual_dummy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long changeable_dir[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_DIR,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_DIR,
|
||||
0,
|
||||
CONFIG_ETRAX_PC_CHANGEABLE_DIR,
|
||||
0,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
0,
|
||||
CONFIG_ETRAX_PV_CHANGEABLE_DIR,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long changeable_bits[NUM_PORTS] = {
|
||||
CONFIG_ETRAX_PA_CHANGEABLE_BITS,
|
||||
CONFIG_ETRAX_PB_CHANGEABLE_BITS,
|
||||
0,
|
||||
CONFIG_ETRAX_PC_CHANGEABLE_BITS,
|
||||
0,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
0,
|
||||
CONFIG_ETRAX_PV_CHANGEABLE_BITS,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long *dir_oe[NUM_PORTS] = {
|
||||
GIO_REG_WR_ADDR(rw_pa_oe),
|
||||
GIO_REG_WR_ADDR(rw_pb_oe),
|
||||
&led_dummy,
|
||||
GIO_REG_WR_ADDR(rw_pc_oe),
|
||||
&port_d_dummy,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&port_e_dummy,
|
||||
&virtual_rw_pv_oe,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void gpio_set_alarm(struct gpio_private *priv)
|
||||
{
|
||||
int bit;
|
||||
int intr_cfg;
|
||||
int mask;
|
||||
int pins;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg);
|
||||
pins = REG_RD_INT(gio, regi_gio, rw_intr_pins);
|
||||
mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS;
|
||||
|
||||
for (bit = 0; bit < 32; bit++) {
|
||||
int intr = bit % 8;
|
||||
int pin = bit / 8;
|
||||
if (priv->minor < GPIO_MINOR_LEDS)
|
||||
pin += priv->minor * 4;
|
||||
else
|
||||
pin += (priv->minor - 1) * 4;
|
||||
|
||||
if (priv->highalarm & (1<<bit)) {
|
||||
intr_cfg |= (regk_gio_hi << (intr * 3));
|
||||
mask |= 1 << intr;
|
||||
wanted_interrupts = mask & 0xff;
|
||||
pins |= pin << (intr * 4);
|
||||
} else if (priv->lowalarm & (1<<bit)) {
|
||||
intr_cfg |= (regk_gio_lo << (intr * 3));
|
||||
mask |= 1 << intr;
|
||||
wanted_interrupts = mask & 0xff;
|
||||
pins |= pin << (intr * 4);
|
||||
}
|
||||
}
|
||||
|
||||
REG_WR_INT(gio, regi_gio, rw_intr_cfg, intr_cfg);
|
||||
REG_WR_INT(gio, regi_gio, rw_intr_pins, pins);
|
||||
REG_WR_INT(gio, regi_gio, rw_intr_mask, mask);
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long data;
|
||||
unsigned long tmp;
|
||||
|
||||
if (priv->minor >= GPIO_MINOR_PWM0 &&
|
||||
priv->minor <= GPIO_MINOR_LAST_PWM)
|
||||
return 0;
|
||||
|
||||
poll_wait(file, &priv->alarm_wq, wait);
|
||||
if (priv->minor <= GPIO_MINOR_D) {
|
||||
data = readl(data_in[priv->minor]);
|
||||
REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts);
|
||||
tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask);
|
||||
tmp &= I2C_INTERRUPT_BITS;
|
||||
tmp |= wanted_interrupts;
|
||||
REG_WR_INT(gio, regi_gio, rw_intr_mask, tmp);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if ((data & priv->highalarm) || (~data & priv->lowalarm))
|
||||
mask = POLLIN|POLLRDNORM;
|
||||
|
||||
DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));
|
||||
return mask;
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
reg_gio_rw_intr_mask intr_mask;
|
||||
reg_gio_r_masked_intr masked_intr;
|
||||
reg_gio_rw_ack_intr ack_intr;
|
||||
unsigned long flags;
|
||||
unsigned long tmp;
|
||||
unsigned long tmp2;
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
unsigned char enable_gpiov_ack = 0;
|
||||
#endif
|
||||
|
||||
/* Find what PA interrupts are active */
|
||||
masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
|
||||
tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr);
|
||||
|
||||
/* Find those that we have enabled */
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
tmp &= wanted_interrupts;
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Something changed on virtual GPIO. Interrupt is acked by
|
||||
* reading the device.
|
||||
*/
|
||||
if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,
|
||||
sizeof(cached_virtual_gpio_read));
|
||||
enable_gpiov_ack = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Ack them */
|
||||
ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
|
||||
REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
|
||||
|
||||
/* Disable those interrupts.. */
|
||||
intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
|
||||
tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
|
||||
tmp2 &= ~tmp;
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Do not disable interrupt on virtual GPIO. Changes on virtual
|
||||
* pins are only noticed by an interrupt.
|
||||
*/
|
||||
if (enable_gpiov_ack)
|
||||
tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
|
||||
REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
|
||||
|
||||
return IRQ_RETVAL(tmp);
|
||||
}
|
||||
|
||||
static void gpio_write_bit(unsigned long *port, unsigned char data, int bit,
|
||||
unsigned char clk_mask, unsigned char data_mask)
|
||||
{
|
||||
unsigned long shadow = readl(port) & ~clk_mask;
|
||||
writel(shadow, port);
|
||||
if (data & 1 << bit)
|
||||
shadow |= data_mask;
|
||||
else
|
||||
shadow &= ~data_mask;
|
||||
writel(shadow, port);
|
||||
/* For FPGA: min 5.0ns (DCC) before CCLK high */
|
||||
shadow |= clk_mask;
|
||||
writel(shadow, port);
|
||||
}
|
||||
|
||||
static void gpio_write_byte(struct gpio_private *priv, unsigned long *port,
|
||||
unsigned char data)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (priv->write_msb)
|
||||
for (i = 7; i >= 0; i--)
|
||||
gpio_write_bit(port, data, i, priv->clk_mask,
|
||||
priv->data_mask);
|
||||
else
|
||||
for (i = 0; i <= 7; i++)
|
||||
gpio_write_bit(port, data, i, priv->clk_mask,
|
||||
priv->data_mask);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t gpio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *off)
|
||||
{
|
||||
struct gpio_private *priv = file->private_data;
|
||||
unsigned long flags;
|
||||
ssize_t retval = count;
|
||||
/* Only bits 0-7 may be used for write operations but allow all
|
||||
devices except leds... */
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
if (priv->minor == GPIO_MINOR_V)
|
||||
return -EFAULT;
|
||||
#endif
|
||||
if (priv->minor == GPIO_MINOR_LEDS)
|
||||
return -EFAULT;
|
||||
|
||||
if (priv->minor >= GPIO_MINOR_PWM0 &&
|
||||
priv->minor <= GPIO_MINOR_LAST_PWM)
|
||||
return -EFAULT;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
/* It must have been configured using the IO_CFG_WRITE_MODE */
|
||||
/* Perhaps a better error code? */
|
||||
if (priv->clk_mask == 0 || priv->data_mask == 0)
|
||||
return -EPERM;
|
||||
|
||||
D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "
|
||||
"msb: %i\n",
|
||||
count, priv->data_mask, priv->clk_mask, priv->write_msb));
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
while (count--)
|
||||
gpio_write_byte(priv, data_out[priv->minor], *buf++);
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int gpio_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct gpio_private *priv;
|
||||
int p = iminor(inode);
|
||||
|
||||
if (p > GPIO_MINOR_LAST_PWM ||
|
||||
(p > GPIO_MINOR_LAST && p < GPIO_MINOR_PWM0))
|
||||
return -EINVAL;
|
||||
|
||||
priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
priv->minor = p;
|
||||
filp->private_data = priv;
|
||||
|
||||
/* initialize the io/alarm struct, not for PWM ports though */
|
||||
if (p <= GPIO_MINOR_LAST) {
|
||||
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
priv->highalarm = 0;
|
||||
priv->lowalarm = 0;
|
||||
|
||||
init_waitqueue_head(&priv->alarm_wq);
|
||||
|
||||
/* link it into our alarmlist */
|
||||
spin_lock_irq(&gpio_lock);
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
spin_unlock_irq(&gpio_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct gpio_private *p;
|
||||
struct gpio_private *todel;
|
||||
/* local copies while updating them: */
|
||||
unsigned long a_high, a_low;
|
||||
|
||||
/* prepare to free private structure */
|
||||
todel = filp->private_data;
|
||||
|
||||
/* unlink from alarmlist - only for non-PWM ports though */
|
||||
if (todel->minor <= GPIO_MINOR_LAST) {
|
||||
spin_lock_irq(&gpio_lock);
|
||||
p = alarmlist;
|
||||
|
||||
if (p == todel)
|
||||
alarmlist = todel->next;
|
||||
else {
|
||||
while (p->next != todel)
|
||||
p = p->next;
|
||||
p->next = todel->next;
|
||||
}
|
||||
|
||||
/* Check if there are still any alarms set */
|
||||
p = alarmlist;
|
||||
a_high = 0;
|
||||
a_low = 0;
|
||||
while (p) {
|
||||
if (p->minor == GPIO_MINOR_A) {
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
a_high |= p->highalarm;
|
||||
a_low |= p->lowalarm;
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Variable 'a_low' needs to be set here again
|
||||
* to ensure that interrupt for virtual GPIO is handled.
|
||||
*/
|
||||
a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
|
||||
spin_unlock_irq(&gpio_lock);
|
||||
}
|
||||
kfree(todel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Main device API. ioctl's to read/set/clear bits, as well as to
|
||||
* set alarms to wait for using a subsequent select().
|
||||
*/
|
||||
|
||||
inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input
|
||||
*/
|
||||
unsigned long flags;
|
||||
unsigned long dir_shadow;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
dir_shadow = readl(dir_oe[priv->minor]) &
|
||||
~(arg & changeable_dir[priv->minor]);
|
||||
writel(dir_shadow, dir_oe[priv->minor]);
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
if (priv->minor == GPIO_MINOR_C)
|
||||
dir_shadow ^= 0xFFFF; /* Only 16 bits */
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
else if (priv->minor == GPIO_MINOR_V)
|
||||
dir_shadow ^= 0xFFFF; /* Only 16 bits */
|
||||
#endif
|
||||
else
|
||||
dir_shadow ^= 0xFFFFFFFF; /* PA, PB and PD 32 bits */
|
||||
|
||||
return dir_shadow;
|
||||
|
||||
} /* setget_input */
|
||||
|
||||
static inline unsigned long setget_output(struct gpio_private *priv,
|
||||
unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long dir_shadow;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
dir_shadow = readl(dir_oe[priv->minor]) |
|
||||
(arg & changeable_dir[priv->minor]);
|
||||
writel(dir_shadow, dir_oe[priv->minor]);
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return dir_shadow;
|
||||
} /* setget_output */
|
||||
|
||||
static int gpio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long val;
|
||||
unsigned long shadow;
|
||||
struct gpio_private *priv = file->private_data;
|
||||
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
|
||||
return -ENOTTY;
|
||||
|
||||
/* Check for special ioctl handlers first */
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
if (priv->minor == GPIO_MINOR_V)
|
||||
return virtual_gpio_ioctl(file, cmd, arg);
|
||||
#endif
|
||||
|
||||
if (priv->minor == GPIO_MINOR_LEDS)
|
||||
return gpio_leds_ioctl(cmd, arg);
|
||||
|
||||
if (priv->minor >= GPIO_MINOR_PWM0 &&
|
||||
priv->minor <= GPIO_MINOR_LAST_PWM)
|
||||
return gpio_pwm_ioctl(priv, cmd, arg);
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
|
||||
/* Read the port. */
|
||||
return readl(data_in[priv->minor]);
|
||||
case IO_SETBITS:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
/* Set changeable bits with a 1 in arg. */
|
||||
shadow = readl(data_out[priv->minor]) |
|
||||
(arg & changeable_bits[priv->minor]);
|
||||
writel(shadow, data_out[priv->minor]);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_CLRBITS:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
/* Clear changeable bits with a 1 in arg. */
|
||||
shadow = readl(data_out[priv->minor]) &
|
||||
~(arg & changeable_bits[priv->minor]);
|
||||
writel(shadow, data_out[priv->minor]);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
/* Set alarm when bits with 1 in arg go high. */
|
||||
priv->highalarm |= arg;
|
||||
gpio_set_alarm(priv);
|
||||
break;
|
||||
case IO_LOWALARM:
|
||||
/* Set alarm when bits with 1 in arg go low. */
|
||||
priv->lowalarm |= arg;
|
||||
gpio_set_alarm(priv);
|
||||
break;
|
||||
case IO_CLRALARM:
|
||||
/* Clear alarm for bits with 1 in arg. */
|
||||
priv->highalarm &= ~arg;
|
||||
priv->lowalarm &= ~arg;
|
||||
gpio_set_alarm(priv);
|
||||
break;
|
||||
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
|
||||
/* Read direction 0=input 1=output */
|
||||
return readl(dir_oe[priv->minor]);
|
||||
|
||||
case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input
|
||||
*/
|
||||
return setget_input(priv, arg);
|
||||
|
||||
case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
|
||||
/* Set direction 0=unchanged 1=output,
|
||||
* return mask with 1=output
|
||||
*/
|
||||
return setget_output(priv, arg);
|
||||
|
||||
case IO_CFG_WRITE_MODE:
|
||||
{
|
||||
int res = -EPERM;
|
||||
unsigned long dir_shadow, clk_mask, data_mask, write_msb;
|
||||
|
||||
clk_mask = arg & 0xFF;
|
||||
data_mask = (arg >> 8) & 0xFF;
|
||||
write_msb = (arg >> 16) & 0x01;
|
||||
|
||||
/* Check if we're allowed to change the bits and
|
||||
* the direction is correct
|
||||
*/
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
dir_shadow = readl(dir_oe[priv->minor]);
|
||||
if ((clk_mask & changeable_bits[priv->minor]) &&
|
||||
(data_mask & changeable_bits[priv->minor]) &&
|
||||
(clk_mask & dir_shadow) &&
|
||||
(data_mask & dir_shadow)) {
|
||||
priv->clk_mask = clk_mask;
|
||||
priv->data_mask = data_mask;
|
||||
priv->write_msb = write_msb;
|
||||
res = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
return res;
|
||||
}
|
||||
case IO_READ_INBITS:
|
||||
/* *arg is result of reading the input pins */
|
||||
val = readl(data_in[priv->minor]);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
case IO_READ_OUTBITS:
|
||||
/* *arg is result of reading the output shadow */
|
||||
val = *data_out[priv->minor];
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_input(priv, val);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_output(priv, val);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
} /* switch */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned short val;
|
||||
unsigned short shadow;
|
||||
struct gpio_private *priv = file->private_data;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_SETBITS:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
/* Set changeable bits with a 1 in arg. */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
shadow |= ~readl(dir_oe[priv->minor]) |
|
||||
(arg & changeable_bits[priv->minor]);
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
spin_lock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_CLRBITS:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
/* Clear changeable bits with a 1 in arg. */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
shadow |= ~readl(dir_oe[priv->minor]) &
|
||||
~(arg & changeable_bits[priv->minor]);
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
spin_lock_irqrestore(&gpio_lock, flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
/* Set alarm when bits with 1 in arg go high. */
|
||||
priv->highalarm |= arg;
|
||||
break;
|
||||
case IO_LOWALARM:
|
||||
/* Set alarm when bits with 1 in arg go low. */
|
||||
priv->lowalarm |= arg;
|
||||
break;
|
||||
case IO_CLRALARM:
|
||||
/* Clear alarm for bits with 1 in arg. */
|
||||
priv->highalarm &= ~arg;
|
||||
priv->lowalarm &= ~arg;
|
||||
break;
|
||||
case IO_CFG_WRITE_MODE:
|
||||
{
|
||||
unsigned long dir_shadow;
|
||||
dir_shadow = readl(dir_oe[priv->minor]);
|
||||
|
||||
priv->clk_mask = arg & 0xFF;
|
||||
priv->data_mask = (arg >> 8) & 0xFF;
|
||||
priv->write_msb = (arg >> 16) & 0x01;
|
||||
/* Check if we're allowed to change the bits and
|
||||
* the direction is correct
|
||||
*/
|
||||
if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->data_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->clk_mask & dir_shadow) &&
|
||||
(priv->data_mask & dir_shadow))) {
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
return -EPERM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IO_READ_INBITS:
|
||||
/* *arg is result of reading the input pins */
|
||||
val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case IO_READ_OUTBITS:
|
||||
/* *arg is result of reading the output shadow */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));
|
||||
val &= readl(dir_oe[priv->minor]);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
{
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
unsigned short input_mask = ~readl(dir_oe[priv->minor]);
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_input(priv, val);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
if ((input_mask & val) != input_mask) {
|
||||
/* Input pins changed. All ports desired as input
|
||||
* should be set to logic 1.
|
||||
*/
|
||||
unsigned short change = input_mask ^ val;
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow,
|
||||
sizeof(shadow));
|
||||
shadow &= ~change;
|
||||
shadow |= val;
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow,
|
||||
sizeof(shadow));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (void __user *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_output(priv, val);
|
||||
if (copy_to_user((void __user *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
} /* switch */
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */
|
||||
|
||||
static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned char green;
|
||||
unsigned char red;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_LEDACTIVE_SET:
|
||||
green = ((unsigned char) arg) & 1;
|
||||
red = (((unsigned char) arg) >> 1) & 1;
|
||||
CRIS_LED_ACTIVE_SET_G(green);
|
||||
CRIS_LED_ACTIVE_SET_R(red);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
} /* switch */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_pwm_set_mode(unsigned long arg, int pwm_port)
|
||||
{
|
||||
int pinmux_pwm = pinmux_pwm0 + pwm_port;
|
||||
int mode;
|
||||
reg_gio_rw_pwm0_ctrl rw_pwm_ctrl = {
|
||||
.ccd_val = 0,
|
||||
.ccd_override = regk_gio_no,
|
||||
.mode = regk_gio_no
|
||||
};
|
||||
int allocstatus;
|
||||
|
||||
if (get_user(mode, &((struct io_pwm_set_mode *) arg)->mode))
|
||||
return -EFAULT;
|
||||
rw_pwm_ctrl.mode = mode;
|
||||
if (mode != PWM_OFF)
|
||||
allocstatus = crisv32_pinmux_alloc_fixed(pinmux_pwm);
|
||||
else
|
||||
allocstatus = crisv32_pinmux_dealloc_fixed(pinmux_pwm);
|
||||
if (allocstatus)
|
||||
return allocstatus;
|
||||
REG_WRITE(reg_gio_rw_pwm0_ctrl, REG_ADDR(gio, regi_gio, rw_pwm0_ctrl) +
|
||||
12 * pwm_port, rw_pwm_ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_pwm_set_period(unsigned long arg, int pwm_port)
|
||||
{
|
||||
struct io_pwm_set_period periods;
|
||||
reg_gio_rw_pwm0_var rw_pwm_widths;
|
||||
|
||||
if (copy_from_user(&periods, (void __user *)arg, sizeof(periods)))
|
||||
return -EFAULT;
|
||||
if (periods.lo > 8191 || periods.hi > 8191)
|
||||
return -EINVAL;
|
||||
rw_pwm_widths.lo = periods.lo;
|
||||
rw_pwm_widths.hi = periods.hi;
|
||||
REG_WRITE(reg_gio_rw_pwm0_var, REG_ADDR(gio, regi_gio, rw_pwm0_var) +
|
||||
12 * pwm_port, rw_pwm_widths);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_pwm_set_duty(unsigned long arg, int pwm_port)
|
||||
{
|
||||
unsigned int duty;
|
||||
reg_gio_rw_pwm0_data rw_pwm_duty;
|
||||
|
||||
if (get_user(duty, &((struct io_pwm_set_duty *) arg)->duty))
|
||||
return -EFAULT;
|
||||
if (duty > 255)
|
||||
return -EINVAL;
|
||||
rw_pwm_duty.data = duty;
|
||||
REG_WRITE(reg_gio_rw_pwm0_data, REG_ADDR(gio, regi_gio, rw_pwm0_data) +
|
||||
12 * pwm_port, rw_pwm_duty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int pwm_port = priv->minor - GPIO_MINOR_PWM0;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_PWM_SET_MODE:
|
||||
return gpio_pwm_set_mode(arg, pwm_port);
|
||||
case IO_PWM_SET_PERIOD:
|
||||
return gpio_pwm_set_period(arg, pwm_port);
|
||||
case IO_PWM_SET_DUTY:
|
||||
return gpio_pwm_set_duty(arg, pwm_port);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations gpio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.poll = gpio_poll,
|
||||
.ioctl = gpio_ioctl,
|
||||
.write = gpio_write,
|
||||
.open = gpio_open,
|
||||
.release = gpio_release,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static void __init virtual_gpio_init(void)
|
||||
{
|
||||
reg_gio_rw_intr_cfg intr_cfg;
|
||||
reg_gio_rw_intr_mask intr_mask;
|
||||
unsigned short shadow;
|
||||
|
||||
shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */
|
||||
shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
|
||||
/* Set interrupt mask and on what state the interrupt shall trigger.
|
||||
* For virtual gpio the interrupt shall trigger on logic '0'.
|
||||
*/
|
||||
intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
|
||||
intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
|
||||
|
||||
switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {
|
||||
case 0:
|
||||
intr_cfg.pa0 = regk_gio_lo;
|
||||
intr_mask.pa0 = regk_gio_yes;
|
||||
break;
|
||||
case 1:
|
||||
intr_cfg.pa1 = regk_gio_lo;
|
||||
intr_mask.pa1 = regk_gio_yes;
|
||||
break;
|
||||
case 2:
|
||||
intr_cfg.pa2 = regk_gio_lo;
|
||||
intr_mask.pa2 = regk_gio_yes;
|
||||
break;
|
||||
case 3:
|
||||
intr_cfg.pa3 = regk_gio_lo;
|
||||
intr_mask.pa3 = regk_gio_yes;
|
||||
break;
|
||||
case 4:
|
||||
intr_cfg.pa4 = regk_gio_lo;
|
||||
intr_mask.pa4 = regk_gio_yes;
|
||||
break;
|
||||
case 5:
|
||||
intr_cfg.pa5 = regk_gio_lo;
|
||||
intr_mask.pa5 = regk_gio_yes;
|
||||
break;
|
||||
case 6:
|
||||
intr_cfg.pa6 = regk_gio_lo;
|
||||
intr_mask.pa6 = regk_gio_yes;
|
||||
break;
|
||||
case 7:
|
||||
intr_cfg.pa7 = regk_gio_lo;
|
||||
intr_mask.pa7 = regk_gio_yes;
|
||||
break;
|
||||
}
|
||||
|
||||
REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
|
||||
REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* main driver initialization routine, called from mem.c */
|
||||
|
||||
static int __init gpio_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 "
|
||||
"Axis Communications AB\n");
|
||||
|
||||
/* do the formalities */
|
||||
|
||||
res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops);
|
||||
if (res < 0) {
|
||||
printk(KERN_ERR "gpio: couldn't get a major number.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Clear all leds */
|
||||
CRIS_LED_NETWORK_GRP0_SET(0);
|
||||
CRIS_LED_NETWORK_GRP1_SET(0);
|
||||
CRIS_LED_ACTIVE_SET(0);
|
||||
CRIS_LED_DISK_READ(0);
|
||||
CRIS_LED_DISK_WRITE(0);
|
||||
|
||||
int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist);
|
||||
if (res2) {
|
||||
printk(KERN_ERR "err: irq for gpio\n");
|
||||
return res2;
|
||||
}
|
||||
|
||||
/* No IRQs by default. */
|
||||
REG_WR_INT(gio, regi_gio, rw_intr_pins, 0);
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
virtual_gpio_init();
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* this makes sure that gpio_init is called during kernel boot */
|
||||
|
||||
module_init(gpio_init);
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* arch/cris/arch-v32/drivers/nandflash.c
|
||||
*
|
||||
* Copyright (c) 2007
|
||||
*
|
||||
* Derived from drivers/mtd/nand/spia.c
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/arch/memmap.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/pio_defs.h>
|
||||
#include <pinmux.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MANUAL_ALE_CLE_CONTROL 1
|
||||
|
||||
#define regf_ALE a0
|
||||
#define regf_CLE a1
|
||||
#define regf_NCE ce0_n
|
||||
|
||||
#define CLE_BIT 10
|
||||
#define ALE_BIT 11
|
||||
#define CE_BIT 12
|
||||
|
||||
struct mtd_info_wrapper {
|
||||
struct mtd_info info;
|
||||
struct nand_chip chip;
|
||||
};
|
||||
|
||||
/* Bitmask for control pins */
|
||||
#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT))
|
||||
|
||||
static struct mtd_info *crisv32_mtd;
|
||||
/*
|
||||
* hardware specific access to control-lines
|
||||
*/
|
||||
static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_pio_rw_dout dout;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* control bits change */
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
dout = REG_RD(pio, regi_pio, rw_dout);
|
||||
dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1;
|
||||
|
||||
#if !MANUAL_ALE_CLE_CONTROL
|
||||
if (ctrl & NAND_ALE) {
|
||||
/* A0 = ALE high */
|
||||
this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
|
||||
regi_pio, rw_io_access1);
|
||||
} else if (ctrl & NAND_CLE) {
|
||||
/* A1 = CLE high */
|
||||
this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
|
||||
regi_pio, rw_io_access2);
|
||||
} else {
|
||||
/* A1 = CLE and A0 = ALE low */
|
||||
this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
|
||||
regi_pio, rw_io_access0);
|
||||
}
|
||||
#else
|
||||
|
||||
dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0;
|
||||
dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0;
|
||||
#endif
|
||||
REG_WR(pio, regi_pio, rw_dout, dout);
|
||||
}
|
||||
|
||||
/* command to chip */
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* read device ready pin
|
||||
*/
|
||||
static int crisv32_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
reg_pio_r_din din = REG_RD(pio, regi_pio, r_din);
|
||||
return din.rdy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
struct mtd_info *__init crisv32_nand_flash_probe(void)
|
||||
{
|
||||
void __iomem *read_cs;
|
||||
void __iomem *write_cs;
|
||||
|
||||
struct mtd_info_wrapper *wrapper;
|
||||
struct nand_chip *this;
|
||||
int err = 0;
|
||||
|
||||
reg_pio_rw_man_ctrl man_ctrl = {
|
||||
.regf_NCE = regk_pio_yes,
|
||||
#if MANUAL_ALE_CLE_CONTROL
|
||||
.regf_ALE = regk_pio_yes,
|
||||
.regf_CLE = regk_pio_yes
|
||||
#endif
|
||||
};
|
||||
reg_pio_rw_oe oe = {
|
||||
.regf_NCE = regk_pio_yes,
|
||||
#if MANUAL_ALE_CLE_CONTROL
|
||||
.regf_ALE = regk_pio_yes,
|
||||
.regf_CLE = regk_pio_yes
|
||||
#endif
|
||||
};
|
||||
reg_pio_rw_dout dout = { .regf_NCE = 1 };
|
||||
|
||||
/* Allocate pio pins to pio */
|
||||
crisv32_pinmux_alloc_fixed(pinmux_pio);
|
||||
/* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */
|
||||
REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl);
|
||||
REG_WR(pio, regi_pio, rw_dout, dout);
|
||||
REG_WR(pio, regi_pio, rw_oe, oe);
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL);
|
||||
if (!wrapper) {
|
||||
printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD "
|
||||
"device structure.\n");
|
||||
err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio,
|
||||
rw_io_access0);
|
||||
|
||||
/* Get pointer to private data */
|
||||
this = &wrapper->chip;
|
||||
crisv32_mtd = &wrapper->info;
|
||||
|
||||
/* Link the private data with the MTD structure */
|
||||
crisv32_mtd->priv = this;
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
this->IO_ADDR_R = read_cs;
|
||||
this->IO_ADDR_W = write_cs;
|
||||
this->cmd_ctrl = crisv32_hwcontrol;
|
||||
this->dev_ready = crisv32_device_ready;
|
||||
/* 20 us command delay time */
|
||||
this->chip_delay = 20;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
/* Enable the following for a flash based bad block table */
|
||||
/* this->options = NAND_USE_FLASH_BBT; */
|
||||
|
||||
/* Scan to find existance of the device */
|
||||
if (nand_scan(crisv32_mtd, 1)) {
|
||||
err = -ENXIO;
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
return crisv32_mtd;
|
||||
|
||||
out_mtd:
|
||||
kfree(wrapper);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Makefile for Etrax-specific drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o
|
||||
obj-$(CONFIG_ETRAX_GPIO) += gpio.o
|
|
@ -1,68 +1,15 @@
|
|||
/* $Id: gpio.c,v 1.16 2005/06/19 17:06:49 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* ETRAX CRISv32 general port I/O device
|
||||
*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 Axis Communications AB
|
||||
* Copyright (c) 1999-2006 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen (initial version)
|
||||
* Ola Knutsson (LED handling)
|
||||
* Johan Adolfsson (read/set directions, write, port G,
|
||||
* port to ETRAX FS.
|
||||
*
|
||||
* $Log: gpio.c,v $
|
||||
* Revision 1.16 2005/06/19 17:06:49 starvik
|
||||
* Merge of Linux 2.6.12.
|
||||
*
|
||||
* Revision 1.15 2005/05/25 08:22:20 starvik
|
||||
* Changed GPIO port order to fit packages/devices/axis-2.4.
|
||||
*
|
||||
* Revision 1.14 2005/04/24 18:35:08 starvik
|
||||
* Updated with final register headers.
|
||||
*
|
||||
* Revision 1.13 2005/03/15 15:43:00 starvik
|
||||
* dev_id needs to be supplied for shared IRQs.
|
||||
*
|
||||
* Revision 1.12 2005/03/10 17:12:00 starvik
|
||||
* Protect alarm list with spinlock.
|
||||
*
|
||||
* Revision 1.11 2005/01/05 06:08:59 starvik
|
||||
* No need to do local_irq_disable after local_irq_save.
|
||||
*
|
||||
* Revision 1.10 2004/11/19 08:38:31 starvik
|
||||
* Removed old crap.
|
||||
*
|
||||
* Revision 1.9 2004/05/14 07:58:02 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.8 2003/09/11 07:29:50 starvik
|
||||
* Merge of Linux 2.6.0-test5
|
||||
*
|
||||
* Revision 1.7 2003/07/10 13:25:46 starvik
|
||||
* Compiles for 2.5.74
|
||||
* Lindented ethernet.c
|
||||
*
|
||||
* Revision 1.6 2003/07/04 08:27:46 starvik
|
||||
* Merge of Linux 2.5.74
|
||||
*
|
||||
* Revision 1.5 2003/06/10 08:26:37 johana
|
||||
* Etrax -> ETRAX CRISv32
|
||||
*
|
||||
* Revision 1.4 2003/06/05 14:22:48 johana
|
||||
* Initialise some_alarms.
|
||||
*
|
||||
* Revision 1.3 2003/06/05 10:15:46 johana
|
||||
* New INTR_VECT macros.
|
||||
* Enable interrupts in global config.
|
||||
*
|
||||
* Revision 1.2 2003/06/03 15:52:50 johana
|
||||
* Initial CRIS v32 version.
|
||||
*
|
||||
* Revision 1.1 2003/06/03 08:53:15 johana
|
||||
* Copy of os/lx25/arch/cris/arch-v10/drivers/gpio.c version 1.7.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -77,14 +24,20 @@
|
|||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/etraxgpio.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/gio_defs.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/gio_defs.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
#include "../i2c.h"
|
||||
|
||||
#define VIRT_I2C_ADDR 0x40
|
||||
#endif
|
||||
|
||||
/* The following gio ports on ETRAX FS is available:
|
||||
* pa 8 bits, supports interrupts off, hi, low, set, posedge, negedge anyedge
|
||||
* pb 18 bits
|
||||
|
@ -100,7 +53,12 @@
|
|||
|
||||
#if 0
|
||||
static int dp_cnt;
|
||||
#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0)
|
||||
#define DP(x) \
|
||||
do { \
|
||||
dp_cnt++; \
|
||||
if (dp_cnt % 1000 == 0) \
|
||||
x; \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP(x)
|
||||
#endif
|
||||
|
@ -111,13 +69,18 @@ static char gpio_name[] = "etrax gpio";
|
|||
static wait_queue_head_t *gpio_wq;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static int virtual_gpio_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
#endif
|
||||
static int gpio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off);
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t gpio_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t *off);
|
||||
static int gpio_open(struct inode *inode, struct file *filp);
|
||||
static int gpio_release(struct inode *inode, struct file *filp);
|
||||
static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait);
|
||||
static unsigned int gpio_poll(struct file *filp,
|
||||
struct poll_table_struct *wait);
|
||||
|
||||
/* private data per open() of this driver */
|
||||
|
||||
|
@ -136,18 +99,25 @@ struct gpio_private {
|
|||
|
||||
/* linked list of alarms to check for */
|
||||
|
||||
static struct gpio_private *alarmlist = 0;
|
||||
static struct gpio_private *alarmlist;
|
||||
|
||||
static int gpio_some_alarms = 0; /* Set if someone uses alarm */
|
||||
static unsigned long gpio_pa_high_alarms = 0;
|
||||
static unsigned long gpio_pa_low_alarms = 0;
|
||||
static int gpio_some_alarms; /* Set if someone uses alarm */
|
||||
static unsigned long gpio_pa_high_alarms;
|
||||
static unsigned long gpio_pa_low_alarms;
|
||||
|
||||
static DEFINE_SPINLOCK(alarm_lock);
|
||||
|
||||
#define NUM_PORTS (GPIO_MINOR_LAST+1)
|
||||
#define GIO_REG_RD_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
|
||||
#define GIO_REG_WR_ADDR(reg) (volatile unsigned long*) (regi_gio + REG_RD_ADDR_gio_##reg )
|
||||
#define GIO_REG_RD_ADDR(reg) \
|
||||
(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
|
||||
#define GIO_REG_WR_ADDR(reg) \
|
||||
(volatile unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg)
|
||||
unsigned long led_dummy;
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static unsigned long virtual_dummy;
|
||||
static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE;
|
||||
static unsigned short cached_virtual_gpio_read;
|
||||
#endif
|
||||
|
||||
static volatile unsigned long *data_out[NUM_PORTS] = {
|
||||
GIO_REG_WR_ADDR(rw_pa_dout),
|
||||
|
@ -156,6 +126,9 @@ static volatile unsigned long *data_out[NUM_PORTS] = {
|
|||
GIO_REG_WR_ADDR(rw_pc_dout),
|
||||
GIO_REG_WR_ADDR(rw_pd_dout),
|
||||
GIO_REG_WR_ADDR(rw_pe_dout),
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&virtual_dummy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static volatile unsigned long *data_in[NUM_PORTS] = {
|
||||
|
@ -165,6 +138,9 @@ static volatile unsigned long *data_in[NUM_PORTS] = {
|
|||
GIO_REG_RD_ADDR(r_pc_din),
|
||||
GIO_REG_RD_ADDR(r_pd_din),
|
||||
GIO_REG_RD_ADDR(r_pe_din),
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&virtual_dummy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long changeable_dir[NUM_PORTS] = {
|
||||
|
@ -174,6 +150,9 @@ static unsigned long changeable_dir[NUM_PORTS] = {
|
|||
CONFIG_ETRAX_PC_CHANGEABLE_DIR,
|
||||
CONFIG_ETRAX_PD_CHANGEABLE_DIR,
|
||||
CONFIG_ETRAX_PE_CHANGEABLE_DIR,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
CONFIG_ETRAX_PV_CHANGEABLE_DIR,
|
||||
#endif
|
||||
};
|
||||
|
||||
static unsigned long changeable_bits[NUM_PORTS] = {
|
||||
|
@ -183,6 +162,9 @@ static unsigned long changeable_bits[NUM_PORTS] = {
|
|||
CONFIG_ETRAX_PC_CHANGEABLE_BITS,
|
||||
CONFIG_ETRAX_PD_CHANGEABLE_BITS,
|
||||
CONFIG_ETRAX_PE_CHANGEABLE_BITS,
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
CONFIG_ETRAX_PV_CHANGEABLE_BITS,
|
||||
#endif
|
||||
};
|
||||
|
||||
static volatile unsigned long *dir_oe[NUM_PORTS] = {
|
||||
|
@ -192,13 +174,14 @@ static volatile unsigned long *dir_oe[NUM_PORTS] = {
|
|||
GIO_REG_WR_ADDR(rw_pc_oe),
|
||||
GIO_REG_WR_ADDR(rw_pd_oe),
|
||||
GIO_REG_WR_ADDR(rw_pe_oe),
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
&virtual_rw_pv_oe,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
static unsigned int
|
||||
gpio_poll(struct file *file,
|
||||
poll_table *wait)
|
||||
static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
|
@ -210,65 +193,50 @@ gpio_poll(struct file *file,
|
|||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din, REG_RD(gio, regi_gio, r_pa_din));
|
||||
data = REG_TYPE_CONV(unsigned long, reg_gio_r_pa_din,
|
||||
REG_RD(gio, regi_gio, r_pa_din));
|
||||
/* PA has support for interrupt
|
||||
* lets activate high for those low and with highalarm set
|
||||
*/
|
||||
intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
|
||||
|
||||
tmp = ~data & priv->highalarm & 0xFF;
|
||||
if (tmp & (1 << 0)) {
|
||||
if (tmp & (1 << 0))
|
||||
intr_cfg.pa0 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 1)) {
|
||||
if (tmp & (1 << 1))
|
||||
intr_cfg.pa1 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 2)) {
|
||||
if (tmp & (1 << 2))
|
||||
intr_cfg.pa2 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 3)) {
|
||||
if (tmp & (1 << 3))
|
||||
intr_cfg.pa3 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 4)) {
|
||||
if (tmp & (1 << 4))
|
||||
intr_cfg.pa4 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 5)) {
|
||||
if (tmp & (1 << 5))
|
||||
intr_cfg.pa5 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 6)) {
|
||||
if (tmp & (1 << 6))
|
||||
intr_cfg.pa6 = regk_gio_hi;
|
||||
}
|
||||
if (tmp & (1 << 7)) {
|
||||
if (tmp & (1 << 7))
|
||||
intr_cfg.pa7 = regk_gio_hi;
|
||||
}
|
||||
/*
|
||||
* lets activate low for those high and with lowalarm set
|
||||
*/
|
||||
tmp = data & priv->lowalarm & 0xFF;
|
||||
if (tmp & (1 << 0)) {
|
||||
if (tmp & (1 << 0))
|
||||
intr_cfg.pa0 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 1)) {
|
||||
if (tmp & (1 << 1))
|
||||
intr_cfg.pa1 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 2)) {
|
||||
if (tmp & (1 << 2))
|
||||
intr_cfg.pa2 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 3)) {
|
||||
if (tmp & (1 << 3))
|
||||
intr_cfg.pa3 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 4)) {
|
||||
if (tmp & (1 << 4))
|
||||
intr_cfg.pa4 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 5)) {
|
||||
if (tmp & (1 << 5))
|
||||
intr_cfg.pa5 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 6)) {
|
||||
if (tmp & (1 << 6))
|
||||
intr_cfg.pa6 = regk_gio_lo;
|
||||
}
|
||||
if (tmp & (1 << 7)) {
|
||||
if (tmp & (1 << 7))
|
||||
intr_cfg.pa7 = regk_gio_lo;
|
||||
}
|
||||
|
||||
REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
|
||||
local_irq_restore(flags);
|
||||
|
@ -277,50 +245,65 @@ gpio_poll(struct file *file,
|
|||
else
|
||||
return 0;
|
||||
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
if ((data & priv->highalarm) || (~data & priv->lowalarm))
|
||||
mask = POLLIN|POLLRDNORM;
|
||||
}
|
||||
|
||||
DP(printk("gpio_poll ready: mask 0x%08X\n", mask));
|
||||
DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask));
|
||||
return mask;
|
||||
}
|
||||
|
||||
int etrax_gpio_wake_up_check(void)
|
||||
{
|
||||
struct gpio_private *priv = alarmlist;
|
||||
struct gpio_private *priv;
|
||||
unsigned long data = 0;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
spin_lock_irqsave(&alarm_lock, flags);
|
||||
priv = alarmlist;
|
||||
while (priv) {
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
if (priv->minor == GPIO_MINOR_V)
|
||||
data = (unsigned long)cached_virtual_gpio_read;
|
||||
else {
|
||||
data = *data_in[priv->minor];
|
||||
if (priv->minor == GPIO_MINOR_A)
|
||||
priv->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
}
|
||||
#else
|
||||
data = *data_in[priv->minor];
|
||||
#endif
|
||||
if ((data & priv->highalarm) ||
|
||||
(~data & priv->lowalarm)) {
|
||||
DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor));
|
||||
DP(printk(KERN_DEBUG
|
||||
"etrax_gpio_wake_up_check %i\n", priv->minor));
|
||||
wake_up_interruptible(&priv->alarm_wq);
|
||||
ret = 1;
|
||||
ret = 1;
|
||||
}
|
||||
priv = priv->next;
|
||||
}
|
||||
return ret;
|
||||
spin_unlock_irqrestore(&alarm_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
gpio_poll_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
if (gpio_some_alarms) {
|
||||
if (gpio_some_alarms)
|
||||
return IRQ_RETVAL(etrax_gpio_wake_up_check());
|
||||
}
|
||||
return IRQ_NONE;
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
gpio_pa_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
reg_gio_rw_intr_mask intr_mask;
|
||||
reg_gio_r_masked_intr masked_intr;
|
||||
reg_gio_rw_ack_intr ack_intr;
|
||||
unsigned long tmp;
|
||||
unsigned long tmp2;
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
unsigned char enable_gpiov_ack = 0;
|
||||
#endif
|
||||
|
||||
/* Find what PA interrupts are active */
|
||||
masked_intr = REG_RD(gio, regi_gio, r_masked_intr);
|
||||
|
@ -331,6 +314,17 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
tmp &= (gpio_pa_high_alarms | gpio_pa_low_alarms);
|
||||
spin_unlock(&alarm_lock);
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Something changed on virtual GPIO. Interrupt is acked by
|
||||
* reading the device.
|
||||
*/
|
||||
if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) {
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read,
|
||||
sizeof(cached_virtual_gpio_read));
|
||||
enable_gpiov_ack = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Ack them */
|
||||
ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp);
|
||||
REG_WR(gio, regi_gio, rw_ack_intr, ack_intr);
|
||||
|
@ -339,18 +333,24 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
|
||||
tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask);
|
||||
tmp2 &= ~tmp;
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Do not disable interrupt on virtual GPIO. Changes on virtual
|
||||
* pins are only noticed by an interrupt.
|
||||
*/
|
||||
if (enable_gpiov_ack)
|
||||
tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2);
|
||||
REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
|
||||
|
||||
if (gpio_some_alarms) {
|
||||
if (gpio_some_alarms)
|
||||
return IRQ_RETVAL(etrax_gpio_wake_up_check());
|
||||
}
|
||||
return IRQ_NONE;
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
||||
loff_t *off)
|
||||
static ssize_t gpio_write(struct file *file, const char *buf, size_t count,
|
||||
loff_t *off)
|
||||
{
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
unsigned char data, clk_mask, data_mask, write_msb;
|
||||
|
@ -360,29 +360,31 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
|||
ssize_t retval = count;
|
||||
/* Only bits 0-7 may be used for write operations but allow all
|
||||
devices except leds... */
|
||||
if (priv->minor == GPIO_MINOR_LEDS) {
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
if (priv->minor == GPIO_MINOR_V)
|
||||
return -EFAULT;
|
||||
#endif
|
||||
if (priv->minor == GPIO_MINOR_LEDS)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count)) {
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
}
|
||||
clk_mask = priv->clk_mask;
|
||||
data_mask = priv->data_mask;
|
||||
/* It must have been configured using the IO_CFG_WRITE_MODE */
|
||||
/* Perhaps a better error code? */
|
||||
if (clk_mask == 0 || data_mask == 0) {
|
||||
if (clk_mask == 0 || data_mask == 0)
|
||||
return -EPERM;
|
||||
}
|
||||
write_msb = priv->write_msb;
|
||||
D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb));
|
||||
D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X "
|
||||
"msb: %i\n", count, data_mask, clk_mask, write_msb));
|
||||
port = data_out[priv->minor];
|
||||
|
||||
while (count--) {
|
||||
int i;
|
||||
data = *buf++;
|
||||
if (priv->write_msb) {
|
||||
for (i = 7; i >= 0;i--) {
|
||||
for (i = 7; i >= 0; i--) {
|
||||
local_irq_save(flags);
|
||||
shadow = *port;
|
||||
*port = shadow &= ~clk_mask;
|
||||
|
@ -395,7 +397,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count,
|
|||
local_irq_restore(flags);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i <= 7;i++) {
|
||||
for (i = 0; i <= 7; i++) {
|
||||
local_irq_save(flags);
|
||||
shadow = *port;
|
||||
*port = shadow &= ~clk_mask;
|
||||
|
@ -423,18 +425,16 @@ gpio_open(struct inode *inode, struct file *filp)
|
|||
if (p > GPIO_MINOR_LAST)
|
||||
return -EINVAL;
|
||||
|
||||
priv = kmalloc(sizeof(struct gpio_private),
|
||||
GFP_KERNEL);
|
||||
priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL);
|
||||
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
priv->minor = p;
|
||||
|
||||
/* initialize the io/alarm struct and link it into our alarmlist */
|
||||
/* initialize the io/alarm struct */
|
||||
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
priv->highalarm = 0;
|
||||
|
@ -443,20 +443,30 @@ gpio_open(struct inode *inode, struct file *filp)
|
|||
|
||||
filp->private_data = (void *)priv;
|
||||
|
||||
/* link it into our alarmlist */
|
||||
spin_lock_irq(&alarm_lock);
|
||||
priv->next = alarmlist;
|
||||
alarmlist = priv;
|
||||
spin_unlock_irq(&alarm_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gpio_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct gpio_private *p = alarmlist;
|
||||
struct gpio_private *todel = (struct gpio_private *)filp->private_data;
|
||||
struct gpio_private *p;
|
||||
struct gpio_private *todel;
|
||||
/* local copies while updating them: */
|
||||
unsigned long a_high, a_low;
|
||||
unsigned long some_alarms;
|
||||
|
||||
/* unlink from alarmlist and free the private structure */
|
||||
|
||||
spin_lock_irq(&alarm_lock);
|
||||
p = alarmlist;
|
||||
todel = (struct gpio_private *)filp->private_data;
|
||||
|
||||
if (p == todel) {
|
||||
alarmlist = todel->next;
|
||||
} else {
|
||||
|
@ -468,26 +478,35 @@ gpio_release(struct inode *inode, struct file *filp)
|
|||
kfree(todel);
|
||||
/* Check if there are still any alarms set */
|
||||
p = alarmlist;
|
||||
some_alarms = 0;
|
||||
some_alarms = 0;
|
||||
a_high = 0;
|
||||
a_low = 0;
|
||||
while (p) {
|
||||
if (p->minor == GPIO_MINOR_A) {
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
a_high |= p->highalarm;
|
||||
a_low |= p->lowalarm;
|
||||
}
|
||||
|
||||
if (p->highalarm | p->lowalarm) {
|
||||
if (p->highalarm | p->lowalarm)
|
||||
some_alarms = 1;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
spin_lock(&alarm_lock);
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
/* Variables 'some_alarms' and 'a_low' needs to be set here again
|
||||
* to ensure that interrupt for virtual GPIO is handled.
|
||||
*/
|
||||
some_alarms = 1;
|
||||
a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
#endif
|
||||
|
||||
gpio_some_alarms = some_alarms;
|
||||
gpio_pa_high_alarms = a_high;
|
||||
gpio_pa_low_alarms = a_low;
|
||||
spin_unlock(&alarm_lock);
|
||||
spin_unlock_irq(&alarm_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -496,7 +515,7 @@ gpio_release(struct inode *inode, struct file *filp)
|
|||
* set alarms to wait for using a subsequent select().
|
||||
*/
|
||||
|
||||
unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
|
||||
inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
/* Set direction 0=unchanged 1=input,
|
||||
* return mask with 1=input
|
||||
|
@ -512,13 +531,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
|
|||
|
||||
if (priv->minor == GPIO_MINOR_A)
|
||||
dir_shadow ^= 0xFF; /* Only 8 bits */
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
else if (priv->minor == GPIO_MINOR_V)
|
||||
dir_shadow ^= 0xFFFF; /* Only 16 bits */
|
||||
#endif
|
||||
else
|
||||
dir_shadow ^= 0x3FFFF; /* Only 18 bits */
|
||||
return dir_shadow;
|
||||
|
||||
} /* setget_input */
|
||||
|
||||
unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
|
||||
inline unsigned long setget_output(struct gpio_private *priv, unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long dir_shadow;
|
||||
|
@ -542,20 +565,22 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
unsigned long val;
|
||||
unsigned long shadow;
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) {
|
||||
if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
if (priv->minor == GPIO_MINOR_V)
|
||||
return virtual_gpio_ioctl(file, cmd, arg);
|
||||
#endif
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
|
||||
// read the port
|
||||
/* Read the port. */
|
||||
return *data_in[priv->minor];
|
||||
break;
|
||||
case IO_SETBITS:
|
||||
local_irq_save(flags);
|
||||
if (arg & 0x04)
|
||||
printk("GPIO SET 2\n");
|
||||
// set changeable bits with a 1 in arg
|
||||
/* Set changeable bits with a 1 in arg. */
|
||||
shadow = *data_out[priv->minor];
|
||||
shadow |= (arg & changeable_bits[priv->minor]);
|
||||
*data_out[priv->minor] = shadow;
|
||||
|
@ -563,46 +588,42 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
break;
|
||||
case IO_CLRBITS:
|
||||
local_irq_save(flags);
|
||||
if (arg & 0x04)
|
||||
printk("GPIO CLR 2\n");
|
||||
// clear changeable bits with a 1 in arg
|
||||
/* Clear changeable bits with a 1 in arg. */
|
||||
shadow = *data_out[priv->minor];
|
||||
shadow &= ~(arg & changeable_bits[priv->minor]);
|
||||
*data_out[priv->minor] = shadow;
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
// set alarm when bits with 1 in arg go high
|
||||
/* Set alarm when bits with 1 in arg go high. */
|
||||
priv->highalarm |= arg;
|
||||
spin_lock(&alarm_lock);
|
||||
spin_lock_irqsave(&alarm_lock, flags);
|
||||
gpio_some_alarms = 1;
|
||||
if (priv->minor == GPIO_MINOR_A) {
|
||||
if (priv->minor == GPIO_MINOR_A)
|
||||
gpio_pa_high_alarms |= arg;
|
||||
}
|
||||
spin_unlock(&alarm_lock);
|
||||
spin_unlock_irqrestore(&alarm_lock, flags);
|
||||
break;
|
||||
case IO_LOWALARM:
|
||||
// set alarm when bits with 1 in arg go low
|
||||
/* Set alarm when bits with 1 in arg go low. */
|
||||
priv->lowalarm |= arg;
|
||||
spin_lock(&alarm_lock);
|
||||
spin_lock_irqsave(&alarm_lock, flags);
|
||||
gpio_some_alarms = 1;
|
||||
if (priv->minor == GPIO_MINOR_A) {
|
||||
if (priv->minor == GPIO_MINOR_A)
|
||||
gpio_pa_low_alarms |= arg;
|
||||
}
|
||||
spin_unlock(&alarm_lock);
|
||||
spin_unlock_irqrestore(&alarm_lock, flags);
|
||||
break;
|
||||
case IO_CLRALARM:
|
||||
// clear alarm for bits with 1 in arg
|
||||
/* Clear alarm for bits with 1 in arg. */
|
||||
priv->highalarm &= ~arg;
|
||||
priv->lowalarm &= ~arg;
|
||||
spin_lock(&alarm_lock);
|
||||
spin_lock_irqsave(&alarm_lock, flags);
|
||||
if (priv->minor == GPIO_MINOR_A) {
|
||||
if (gpio_pa_high_alarms & arg ||
|
||||
gpio_pa_low_alarms & arg) {
|
||||
gpio_pa_low_alarms & arg)
|
||||
/* Must update the gpio_pa_*alarms masks */
|
||||
}
|
||||
;
|
||||
}
|
||||
spin_unlock(&alarm_lock);
|
||||
spin_unlock_irqrestore(&alarm_lock, flags);
|
||||
break;
|
||||
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
|
||||
/* Read direction 0=input 1=output */
|
||||
|
@ -633,8 +654,7 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->data_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->clk_mask & dir_shadow) &&
|
||||
(priv->data_mask & dir_shadow)))
|
||||
{
|
||||
(priv->data_mask & dir_shadow))) {
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
return -EPERM;
|
||||
|
@ -644,34 +664,34 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
case IO_READ_INBITS:
|
||||
/* *arg is result of reading the input pins */
|
||||
val = *data_in[priv->minor];
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
break;
|
||||
case IO_READ_OUTBITS:
|
||||
/* *arg is result of reading the output shadow */
|
||||
val = *data_out[priv->minor];
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
|
||||
if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_input(priv, val);
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (unsigned long*)arg, sizeof(val)))
|
||||
if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_output(priv, val);
|
||||
if (copy_to_user((unsigned long*)arg, &val, sizeof(val)))
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
|
@ -684,6 +704,133 @@ gpio_ioctl(struct inode *inode, struct file *file,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static int
|
||||
virtual_gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned short val;
|
||||
unsigned short shadow;
|
||||
struct gpio_private *priv = (struct gpio_private *)file->private_data;
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case IO_SETBITS:
|
||||
local_irq_save(flags);
|
||||
/* Set changeable bits with a 1 in arg. */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
shadow |= ~*dir_oe[priv->minor];
|
||||
shadow |= (arg & changeable_bits[priv->minor]);
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case IO_CLRBITS:
|
||||
local_irq_save(flags);
|
||||
/* Clear changeable bits with a 1 in arg. */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
shadow |= ~*dir_oe[priv->minor];
|
||||
shadow &= ~(arg & changeable_bits[priv->minor]);
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
case IO_HIGHALARM:
|
||||
/* Set alarm when bits with 1 in arg go high. */
|
||||
priv->highalarm |= arg;
|
||||
spin_lock(&alarm_lock);
|
||||
gpio_some_alarms = 1;
|
||||
spin_unlock(&alarm_lock);
|
||||
break;
|
||||
case IO_LOWALARM:
|
||||
/* Set alarm when bits with 1 in arg go low. */
|
||||
priv->lowalarm |= arg;
|
||||
spin_lock(&alarm_lock);
|
||||
gpio_some_alarms = 1;
|
||||
spin_unlock(&alarm_lock);
|
||||
break;
|
||||
case IO_CLRALARM:
|
||||
/* Clear alarm for bits with 1 in arg. */
|
||||
priv->highalarm &= ~arg;
|
||||
priv->lowalarm &= ~arg;
|
||||
spin_lock(&alarm_lock);
|
||||
spin_unlock(&alarm_lock);
|
||||
break;
|
||||
case IO_CFG_WRITE_MODE:
|
||||
{
|
||||
unsigned long dir_shadow;
|
||||
dir_shadow = *dir_oe[priv->minor];
|
||||
|
||||
priv->clk_mask = arg & 0xFF;
|
||||
priv->data_mask = (arg >> 8) & 0xFF;
|
||||
priv->write_msb = (arg >> 16) & 0x01;
|
||||
/* Check if we're allowed to change the bits and
|
||||
* the direction is correct
|
||||
*/
|
||||
if (!((priv->clk_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->data_mask & changeable_bits[priv->minor]) &&
|
||||
(priv->clk_mask & dir_shadow) &&
|
||||
(priv->data_mask & dir_shadow))) {
|
||||
priv->clk_mask = 0;
|
||||
priv->data_mask = 0;
|
||||
return -EPERM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IO_READ_INBITS:
|
||||
/* *arg is result of reading the input pins */
|
||||
val = cached_virtual_gpio_read;
|
||||
val &= ~*dir_oe[priv->minor];
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
break;
|
||||
case IO_READ_OUTBITS:
|
||||
/* *arg is result of reading the output shadow */
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val));
|
||||
val &= *dir_oe[priv->minor];
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case IO_SETGET_INPUT:
|
||||
{
|
||||
/* bits set in *arg is set to input,
|
||||
* *arg updated with current input pins.
|
||||
*/
|
||||
unsigned short input_mask = ~*dir_oe[priv->minor];
|
||||
if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_input(priv, val);
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
if ((input_mask & val) != input_mask) {
|
||||
/* Input pins changed. All ports desired as input
|
||||
* should be set to logic 1.
|
||||
*/
|
||||
unsigned short change = input_mask ^ val;
|
||||
i2c_read(VIRT_I2C_ADDR, (void *)&shadow,
|
||||
sizeof(shadow));
|
||||
shadow &= ~change;
|
||||
shadow |= val;
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow,
|
||||
sizeof(shadow));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IO_SETGET_OUTPUT:
|
||||
/* bits set in *arg is set to output,
|
||||
* *arg updated with current output pins.
|
||||
*/
|
||||
if (copy_from_user(&val, (unsigned long *)arg, sizeof(val)))
|
||||
return -EFAULT;
|
||||
val = setget_output(priv, val);
|
||||
if (copy_to_user((unsigned long *)arg, &val, sizeof(val)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
} /* switch */
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_ETRAX_VIRTUAL_GPIO */
|
||||
|
||||
static int
|
||||
gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
@ -694,8 +841,8 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
|||
case IO_LEDACTIVE_SET:
|
||||
green = ((unsigned char) arg) & 1;
|
||||
red = (((unsigned char) arg) >> 1) & 1;
|
||||
LED_ACTIVE_SET_G(green);
|
||||
LED_ACTIVE_SET_R(red);
|
||||
CRIS_LED_ACTIVE_SET_G(green);
|
||||
CRIS_LED_ACTIVE_SET_R(red);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -705,7 +852,7 @@ gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations gpio_fops = {
|
||||
struct file_operations gpio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.poll = gpio_poll,
|
||||
.ioctl = gpio_ioctl,
|
||||
|
@ -714,6 +861,66 @@ const struct file_operations gpio_fops = {
|
|||
.release = gpio_release,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
static void
|
||||
virtual_gpio_init(void)
|
||||
{
|
||||
reg_gio_rw_intr_cfg intr_cfg;
|
||||
reg_gio_rw_intr_mask intr_mask;
|
||||
unsigned short shadow;
|
||||
|
||||
shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */
|
||||
shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT;
|
||||
i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow));
|
||||
|
||||
/* Set interrupt mask and on what state the interrupt shall trigger.
|
||||
* For virtual gpio the interrupt shall trigger on logic '0'.
|
||||
*/
|
||||
intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg);
|
||||
intr_mask = REG_RD(gio, regi_gio, rw_intr_mask);
|
||||
|
||||
switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) {
|
||||
case 0:
|
||||
intr_cfg.pa0 = regk_gio_lo;
|
||||
intr_mask.pa0 = regk_gio_yes;
|
||||
break;
|
||||
case 1:
|
||||
intr_cfg.pa1 = regk_gio_lo;
|
||||
intr_mask.pa1 = regk_gio_yes;
|
||||
break;
|
||||
case 2:
|
||||
intr_cfg.pa2 = regk_gio_lo;
|
||||
intr_mask.pa2 = regk_gio_yes;
|
||||
break;
|
||||
case 3:
|
||||
intr_cfg.pa3 = regk_gio_lo;
|
||||
intr_mask.pa3 = regk_gio_yes;
|
||||
break;
|
||||
case 4:
|
||||
intr_cfg.pa4 = regk_gio_lo;
|
||||
intr_mask.pa4 = regk_gio_yes;
|
||||
break;
|
||||
case 5:
|
||||
intr_cfg.pa5 = regk_gio_lo;
|
||||
intr_mask.pa5 = regk_gio_yes;
|
||||
break;
|
||||
case 6:
|
||||
intr_cfg.pa6 = regk_gio_lo;
|
||||
intr_mask.pa6 = regk_gio_yes;
|
||||
break;
|
||||
case 7:
|
||||
intr_cfg.pa7 = regk_gio_lo;
|
||||
intr_mask.pa7 = regk_gio_yes;
|
||||
break;
|
||||
}
|
||||
|
||||
REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg);
|
||||
REG_WR(gio, regi_gio, rw_intr_mask, intr_mask);
|
||||
|
||||
gpio_pa_low_alarms |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN);
|
||||
gpio_some_alarms = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* main driver initialization routine, called from mem.c */
|
||||
|
||||
|
@ -721,7 +928,6 @@ static __init int
|
|||
gpio_init(void)
|
||||
{
|
||||
int res;
|
||||
reg_intr_vect_rw_mask intr_mask;
|
||||
|
||||
/* do the formalities */
|
||||
|
||||
|
@ -732,30 +938,30 @@ gpio_init(void)
|
|||
}
|
||||
|
||||
/* Clear all leds */
|
||||
LED_NETWORK_SET(0);
|
||||
LED_ACTIVE_SET(0);
|
||||
LED_DISK_READ(0);
|
||||
LED_DISK_WRITE(0);
|
||||
CRIS_LED_NETWORK_GRP0_SET(0);
|
||||
CRIS_LED_NETWORK_GRP1_SET(0);
|
||||
CRIS_LED_ACTIVE_SET(0);
|
||||
CRIS_LED_DISK_READ(0);
|
||||
CRIS_LED_DISK_WRITE(0);
|
||||
|
||||
printk("ETRAX FS GPIO driver v2.5, (c) 2003-2005 Axis Communications AB\n");
|
||||
printk(KERN_INFO "ETRAX FS GPIO driver v2.5, (c) 2003-2007 "
|
||||
"Axis Communications AB\n");
|
||||
/* We call etrax_gpio_wake_up_check() from timer interrupt and
|
||||
* from cpu_idle() in kernel/process.c
|
||||
* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
|
||||
* in some tests.
|
||||
*/
|
||||
if (request_irq(TIMER_INTR_VECT, gpio_poll_timer_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED,"gpio poll", &alarmlist)) {
|
||||
printk("err: timer0 irq for gpio\n");
|
||||
}
|
||||
if (request_irq(GEN_IO_INTR_VECT, gpio_pa_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED,"gpio PA", &alarmlist)) {
|
||||
printk("err: PA irq for gpio\n");
|
||||
}
|
||||
/* enable the gio and timer irq in global config */
|
||||
intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
|
||||
intr_mask.timer = 1;
|
||||
intr_mask.gen_io = 1;
|
||||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist))
|
||||
printk(KERN_ERR "timer0 irq for gpio\n");
|
||||
|
||||
if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist))
|
||||
printk(KERN_ERR "PA irq for gpio\n");
|
||||
|
||||
#ifdef CONFIG_ETRAX_VIRTUAL_GPIO
|
||||
virtual_gpio_init();
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
|
@ -4,9 +4,7 @@
|
|||
* Copyright (c) 2004
|
||||
*
|
||||
* Derived from drivers/mtd/nand/spia.c
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
*
|
||||
* $Id: nandflash.c,v 1.3 2005/06/01 10:57:12 starvik Exp $
|
||||
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
|
@ -21,10 +19,10 @@
|
|||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <asm/arch/memmap.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/gio_defs.h>
|
||||
#include <asm/arch/hwregs/bif_core_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/gio_defs.h>
|
||||
#include <hwregs/bif_core_defs.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define CE_BIT 4
|
||||
|
@ -32,44 +30,65 @@
|
|||
#define ALE_BIT 6
|
||||
#define BY_BIT 7
|
||||
|
||||
static struct mtd_info *crisv32_mtd = NULL;
|
||||
struct mtd_info_wrapper {
|
||||
struct mtd_info info;
|
||||
struct nand_chip chip;
|
||||
};
|
||||
|
||||
/* Bitmask for control pins */
|
||||
#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT))
|
||||
|
||||
/* Bitmask for mtd nand control bits */
|
||||
#define CTRL_BITMASK (NAND_NCE | NAND_CLE | NAND_ALE)
|
||||
|
||||
|
||||
static struct mtd_info *crisv32_mtd;
|
||||
/*
|
||||
* hardware specific access to control-lines
|
||||
*/
|
||||
static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||
*/
|
||||
static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
|
||||
unsigned int ctrl)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_gio_rw_pa_dout dout = REG_RD(gio, regi_gio, rw_pa_dout);
|
||||
reg_gio_rw_pa_dout dout;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
local_irq_save(flags);
|
||||
switch(cmd){
|
||||
case NAND_CTL_SETCLE:
|
||||
dout.data |= (1<<CLE_BIT);
|
||||
break;
|
||||
case NAND_CTL_CLRCLE:
|
||||
dout.data &= ~(1<<CLE_BIT);
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
dout.data |= (1<<ALE_BIT);
|
||||
break;
|
||||
case NAND_CTL_CLRALE:
|
||||
dout.data &= ~(1<<ALE_BIT);
|
||||
break;
|
||||
case NAND_CTL_SETNCE:
|
||||
dout.data |= (1<<CE_BIT);
|
||||
break;
|
||||
case NAND_CTL_CLRNCE:
|
||||
dout.data &= ~(1<<CE_BIT);
|
||||
break;
|
||||
|
||||
/* control bits change */
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
dout = REG_RD(gio, regi_gio, rw_pa_dout);
|
||||
dout.data &= ~PIN_BITMASK;
|
||||
|
||||
#if (CE_BIT == 4 && NAND_NCE == 1 && \
|
||||
CLE_BIT == 5 && NAND_CLE == 2 && \
|
||||
ALE_BIT == 6 && NAND_ALE == 4)
|
||||
/* Pins in same order as control bits, but shifted.
|
||||
* Optimize for this case; works for 2.6.18 */
|
||||
dout.data |= ((ctrl & CTRL_BITMASK) ^ NAND_NCE) << CE_BIT;
|
||||
#else
|
||||
/* the slow way */
|
||||
if (!(ctrl & NAND_NCE))
|
||||
dout.data |= (1 << CE_BIT);
|
||||
if (ctrl & NAND_CLE)
|
||||
dout.data |= (1 << CLE_BIT);
|
||||
if (ctrl & NAND_ALE)
|
||||
dout.data |= (1 << ALE_BIT);
|
||||
#endif
|
||||
REG_WR(gio, regi_gio, rw_pa_dout, dout);
|
||||
}
|
||||
REG_WR(gio, regi_gio, rw_pa_dout, dout);
|
||||
|
||||
/* command to chip */
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
writeb(cmd, this->IO_ADDR_W);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* read device ready pin
|
||||
*/
|
||||
int crisv32_device_ready(struct mtd_info *mtd)
|
||||
static int crisv32_device_ready(struct mtd_info *mtd)
|
||||
{
|
||||
reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din);
|
||||
return ((din.data & (1 << BY_BIT)) >> BY_BIT);
|
||||
|
@ -78,21 +97,23 @@ int crisv32_device_ready(struct mtd_info *mtd)
|
|||
/*
|
||||
* Main initialization routine
|
||||
*/
|
||||
struct mtd_info* __init crisv32_nand_flash_probe (void)
|
||||
struct mtd_info *__init crisv32_nand_flash_probe(void)
|
||||
{
|
||||
void __iomem *read_cs;
|
||||
void __iomem *write_cs;
|
||||
|
||||
reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, rw_grp3_cfg);
|
||||
reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core,
|
||||
rw_grp3_cfg);
|
||||
reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe);
|
||||
struct mtd_info_wrapper *wrapper;
|
||||
struct nand_chip *this;
|
||||
int err = 0;
|
||||
|
||||
/* Allocate memory for MTD device structure and private data */
|
||||
crisv32_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
|
||||
GFP_KERNEL);
|
||||
if (!crisv32_mtd) {
|
||||
printk ("Unable to allocate CRISv32 NAND MTD device structure.\n");
|
||||
wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL);
|
||||
if (!wrapper) {
|
||||
printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD "
|
||||
"device structure.\n");
|
||||
err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -101,45 +122,42 @@ struct mtd_info* __init crisv32_nand_flash_probe (void)
|
|||
write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192);
|
||||
|
||||
if (!read_cs || !write_cs) {
|
||||
printk("CRISv32 NAND ioremap failed\n");
|
||||
printk(KERN_ERR "CRISv32 NAND ioremap failed\n");
|
||||
err = -EIO;
|
||||
goto out_mtd;
|
||||
}
|
||||
|
||||
/* Get pointer to private data */
|
||||
this = (struct nand_chip *) (&crisv32_mtd[1]);
|
||||
this = &wrapper->chip;
|
||||
crisv32_mtd = &wrapper->info;
|
||||
|
||||
pa_oe.oe |= 1 << CE_BIT;
|
||||
pa_oe.oe |= 1 << ALE_BIT;
|
||||
pa_oe.oe |= 1 << CLE_BIT;
|
||||
pa_oe.oe &= ~ (1 << BY_BIT);
|
||||
pa_oe.oe &= ~(1 << BY_BIT);
|
||||
REG_WR(gio, regi_gio, rw_pa_oe, pa_oe);
|
||||
|
||||
bif_cfg.gated_csp0 = regk_bif_core_rd;
|
||||
bif_cfg.gated_csp1 = regk_bif_core_wr;
|
||||
REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg);
|
||||
|
||||
/* Initialize structures */
|
||||
memset((char *) crisv32_mtd, 0, sizeof(struct mtd_info));
|
||||
memset((char *) this, 0, sizeof(struct nand_chip));
|
||||
|
||||
/* Link the private data with the MTD structure */
|
||||
crisv32_mtd->priv = this;
|
||||
|
||||
/* Set address of NAND IO lines */
|
||||
this->IO_ADDR_R = read_cs;
|
||||
this->IO_ADDR_W = write_cs;
|
||||
this->hwcontrol = crisv32_hwcontrol;
|
||||
this->cmd_ctrl = crisv32_hwcontrol;
|
||||
this->dev_ready = crisv32_device_ready;
|
||||
/* 20 us command delay time */
|
||||
this->chip_delay = 20;
|
||||
this->eccmode = NAND_ECC_SOFT;
|
||||
this->ecc.mode = NAND_ECC_SOFT;
|
||||
|
||||
/* Enable the following for a flash based bad block table */
|
||||
this->options = NAND_USE_FLASH_BBT;
|
||||
/* this->options = NAND_USE_FLASH_BBT; */
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
if (nand_scan (crisv32_mtd, 1)) {
|
||||
/* Scan to find existance of the device */
|
||||
if (nand_scan(crisv32_mtd, 1)) {
|
||||
err = -ENXIO;
|
||||
goto out_ior;
|
||||
}
|
||||
|
@ -150,7 +168,7 @@ out_ior:
|
|||
iounmap((void *)read_cs);
|
||||
iounmap((void *)write_cs);
|
||||
out_mtd:
|
||||
kfree (crisv32_mtd);
|
||||
return NULL;
|
||||
kfree(wrapper);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
* 400 kbits/s. The built-in word address register is incremented
|
||||
* automatically after each written or read byte.
|
||||
*
|
||||
* Copyright (c) 2002-2003, Axis Communications AB
|
||||
* Copyright (c) 2002-2007, Axis Communications AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Author: Tobias Anderberg <tobiasa@axis.com>.
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include <linux/ioctl.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
@ -37,24 +38,27 @@
|
|||
#define PCF8563_MAJOR 121 /* Local major number. */
|
||||
#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */
|
||||
#define PCF8563_NAME "PCF8563"
|
||||
#define DRIVER_VERSION "$Revision: 1.1 $"
|
||||
#define DRIVER_VERSION "$Revision: 1.17 $"
|
||||
|
||||
/* Two simple wrapper macros, saves a few keystrokes. */
|
||||
#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x)
|
||||
#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y)
|
||||
|
||||
static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
|
||||
|
||||
static const unsigned char days_in_month[] =
|
||||
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
|
||||
int pcf8563_open(struct inode *, struct file *);
|
||||
int pcf8563_release(struct inode *, struct file *);
|
||||
|
||||
/* Cache VL bit value read at driver init since writing the RTC_SECOND
|
||||
* register clears the VL status.
|
||||
*/
|
||||
static int voltage_low;
|
||||
|
||||
static const struct file_operations pcf8563_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.ioctl = pcf8563_ioctl,
|
||||
.open = pcf8563_open,
|
||||
.release = pcf8563_release,
|
||||
.ioctl = pcf8563_ioctl
|
||||
};
|
||||
|
||||
unsigned char
|
||||
|
@ -62,7 +66,7 @@ pcf8563_readreg(int reg)
|
|||
{
|
||||
unsigned char res = rtc_read(reg);
|
||||
|
||||
/* The PCF8563 does not return 0 for unimplemented bits */
|
||||
/* The PCF8563 does not return 0 for unimplemented bits. */
|
||||
switch (reg) {
|
||||
case RTC_SECONDS:
|
||||
case RTC_MINUTES:
|
||||
|
@ -95,11 +99,6 @@ pcf8563_readreg(int reg)
|
|||
void
|
||||
pcf8563_writereg(int reg, unsigned char val)
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_RTC_READONLY
|
||||
if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR))
|
||||
return;
|
||||
#endif
|
||||
|
||||
rtc_write(reg, val);
|
||||
}
|
||||
|
||||
|
@ -114,11 +113,13 @@ get_rtc_time(struct rtc_time *tm)
|
|||
tm->tm_mon = rtc_read(RTC_MONTH);
|
||||
tm->tm_year = rtc_read(RTC_YEAR);
|
||||
|
||||
if (tm->tm_sec & 0x80)
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
|
||||
if (tm->tm_sec & 0x80) {
|
||||
printk(KERN_ERR "%s: RTC Voltage Low - reliable date/time "
|
||||
"information is no longer guaranteed!\n", PCF8563_NAME);
|
||||
}
|
||||
|
||||
tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0);
|
||||
tm->tm_year = BCD_TO_BIN(tm->tm_year) +
|
||||
((tm->tm_mon & 0x80) ? 100 : 0);
|
||||
tm->tm_sec &= 0x7F;
|
||||
tm->tm_min &= 0x7F;
|
||||
tm->tm_hour &= 0x3F;
|
||||
|
@ -137,8 +138,19 @@ get_rtc_time(struct rtc_time *tm)
|
|||
int __init
|
||||
pcf8563_init(void)
|
||||
{
|
||||
static int res;
|
||||
static int first = 1;
|
||||
|
||||
if (!first)
|
||||
return res;
|
||||
first = 0;
|
||||
|
||||
/* Initiate the i2c protocol. */
|
||||
i2c_init();
|
||||
res = i2c_init();
|
||||
if (res < 0) {
|
||||
printk(KERN_CRIT "pcf8563_init: Failed to init i2c.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* First of all we need to reset the chip. This is done by
|
||||
|
@ -170,24 +182,20 @@ pcf8563_init(void)
|
|||
if (rtc_write(RTC_WEEKDAY_ALARM, 0x80) < 0)
|
||||
goto err;
|
||||
|
||||
if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
|
||||
printk(KERN_INFO "%s: Unable to get major number %d for RTC device.\n",
|
||||
PCF8563_NAME, PCF8563_MAJOR);
|
||||
return -1;
|
||||
/* Check for low voltage, and warn about it. */
|
||||
if (rtc_read(RTC_SECONDS) & 0x80) {
|
||||
voltage_low = 1;
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
|
||||
"date/time information is no longer guaranteed!\n",
|
||||
PCF8563_NAME);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
|
||||
|
||||
/* Check for low voltage, and warn about it.. */
|
||||
if (rtc_read(RTC_SECONDS) & 0x80)
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
|
||||
"information is no longer guaranteed!\n", PCF8563_NAME);
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
|
||||
err:
|
||||
printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME);
|
||||
return -1;
|
||||
res = -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
void __exit
|
||||
|
@ -200,8 +208,8 @@ pcf8563_exit(void)
|
|||
* ioctl calls for this driver. Why return -ENOTTY upon error? Because
|
||||
* POSIX says so!
|
||||
*/
|
||||
int
|
||||
pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
/* Some sanity checks. */
|
||||
if (_IOC_TYPE(cmd) != RTC_MAGIC)
|
||||
|
@ -211,125 +219,147 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
|
|||
return -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_RD_TIME:
|
||||
{
|
||||
struct rtc_time tm;
|
||||
case RTC_RD_TIME:
|
||||
{
|
||||
struct rtc_time tm;
|
||||
|
||||
memset(&tm, 0, sizeof (struct rtc_time));
|
||||
get_rtc_time(&tm);
|
||||
mutex_lock(&rtc_lock);
|
||||
memset(&tm, 0, sizeof tm);
|
||||
get_rtc_time(&tm);
|
||||
|
||||
if (copy_to_user((struct rtc_time *) arg, &tm, sizeof tm)) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (copy_to_user((struct rtc_time *) arg, &tm,
|
||||
sizeof tm)) {
|
||||
spin_unlock(&rtc_lock);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
case RTC_SET_TIME:
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_RTC_READONLY
|
||||
mutex_unlock(&rtc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_SET_TIME:
|
||||
{
|
||||
int leap;
|
||||
int year;
|
||||
int century;
|
||||
struct rtc_time tm;
|
||||
|
||||
memset(&tm, 0, sizeof tm);
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EPERM;
|
||||
#else
|
||||
int leap;
|
||||
int year;
|
||||
int century;
|
||||
struct rtc_time tm;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EPERM;
|
||||
if (copy_from_user(&tm, (struct rtc_time *) arg,
|
||||
sizeof tm))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof tm))
|
||||
return -EFAULT;
|
||||
/* Convert from struct tm to struct rtc_time. */
|
||||
tm.tm_year += 1900;
|
||||
tm.tm_mon += 1;
|
||||
|
||||
/* Convert from struct tm to struct rtc_time. */
|
||||
tm.tm_year += 1900;
|
||||
tm.tm_mon += 1;
|
||||
/*
|
||||
* Check if tm.tm_year is a leap year. A year is a leap
|
||||
* year if it is divisible by 4 but not 100, except
|
||||
* that years divisible by 400 _are_ leap years.
|
||||
*/
|
||||
year = tm.tm_year;
|
||||
leap = (tm.tm_mon == 2) &&
|
||||
((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
|
||||
|
||||
/*
|
||||
* Check if tm.tm_year is a leap year. A year is a leap
|
||||
* year if it is divisible by 4 but not 100, except
|
||||
* that years divisible by 400 _are_ leap years.
|
||||
*/
|
||||
year = tm.tm_year;
|
||||
leap = (tm.tm_mon == 2) && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
|
||||
/* Perform some sanity checks. */
|
||||
if ((tm.tm_year < 1970) ||
|
||||
(tm.tm_mon > 12) ||
|
||||
(tm.tm_mday == 0) ||
|
||||
(tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
|
||||
(tm.tm_wday >= 7) ||
|
||||
(tm.tm_hour >= 24) ||
|
||||
(tm.tm_min >= 60) ||
|
||||
(tm.tm_sec >= 60))
|
||||
return -EINVAL;
|
||||
|
||||
/* Perform some sanity checks. */
|
||||
if ((tm.tm_year < 1970) ||
|
||||
(tm.tm_mon > 12) ||
|
||||
(tm.tm_mday == 0) ||
|
||||
(tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
|
||||
(tm.tm_wday >= 7) ||
|
||||
(tm.tm_hour >= 24) ||
|
||||
(tm.tm_min >= 60) ||
|
||||
(tm.tm_sec >= 60))
|
||||
return -EINVAL;
|
||||
century = (tm.tm_year >= 2000) ? 0x80 : 0;
|
||||
tm.tm_year = tm.tm_year % 100;
|
||||
|
||||
century = (tm.tm_year >= 2000) ? 0x80 : 0;
|
||||
tm.tm_year = tm.tm_year % 100;
|
||||
BIN_TO_BCD(tm.tm_year);
|
||||
BIN_TO_BCD(tm.tm_mon);
|
||||
BIN_TO_BCD(tm.tm_mday);
|
||||
BIN_TO_BCD(tm.tm_hour);
|
||||
BIN_TO_BCD(tm.tm_min);
|
||||
BIN_TO_BCD(tm.tm_sec);
|
||||
tm.tm_mon |= century;
|
||||
|
||||
BIN_TO_BCD(tm.tm_year);
|
||||
BIN_TO_BCD(tm.tm_mday);
|
||||
BIN_TO_BCD(tm.tm_hour);
|
||||
BIN_TO_BCD(tm.tm_min);
|
||||
BIN_TO_BCD(tm.tm_sec);
|
||||
tm.tm_mon |= century;
|
||||
mutex_lock(&rtc_lock);
|
||||
|
||||
rtc_write(RTC_YEAR, tm.tm_year);
|
||||
rtc_write(RTC_MONTH, tm.tm_mon);
|
||||
rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
|
||||
rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
|
||||
rtc_write(RTC_HOURS, tm.tm_hour);
|
||||
rtc_write(RTC_MINUTES, tm.tm_min);
|
||||
rtc_write(RTC_SECONDS, tm.tm_sec);
|
||||
rtc_write(RTC_YEAR, tm.tm_year);
|
||||
rtc_write(RTC_MONTH, tm.tm_mon);
|
||||
rtc_write(RTC_WEEKDAY, tm.tm_wday); /* Not coded in BCD. */
|
||||
rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
|
||||
rtc_write(RTC_HOURS, tm.tm_hour);
|
||||
rtc_write(RTC_MINUTES, tm.tm_min);
|
||||
rtc_write(RTC_SECONDS, tm.tm_sec);
|
||||
|
||||
return 0;
|
||||
#endif /* !CONFIG_ETRAX_RTC_READONLY */
|
||||
}
|
||||
mutex_unlock(&rtc_lock);
|
||||
|
||||
case RTC_VLOW_RD:
|
||||
{
|
||||
int vl_bit = 0;
|
||||
return 0;
|
||||
}
|
||||
case RTC_VL_READ:
|
||||
if (voltage_low)
|
||||
printk(KERN_ERR "%s: RTC Voltage Low - "
|
||||
"reliable date/time information is no "
|
||||
"longer guaranteed!\n", PCF8563_NAME);
|
||||
|
||||
if (rtc_read(RTC_SECONDS) & 0x80) {
|
||||
vl_bit = 1;
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
|
||||
"date/time information is no longer guaranteed!\n",
|
||||
PCF8563_NAME);
|
||||
}
|
||||
if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
|
||||
return -EFAULT;
|
||||
if (copy_to_user((int *) arg, &voltage_low, sizeof(int)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case RTC_VL_CLR:
|
||||
{
|
||||
/* Clear the VL bit in the seconds register in case
|
||||
* the time has not been set already (which would
|
||||
* have cleared it). This does not really matter
|
||||
* because of the cached voltage_low value but do it
|
||||
* anyway for consistency. */
|
||||
|
||||
case RTC_VLOW_SET:
|
||||
{
|
||||
/* Clear the VL bit in the seconds register */
|
||||
int ret = rtc_read(RTC_SECONDS);
|
||||
int ret = rtc_read(RTC_SECONDS);
|
||||
|
||||
rtc_write(RTC_SECONDS, (ret & 0x7F));
|
||||
rtc_write(RTC_SECONDS, (ret & 0x7F));
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* Clear the cached value. */
|
||||
voltage_low = 0;
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pcf8563_open(struct inode *inode, struct file *filp)
|
||||
static int __init pcf8563_register(void)
|
||||
{
|
||||
if (pcf8563_init() < 0) {
|
||||
printk(KERN_INFO "%s: Unable to initialize Real-Time Clock "
|
||||
"Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
|
||||
printk(KERN_INFO "%s: Unable to get major numer %d for RTC "
|
||||
"device.\n", PCF8563_NAME, PCF8563_MAJOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME,
|
||||
DRIVER_VERSION);
|
||||
|
||||
/* Check for low voltage, and warn about it. */
|
||||
if (voltage_low) {
|
||||
printk(KERN_WARNING "%s: RTC Voltage Low - reliable date/time "
|
||||
"information is no longer guaranteed!\n", PCF8563_NAME);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
pcf8563_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(pcf8563_init);
|
||||
module_init(pcf8563_register);
|
||||
module_exit(pcf8563_exit);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,3 @@
|
|||
# $Id: Makefile,v 1.11 2004/12/17 10:16:13 starvik Exp $
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
@ -6,9 +5,9 @@
|
|||
extra-y := head.o
|
||||
|
||||
|
||||
obj-y := entry.o traps.o irq.o debugport.o dma.o pinmux.o \
|
||||
obj-y := entry.o traps.o irq.o debugport.o \
|
||||
process.o ptrace.o setup.o signal.o traps.o time.o \
|
||||
arbiter.o io.o
|
||||
cache.o cacheflush.o
|
||||
|
||||
obj-$(CONFIG_ETRAXFS_SIM) += vcs_hook.o
|
||||
|
||||
|
|
|
@ -1,296 +0,0 @@
|
|||
/*
|
||||
* Memory arbiter functions. Allocates bandwidth through the
|
||||
* arbiter and sets up arbiter breakpoints.
|
||||
*
|
||||
* The algorithm first assigns slots to the clients that has specified
|
||||
* bandwidth (e.g. ethernet) and then the remaining slots are divided
|
||||
* on all the active clients.
|
||||
*
|
||||
* Copyright (c) 2004, 2005 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/marb_defs.h>
|
||||
#include <asm/arch/arbiter.h>
|
||||
#include <asm/arch/hwregs/intr_vect.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct crisv32_watch_entry
|
||||
{
|
||||
unsigned long instance;
|
||||
watch_callback* cb;
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
int used;
|
||||
};
|
||||
|
||||
#define NUMBER_OF_BP 4
|
||||
#define NBR_OF_CLIENTS 14
|
||||
#define NBR_OF_SLOTS 64
|
||||
#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */
|
||||
#define INTMEM_BANDWIDTH 400000000
|
||||
#define NBR_OF_REGIONS 2
|
||||
|
||||
static struct crisv32_watch_entry watches[NUMBER_OF_BP] =
|
||||
{
|
||||
{regi_marb_bp0},
|
||||
{regi_marb_bp1},
|
||||
{regi_marb_bp2},
|
||||
{regi_marb_bp3}
|
||||
};
|
||||
|
||||
static int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
static int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
|
||||
|
||||
DEFINE_SPINLOCK(arbiter_lock);
|
||||
|
||||
static irqreturn_t
|
||||
crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs);
|
||||
|
||||
static void crisv32_arbiter_config(int region)
|
||||
{
|
||||
int slot;
|
||||
int client;
|
||||
int interval = 0;
|
||||
int val[NBR_OF_SLOTS];
|
||||
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++)
|
||||
val[slot] = NBR_OF_CLIENTS + 1;
|
||||
|
||||
for (client = 0; client < NBR_OF_CLIENTS; client++)
|
||||
{
|
||||
int pos;
|
||||
if (!requested_slots[region][client])
|
||||
continue;
|
||||
interval = NBR_OF_SLOTS / requested_slots[region][client];
|
||||
pos = 0;
|
||||
while (pos < NBR_OF_SLOTS)
|
||||
{
|
||||
if (val[pos] != NBR_OF_CLIENTS + 1)
|
||||
pos++;
|
||||
else
|
||||
{
|
||||
val[pos] = client;
|
||||
pos += interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client = 0;
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++)
|
||||
{
|
||||
if (val[slot] == NBR_OF_CLIENTS + 1)
|
||||
{
|
||||
int first = client;
|
||||
while(!active_clients[region][client]) {
|
||||
client = (client + 1) % NBR_OF_CLIENTS;
|
||||
if (client == first)
|
||||
break;
|
||||
}
|
||||
val[slot] = client;
|
||||
client = (client + 1) % NBR_OF_CLIENTS;
|
||||
}
|
||||
if (region == EXT_REGION)
|
||||
REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, val[slot]);
|
||||
else if (region == INT_REGION)
|
||||
REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, val[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
extern char _stext, _etext;
|
||||
|
||||
static void crisv32_arbiter_init(void)
|
||||
{
|
||||
static int initialized = 0;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
/* CPU caches are active. */
|
||||
active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
|
||||
crisv32_arbiter_config(EXT_REGION);
|
||||
crisv32_arbiter_config(INT_REGION);
|
||||
|
||||
if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
|
||||
"arbiter", NULL))
|
||||
printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
|
||||
|
||||
#ifndef CONFIG_ETRAX_KGDB
|
||||
/* Global watch for writes to kernel text segment. */
|
||||
crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
|
||||
arbiter_all_clients, arbiter_all_write, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
int crisv32_arbiter_allocate_bandwidth(int client, int region,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
int i;
|
||||
int total_assigned = 0;
|
||||
int total_clients = 0;
|
||||
int req;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
for (i = 0; i < NBR_OF_CLIENTS; i++)
|
||||
{
|
||||
total_assigned += requested_slots[region][i];
|
||||
total_clients += active_clients[region][i];
|
||||
}
|
||||
req = NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
|
||||
|
||||
if (total_assigned + total_clients + req + 1 > NBR_OF_SLOTS)
|
||||
return -ENOMEM;
|
||||
|
||||
active_clients[region][client] = 1;
|
||||
requested_slots[region][client] = req;
|
||||
crisv32_arbiter_config(region);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crisv32_arbiter_watch(unsigned long start, unsigned long size,
|
||||
unsigned long clients, unsigned long accesses,
|
||||
watch_callback* cb)
|
||||
{
|
||||
int i;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
if (start > 0x80000000) {
|
||||
printk("Arbiter: %lX doesn't look like a physical address", start);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
for (i = 0; i < NUMBER_OF_BP; i++) {
|
||||
if (!watches[i].used) {
|
||||
reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
|
||||
|
||||
watches[i].used = 1;
|
||||
watches[i].start = start;
|
||||
watches[i].end = start + size;
|
||||
watches[i].cb = cb;
|
||||
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, watches[i].start);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, watches[i].end);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_op, accesses);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_clients, clients);
|
||||
|
||||
if (i == 0)
|
||||
intr_mask.bp0 = regk_marb_yes;
|
||||
else if (i == 1)
|
||||
intr_mask.bp1 = regk_marb_yes;
|
||||
else if (i == 2)
|
||||
intr_mask.bp2 = regk_marb_yes;
|
||||
else if (i == 3)
|
||||
intr_mask.bp3 = regk_marb_yes;
|
||||
|
||||
REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
|
||||
spin_unlock(&arbiter_lock);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
spin_unlock(&arbiter_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int crisv32_arbiter_unwatch(int id)
|
||||
{
|
||||
reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
|
||||
spin_unlock(&arbiter_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
|
||||
|
||||
if (id == 0)
|
||||
intr_mask.bp0 = regk_marb_no;
|
||||
else if (id == 1)
|
||||
intr_mask.bp2 = regk_marb_no;
|
||||
else if (id == 2)
|
||||
intr_mask.bp2 = regk_marb_no;
|
||||
else if (id == 3)
|
||||
intr_mask.bp3 = regk_marb_no;
|
||||
|
||||
REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
|
||||
|
||||
spin_unlock(&arbiter_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void show_registers(struct pt_regs *regs);
|
||||
|
||||
static irqreturn_t
|
||||
crisv32_arbiter_irq(int irq, void* dev_id, struct pt_regs* regs)
|
||||
{
|
||||
reg_marb_r_masked_intr masked_intr = REG_RD(marb, regi_marb, r_masked_intr);
|
||||
reg_marb_bp_r_brk_clients r_clients;
|
||||
reg_marb_bp_r_brk_addr r_addr;
|
||||
reg_marb_bp_r_brk_op r_op;
|
||||
reg_marb_bp_r_brk_first_client r_first;
|
||||
reg_marb_bp_r_brk_size r_size;
|
||||
reg_marb_bp_rw_ack ack = {0};
|
||||
reg_marb_rw_ack_intr ack_intr = {.bp0=1,.bp1=1,.bp2=1,.bp3=1};
|
||||
struct crisv32_watch_entry* watch;
|
||||
|
||||
if (masked_intr.bp0) {
|
||||
watch = &watches[0];
|
||||
ack_intr.bp0 = regk_marb_yes;
|
||||
} else if (masked_intr.bp1) {
|
||||
watch = &watches[1];
|
||||
ack_intr.bp1 = regk_marb_yes;
|
||||
} else if (masked_intr.bp2) {
|
||||
watch = &watches[2];
|
||||
ack_intr.bp2 = regk_marb_yes;
|
||||
} else if (masked_intr.bp3) {
|
||||
watch = &watches[3];
|
||||
ack_intr.bp3 = regk_marb_yes;
|
||||
} else {
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Retrieve all useful information and print it. */
|
||||
r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
|
||||
r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
|
||||
r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
|
||||
r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
|
||||
r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
|
||||
|
||||
printk("Arbiter IRQ\n");
|
||||
printk("Clients %X addr %X op %X first %X size %X\n",
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
|
||||
|
||||
REG_WR(marb_bp, watch->instance, rw_ack, ack);
|
||||
REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
|
||||
|
||||
printk("IRQ occured at %lX\n", regs->erp);
|
||||
|
||||
if (watch->cb)
|
||||
watch->cb();
|
||||
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
#include <linux/irq.h>
|
||||
#include <asm/arch/dma.h>
|
||||
#include <asm/arch/intmem.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
#include <asm/arch/mach/pinmux.h>
|
||||
#include <asm/arch/io.h>
|
||||
|
||||
/* Functions for allocating DMA channels */
|
||||
EXPORT_SYMBOL(crisv32_request_dma);
|
||||
|
@ -16,7 +17,11 @@ EXPORT_SYMBOL(crisv32_intmem_virt_to_phys);
|
|||
|
||||
/* Functions for handling pinmux */
|
||||
EXPORT_SYMBOL(crisv32_pinmux_alloc);
|
||||
EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed);
|
||||
EXPORT_SYMBOL(crisv32_pinmux_dealloc);
|
||||
EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed);
|
||||
EXPORT_SYMBOL(crisv32_io_get_name);
|
||||
EXPORT_SYMBOL(crisv32_io_get);
|
||||
|
||||
/* Functions masking/unmasking interrupts */
|
||||
EXPORT_SYMBOL(mask_irq);
|
||||
|
|
|
@ -4,17 +4,12 @@
|
|||
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hwregs/ser_defs.h>
|
||||
#include <asm/arch/hwregs/dma_defs.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/ser_defs.h>
|
||||
#include <hwregs/dma_defs.h>
|
||||
#include <asm/arch/mach/pinmux.h>
|
||||
|
||||
struct dbg_port
|
||||
{
|
||||
|
@ -59,45 +54,50 @@ struct dbg_port ports[] =
|
|||
115200,
|
||||
'N',
|
||||
8
|
||||
}
|
||||
},
|
||||
#if CONFIG_ETRAX_SERIAL_PORTS == 5
|
||||
{
|
||||
4,
|
||||
regi_ser4,
|
||||
0,
|
||||
115200,
|
||||
'N',
|
||||
8
|
||||
},
|
||||
#endif
|
||||
};
|
||||
static struct dbg_port *port =
|
||||
#if defined(CONFIG_ETRAX_DEBUG_PORT0)
|
||||
&ports[0];
|
||||
&ports[0];
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
|
||||
&ports[1];
|
||||
&ports[1];
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
|
||||
&ports[2];
|
||||
&ports[2];
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
|
||||
&ports[3];
|
||||
&ports[3];
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT4)
|
||||
&ports[4];
|
||||
#else
|
||||
NULL;
|
||||
NULL;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_KGDB
|
||||
static struct dbg_port *kgdb_port =
|
||||
#if defined(CONFIG_ETRAX_KGDB_PORT0)
|
||||
&ports[0];
|
||||
&ports[0];
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT1)
|
||||
&ports[1];
|
||||
&ports[1];
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT2)
|
||||
&ports[2];
|
||||
&ports[2];
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT3)
|
||||
&ports[3];
|
||||
&ports[3];
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT4)
|
||||
&ports[4];
|
||||
#else
|
||||
NULL;
|
||||
NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
extern void print_str( const char *str );
|
||||
static char buffer[1024];
|
||||
static char msg[] = "Debug: ";
|
||||
static int buffer_pos = sizeof(msg) - 1;
|
||||
#endif
|
||||
|
||||
extern struct tty_driver *serial_driver;
|
||||
|
||||
static void
|
||||
start_port(struct dbg_port* p)
|
||||
{
|
||||
|
@ -114,6 +114,10 @@ start_port(struct dbg_port* p)
|
|||
crisv32_pinmux_alloc_fixed(pinmux_ser2);
|
||||
else if (p->nbr == 3)
|
||||
crisv32_pinmux_alloc_fixed(pinmux_ser3);
|
||||
#if CONFIG_ETRAX_SERIAL_PORTS == 5
|
||||
else if (p->nbr == 4)
|
||||
crisv32_pinmux_alloc_fixed(pinmux_ser4);
|
||||
#endif
|
||||
|
||||
/* Set up serial port registers */
|
||||
reg_ser_rw_tr_ctrl tr_ctrl = {0};
|
||||
|
@ -156,124 +160,21 @@ start_port(struct dbg_port* p)
|
|||
REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl);
|
||||
}
|
||||
|
||||
/* No debug */
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
|
||||
|
||||
static void
|
||||
console_write(struct console *co, const char *buf, unsigned int len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Target debug */
|
||||
#elif !defined(CONFIG_ETRAXFS_SIM)
|
||||
|
||||
static void
|
||||
console_write_direct(struct console *co, const char *buf, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
reg_ser_r_stat_din stat;
|
||||
reg_ser_rw_tr_dma_en tr_dma_en, old;
|
||||
|
||||
/* Switch to manual mode */
|
||||
tr_dma_en = old = REG_RD (ser, port->instance, rw_tr_dma_en);
|
||||
if (tr_dma_en.en == regk_ser_yes) {
|
||||
tr_dma_en.en = regk_ser_no;
|
||||
REG_WR(ser, port->instance, rw_tr_dma_en, tr_dma_en);
|
||||
}
|
||||
|
||||
/* Send data */
|
||||
for (i = 0; i < len; i++) {
|
||||
/* LF -> CRLF */
|
||||
if (buf[i] == '\n') {
|
||||
do {
|
||||
stat = REG_RD (ser, port->instance, r_stat_din);
|
||||
} while (!stat.tr_rdy);
|
||||
REG_WR_INT (ser, port->instance, rw_dout, '\r');
|
||||
}
|
||||
/* Wait until transmitter is ready and send.*/
|
||||
do {
|
||||
stat = REG_RD (ser, port->instance, r_stat_din);
|
||||
} while (!stat.tr_rdy);
|
||||
REG_WR_INT (ser, port->instance, rw_dout, buf[i]);
|
||||
}
|
||||
|
||||
/* Restore mode */
|
||||
if (tr_dma_en.en != old.en)
|
||||
REG_WR(ser, port->instance, rw_tr_dma_en, old);
|
||||
}
|
||||
|
||||
static void
|
||||
console_write(struct console *co, const char *buf, unsigned int len)
|
||||
{
|
||||
if (!port)
|
||||
return;
|
||||
console_write_direct(co, buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#else
|
||||
|
||||
/* VCS debug */
|
||||
|
||||
static void
|
||||
console_write(struct console *co, const char *buf, unsigned int len)
|
||||
{
|
||||
char* pos;
|
||||
pos = memchr(buf, '\n', len);
|
||||
if (pos) {
|
||||
int l = ++pos - buf;
|
||||
memcpy(buffer + buffer_pos, buf, l);
|
||||
memcpy(buffer, msg, sizeof(msg) - 1);
|
||||
buffer[buffer_pos + l] = '\0';
|
||||
print_str(buffer);
|
||||
buffer_pos = sizeof(msg) - 1;
|
||||
if (pos - buf != len) {
|
||||
memcpy(buffer + buffer_pos, pos, len - l);
|
||||
buffer_pos += len - l;
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer + buffer_pos, buf, len);
|
||||
buffer_pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int raw_printk(const char *fmt, ...)
|
||||
{
|
||||
static char buf[1024];
|
||||
int printed_len;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printed_len = vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
console_write(NULL, buf, strlen(buf));
|
||||
return printed_len;
|
||||
}
|
||||
|
||||
void
|
||||
stupid_debug(char* buf)
|
||||
{
|
||||
console_write(NULL, buf, strlen(buf));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ETRAX_KGDB
|
||||
/* Use polling to get a single character from the kernel debug port */
|
||||
int
|
||||
getDebugChar(void)
|
||||
{
|
||||
reg_ser_rs_status_data stat;
|
||||
reg_ser_rs_stat_din stat;
|
||||
reg_ser_rw_ack_intr ack_intr = { 0 };
|
||||
|
||||
do {
|
||||
stat = REG_RD(ser, kgdb_instance, rs_status_data);
|
||||
} while (!stat.data_avail);
|
||||
stat = REG_RD(ser, kgdb_port->instance, rs_stat_din);
|
||||
} while (!stat.dav);
|
||||
|
||||
/* Ack the data_avail interrupt. */
|
||||
ack_intr.data_avail = 1;
|
||||
REG_WR(ser, kgdb_instance, rw_ack_intr, ack_intr);
|
||||
ack_intr.dav = 1;
|
||||
REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr);
|
||||
|
||||
return stat.data;
|
||||
}
|
||||
|
@ -282,173 +183,18 @@ getDebugChar(void)
|
|||
void
|
||||
putDebugChar(int val)
|
||||
{
|
||||
reg_ser_r_status_data stat;
|
||||
reg_ser_r_stat_din stat;
|
||||
do {
|
||||
stat = REG_RD (ser, kgdb_instance, r_status_data);
|
||||
} while (!stat.tr_ready);
|
||||
REG_WR (ser, kgdb_instance, rw_data_out, REG_TYPE_CONV(reg_ser_rw_data_out, int, val));
|
||||
stat = REG_RD(ser, kgdb_port->instance, r_stat_din);
|
||||
} while (!stat.tr_rdy);
|
||||
REG_WR_INT(ser, kgdb_port->instance, rw_dout, val);
|
||||
}
|
||||
#endif /* CONFIG_ETRAX_KGDB */
|
||||
|
||||
static int __init
|
||||
console_setup(struct console *co, char *options)
|
||||
{
|
||||
char* s;
|
||||
|
||||
if (options) {
|
||||
port = &ports[co->index];
|
||||
port->baudrate = 115200;
|
||||
port->parity = 'N';
|
||||
port->bits = 8;
|
||||
port->baudrate = simple_strtoul(options, NULL, 10);
|
||||
s = options;
|
||||
while(*s >= '0' && *s <= '9')
|
||||
s++;
|
||||
if (*s) port->parity = *s++;
|
||||
if (*s) port->bits = *s++ - '0';
|
||||
port->started = 0;
|
||||
start_port(port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a dummy serial device that throws away anything written to it.
|
||||
* This is used when no debug output is wanted.
|
||||
*/
|
||||
static struct tty_driver dummy_driver;
|
||||
|
||||
static int dummy_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dummy_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
}
|
||||
|
||||
static int dummy_write(struct tty_struct * tty,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static int
|
||||
dummy_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
|
||||
void __init
|
||||
init_dummy_console(void)
|
||||
{
|
||||
memset(&dummy_driver, 0, sizeof(struct tty_driver));
|
||||
dummy_driver.driver_name = "serial";
|
||||
dummy_driver.name = "ttyS";
|
||||
dummy_driver.major = TTY_MAJOR;
|
||||
dummy_driver.minor_start = 68;
|
||||
dummy_driver.num = 1; /* etrax100 has 4 serial ports */
|
||||
dummy_driver.type = TTY_DRIVER_TYPE_SERIAL;
|
||||
dummy_driver.subtype = SERIAL_TYPE_NORMAL;
|
||||
dummy_driver.init_termios = tty_std_termios;
|
||||
dummy_driver.init_termios.c_cflag =
|
||||
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
|
||||
dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
|
||||
dummy_driver.open = dummy_open;
|
||||
dummy_driver.close = dummy_close;
|
||||
dummy_driver.write = dummy_write;
|
||||
dummy_driver.write_room = dummy_write_room;
|
||||
if (tty_register_driver(&dummy_driver))
|
||||
panic("Couldn't register dummy serial driver\n");
|
||||
}
|
||||
|
||||
static struct tty_driver*
|
||||
crisv32_console_device(struct console* co, int *index)
|
||||
{
|
||||
if (port)
|
||||
*index = port->nbr;
|
||||
return port ? serial_driver : &dummy_driver;
|
||||
}
|
||||
|
||||
static struct console sercons = {
|
||||
name : "ttyS",
|
||||
write: console_write,
|
||||
read : NULL,
|
||||
device : crisv32_console_device,
|
||||
unblank : NULL,
|
||||
setup : console_setup,
|
||||
flags : CON_PRINTBUFFER,
|
||||
index : -1,
|
||||
cflag : 0,
|
||||
next : NULL
|
||||
};
|
||||
static struct console sercons0 = {
|
||||
name : "ttyS",
|
||||
write: console_write,
|
||||
read : NULL,
|
||||
device : crisv32_console_device,
|
||||
unblank : NULL,
|
||||
setup : console_setup,
|
||||
flags : CON_PRINTBUFFER,
|
||||
index : 0,
|
||||
cflag : 0,
|
||||
next : NULL
|
||||
};
|
||||
|
||||
static struct console sercons1 = {
|
||||
name : "ttyS",
|
||||
write: console_write,
|
||||
read : NULL,
|
||||
device : crisv32_console_device,
|
||||
unblank : NULL,
|
||||
setup : console_setup,
|
||||
flags : CON_PRINTBUFFER,
|
||||
index : 1,
|
||||
cflag : 0,
|
||||
next : NULL
|
||||
};
|
||||
static struct console sercons2 = {
|
||||
name : "ttyS",
|
||||
write: console_write,
|
||||
read : NULL,
|
||||
device : crisv32_console_device,
|
||||
unblank : NULL,
|
||||
setup : console_setup,
|
||||
flags : CON_PRINTBUFFER,
|
||||
index : 2,
|
||||
cflag : 0,
|
||||
next : NULL
|
||||
};
|
||||
static struct console sercons3 = {
|
||||
name : "ttyS",
|
||||
write: console_write,
|
||||
read : NULL,
|
||||
device : crisv32_console_device,
|
||||
unblank : NULL,
|
||||
setup : console_setup,
|
||||
flags : CON_PRINTBUFFER,
|
||||
index : 3,
|
||||
cflag : 0,
|
||||
next : NULL
|
||||
};
|
||||
|
||||
/* Register console for printk's, etc. */
|
||||
int __init
|
||||
init_etrax_debug(void)
|
||||
{
|
||||
static int first = 1;
|
||||
|
||||
if (!first) {
|
||||
unregister_console(&sercons);
|
||||
register_console(&sercons0);
|
||||
register_console(&sercons1);
|
||||
register_console(&sercons2);
|
||||
register_console(&sercons3);
|
||||
init_dummy_console();
|
||||
return 0;
|
||||
}
|
||||
first = 0;
|
||||
register_console(&sercons);
|
||||
start_port(port);
|
||||
|
||||
#ifdef CONFIG_ETRAX_KGDB
|
||||
|
@ -456,5 +202,3 @@ init_etrax_debug(void)
|
|||
#endif /* CONFIG_ETRAX_KGDB */
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(init_etrax_debug);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* after a timer-interrupt and after each system call.
|
||||
*
|
||||
* Stack layout in 'ret_from_system_call':
|
||||
* ptrace needs to have all regs on the stack.
|
||||
* ptrace needs to have all regs on the stack.
|
||||
* if the order here is changed, it needs to be
|
||||
* updated in fork.c:copy_process, signal.c:do_signal,
|
||||
* ptrace.c and ptrace.h
|
||||
|
@ -281,12 +281,10 @@ _work_notifysig:
|
|||
;; Deal with pending signals and notify-resume requests.
|
||||
|
||||
addoq +TI_flags, $r0, $acr
|
||||
move.d [$acr], $r13 ; The thread_info_flags parameter.
|
||||
move.d $r9, $r10 ; do_notify_resume syscall/irq param.
|
||||
moveq 0, $r11 ; oldset param - 0 in this case.
|
||||
move.d $sp, $r12 ; The regs param.
|
||||
move.d [$acr], $r12 ; The thread_info_flags parameter.
|
||||
move.d $sp, $r11 ; The regs param.
|
||||
jsr do_notify_resume
|
||||
nop
|
||||
move.d $r9, $r10 ; do_notify_resume syscall/irq param.
|
||||
|
||||
ba _Rexit
|
||||
nop
|
||||
|
@ -396,7 +394,7 @@ nmi_interrupt:
|
|||
btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0
|
||||
bpl 1f
|
||||
nop
|
||||
jsr handle_watchdog_bite ; In time.c.
|
||||
jsr handle_watchdog_bite ; In time.c.
|
||||
move.d $sp, $r10 ; Pointer to registers
|
||||
1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0
|
||||
bpl 1f
|
||||
|
@ -515,6 +513,13 @@ _ugdb_handle_exception:
|
|||
ba do_sigtrap ; SIGTRAP the offending process.
|
||||
move.d [$sp+], $r0 ; Restore R0 in delay slot.
|
||||
|
||||
.global kernel_execve
|
||||
kernel_execve:
|
||||
move.d __NR_execve, $r9
|
||||
break 13
|
||||
ret
|
||||
nop
|
||||
|
||||
.data
|
||||
|
||||
.section .rodata,"a"
|
||||
|
@ -778,21 +783,21 @@ sys_call_table:
|
|||
.long sys_epoll_ctl /* 255 */
|
||||
.long sys_epoll_wait
|
||||
.long sys_remap_file_pages
|
||||
.long sys_set_tid_address
|
||||
.long sys_timer_create
|
||||
.long sys_timer_settime /* 260 */
|
||||
.long sys_timer_gettime
|
||||
.long sys_timer_getoverrun
|
||||
.long sys_timer_delete
|
||||
.long sys_clock_settime
|
||||
.long sys_clock_gettime /* 265 */
|
||||
.long sys_clock_getres
|
||||
.long sys_clock_nanosleep
|
||||
.long sys_set_tid_address
|
||||
.long sys_timer_create
|
||||
.long sys_timer_settime /* 260 */
|
||||
.long sys_timer_gettime
|
||||
.long sys_timer_getoverrun
|
||||
.long sys_timer_delete
|
||||
.long sys_clock_settime
|
||||
.long sys_clock_gettime /* 265 */
|
||||
.long sys_clock_getres
|
||||
.long sys_clock_nanosleep
|
||||
.long sys_statfs64
|
||||
.long sys_fstatfs64
|
||||
.long sys_tgkill /* 270 */
|
||||
.long sys_utimes
|
||||
.long sys_fadvise64_64
|
||||
.long sys_fadvise64_64
|
||||
.long sys_ni_syscall /* sys_vserver */
|
||||
.long sys_ni_syscall /* sys_mbind */
|
||||
.long sys_ni_syscall /* 275 sys_get_mempolicy */
|
||||
|
@ -805,6 +810,48 @@ sys_call_table:
|
|||
.long sys_mq_getsetattr
|
||||
.long sys_ni_syscall /* reserved for kexec */
|
||||
.long sys_waitid
|
||||
.long sys_ni_syscall /* 285 */ /* available */
|
||||
.long sys_add_key
|
||||
.long sys_request_key
|
||||
.long sys_keyctl
|
||||
.long sys_ioprio_set
|
||||
.long sys_ioprio_get /* 290 */
|
||||
.long sys_inotify_init
|
||||
.long sys_inotify_add_watch
|
||||
.long sys_inotify_rm_watch
|
||||
.long sys_migrate_pages
|
||||
.long sys_openat /* 295 */
|
||||
.long sys_mkdirat
|
||||
.long sys_mknodat
|
||||
.long sys_fchownat
|
||||
.long sys_futimesat
|
||||
.long sys_fstatat64 /* 300 */
|
||||
.long sys_unlinkat
|
||||
.long sys_renameat
|
||||
.long sys_linkat
|
||||
.long sys_symlinkat
|
||||
.long sys_readlinkat /* 305 */
|
||||
.long sys_fchmodat
|
||||
.long sys_faccessat
|
||||
.long sys_pselect6
|
||||
.long sys_ppoll
|
||||
.long sys_unshare /* 310 */
|
||||
.long sys_set_robust_list
|
||||
.long sys_get_robust_list
|
||||
.long sys_splice
|
||||
.long sys_sync_file_range
|
||||
.long sys_tee /* 315 */
|
||||
.long sys_vmsplice
|
||||
.long sys_move_pages
|
||||
.long sys_getcpu
|
||||
.long sys_epoll_pwait
|
||||
.long sys_utimensat /* 320 */
|
||||
.long sys_signalfd
|
||||
.long sys_timerfd_create
|
||||
.long sys_eventfd
|
||||
.long sys_fallocate
|
||||
.long sys_timerfd_settime /* 325 */
|
||||
.long sys_timerfd_gettime
|
||||
|
||||
/*
|
||||
* NOTE!! This doesn't have to be exact - we just have
|
||||
|
|
|
@ -1,110 +1,9 @@
|
|||
/* $Id: fasttimer.c,v 1.11 2005/01/04 11:15:46 starvik Exp $
|
||||
/*
|
||||
* linux/arch/cris/kernel/fasttimer.c
|
||||
*
|
||||
* Fast timers for ETRAX FS
|
||||
* This may be useful in other OS than Linux so use 2 space indentation...
|
||||
*
|
||||
* $Log: fasttimer.c,v $
|
||||
* Revision 1.11 2005/01/04 11:15:46 starvik
|
||||
* Don't share timer IRQ.
|
||||
*
|
||||
* Revision 1.10 2004/12/07 09:19:38 starvik
|
||||
* Corrected includes.
|
||||
* Use correct interrupt macros.
|
||||
*
|
||||
* Revision 1.9 2004/05/14 10:18:58 starvik
|
||||
* Export fast_timer_list
|
||||
*
|
||||
* Revision 1.8 2004/05/14 07:58:03 starvik
|
||||
* Merge of changes from 2.4
|
||||
*
|
||||
* Revision 1.7 2003/07/10 12:06:14 starvik
|
||||
* Return IRQ_NONE if irq wasn't handled
|
||||
*
|
||||
* Revision 1.6 2003/07/04 08:27:49 starvik
|
||||
* Merge of Linux 2.5.74
|
||||
*
|
||||
* Revision 1.5 2003/06/05 10:16:22 johana
|
||||
* New INTR_VECT macros.
|
||||
*
|
||||
* Revision 1.4 2003/06/03 08:49:45 johana
|
||||
* Fixed typo.
|
||||
*
|
||||
* Revision 1.3 2003/06/02 12:51:27 johana
|
||||
* Now compiles.
|
||||
* Commented some include files that probably can be removed.
|
||||
*
|
||||
* Revision 1.2 2003/06/02 12:09:41 johana
|
||||
* Ported to ETRAX FS using the trig interrupt instead of timer1.
|
||||
*
|
||||
* Revision 1.3 2002/12/12 08:26:32 starvik
|
||||
* Don't use C-comments inside CVS comments
|
||||
*
|
||||
* Revision 1.2 2002/12/11 15:42:02 starvik
|
||||
* Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/
|
||||
*
|
||||
* Revision 1.1 2002/11/18 07:58:06 starvik
|
||||
* Fast timers (from Linux 2.4)
|
||||
*
|
||||
* Revision 1.5 2002/10/15 06:21:39 starvik
|
||||
* Added call to init_waitqueue_head
|
||||
*
|
||||
* Revision 1.4 2002/05/28 17:47:59 johana
|
||||
* Added del_fast_timer()
|
||||
*
|
||||
* Revision 1.3 2002/05/28 16:16:07 johana
|
||||
* Handle empty fast_timer_list
|
||||
*
|
||||
* Revision 1.2 2002/05/27 15:38:42 johana
|
||||
* Made it compile without warnings on Linux 2.4.
|
||||
* (includes, wait_queue, PROC_FS and snprintf)
|
||||
*
|
||||
* Revision 1.1 2002/05/27 15:32:25 johana
|
||||
* arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree.
|
||||
*
|
||||
* Revision 1.8 2001/11/27 13:50:40 pkj
|
||||
* Disable interrupts while stopping the timer and while modifying the
|
||||
* list of active timers in timer1_handler() as it may be interrupted
|
||||
* by other interrupts (e.g., the serial interrupt) which may add fast
|
||||
* timers.
|
||||
*
|
||||
* Revision 1.7 2001/11/22 11:50:32 pkj
|
||||
* * Only store information about the last 16 timers.
|
||||
* * proc_fasttimer_read() now uses an allocated buffer, since it
|
||||
* requires more space than just a page even for only writing the
|
||||
* last 16 timers. The buffer is only allocated on request, so
|
||||
* unless /proc/fasttimer is read, it is never allocated.
|
||||
* * Renamed fast_timer_started to fast_timers_started to match
|
||||
* fast_timers_added and fast_timers_expired.
|
||||
* * Some clean-up.
|
||||
*
|
||||
* Revision 1.6 2000/12/13 14:02:08 johana
|
||||
* Removed volatile for fast_timer_list
|
||||
*
|
||||
* Revision 1.5 2000/12/13 13:55:35 johana
|
||||
* Added DEBUG_LOG, added som cli() and cleanup
|
||||
*
|
||||
* Revision 1.4 2000/12/05 13:48:50 johana
|
||||
* Added range check when writing proc file, modified timer int handling
|
||||
*
|
||||
* Revision 1.3 2000/11/23 10:10:20 johana
|
||||
* More debug/logging possibilities.
|
||||
* Moved GET_JIFFIES_USEC() to timex.h and time.c
|
||||
*
|
||||
* Revision 1.2 2000/11/01 13:41:04 johana
|
||||
* Clean up and bugfixes.
|
||||
* Created new do_gettimeofday_fast() that gets a timeval struct
|
||||
* with time based on jiffies and *R_TIMER0_DATA, uses a table
|
||||
* for fast conversion of timer value to microseconds.
|
||||
* (Much faster the standard do_gettimeofday() and we don't really
|
||||
* want to use the true time - we want the "uptime" so timers don't screw up
|
||||
* when we change the time.
|
||||
* TODO: Add efficient support for continuous timers as well.
|
||||
*
|
||||
* Revision 1.1 2000/10/26 15:49:16 johana
|
||||
* Added fasttimer, highresolution timers.
|
||||
*
|
||||
* Copyright (C) 2000,2001 2002, 2003 Axis Communications AB, Lund, Sweden
|
||||
* Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
@ -122,9 +21,9 @@
|
|||
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/timer_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/timer_defs.h>
|
||||
#include <asm/fasttimer.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
|
@ -140,30 +39,25 @@
|
|||
|
||||
#define DEBUG_LOG_INCLUDED
|
||||
#define FAST_TIMER_LOG
|
||||
//#define FAST_TIMER_TEST
|
||||
/* #define FAST_TIMER_TEST */
|
||||
|
||||
#define FAST_TIMER_SANITY_CHECKS
|
||||
|
||||
#ifdef FAST_TIMER_SANITY_CHECKS
|
||||
#define SANITYCHECK(x) x
|
||||
static int sanity_failed = 0;
|
||||
#else
|
||||
#define SANITYCHECK(x)
|
||||
static int sanity_failed;
|
||||
#endif
|
||||
|
||||
#define D1(x)
|
||||
#define D2(x)
|
||||
#define DP(x)
|
||||
|
||||
#define __INLINE__ inline
|
||||
|
||||
static int fast_timer_running = 0;
|
||||
static int fast_timers_added = 0;
|
||||
static int fast_timers_started = 0;
|
||||
static int fast_timers_expired = 0;
|
||||
static int fast_timers_deleted = 0;
|
||||
static int fast_timer_is_init = 0;
|
||||
static int fast_timer_ints = 0;
|
||||
static unsigned int fast_timer_running;
|
||||
static unsigned int fast_timers_added;
|
||||
static unsigned int fast_timers_started;
|
||||
static unsigned int fast_timers_expired;
|
||||
static unsigned int fast_timers_deleted;
|
||||
static unsigned int fast_timer_is_init;
|
||||
static unsigned int fast_timer_ints;
|
||||
|
||||
struct fast_timer *fast_timer_list = NULL;
|
||||
|
||||
|
@ -171,8 +65,8 @@ struct fast_timer *fast_timer_list = NULL;
|
|||
#define DEBUG_LOG_MAX 128
|
||||
static const char * debug_log_string[DEBUG_LOG_MAX];
|
||||
static unsigned long debug_log_value[DEBUG_LOG_MAX];
|
||||
static int debug_log_cnt = 0;
|
||||
static int debug_log_cnt_wrapped = 0;
|
||||
static unsigned int debug_log_cnt;
|
||||
static unsigned int debug_log_cnt_wrapped;
|
||||
|
||||
#define DEBUG_LOG(string, value) \
|
||||
{ \
|
||||
|
@ -202,103 +96,92 @@ struct fast_timer timer_expired_log[NUM_TIMER_STATS];
|
|||
int timer_div_settings[NUM_TIMER_STATS];
|
||||
int timer_delay_settings[NUM_TIMER_STATS];
|
||||
|
||||
struct work_struct fast_work;
|
||||
|
||||
static void
|
||||
timer_trig_handler(void);
|
||||
timer_trig_handler(struct work_struct *work);
|
||||
|
||||
|
||||
|
||||
/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */
|
||||
void __INLINE__ do_gettimeofday_fast(struct timeval *tv)
|
||||
inline void do_gettimeofday_fast(struct fasttime_t *tv)
|
||||
{
|
||||
unsigned long sec = jiffies;
|
||||
unsigned long usec = GET_JIFFIES_USEC();
|
||||
|
||||
usec += (sec % HZ) * (1000000 / HZ);
|
||||
sec = sec / HZ;
|
||||
|
||||
if (usec > 1000000)
|
||||
{
|
||||
usec -= 1000000;
|
||||
sec++;
|
||||
}
|
||||
tv->tv_sec = sec;
|
||||
tv->tv_usec = usec;
|
||||
tv->tv_jiff = jiffies;
|
||||
tv->tv_usec = GET_JIFFIES_USEC();
|
||||
}
|
||||
|
||||
int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1)
|
||||
inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1)
|
||||
{
|
||||
if (t0->tv_sec < t1->tv_sec)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (t0->tv_sec > t1->tv_sec)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (t0->tv_usec < t1->tv_usec)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (t0->tv_usec > t1->tv_usec)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
/* Compare jiffies. Takes care of wrapping */
|
||||
if (time_before(t0->tv_jiff, t1->tv_jiff))
|
||||
return -1;
|
||||
else if (time_after(t0->tv_jiff, t1->tv_jiff))
|
||||
return 1;
|
||||
|
||||
/* Compare us */
|
||||
if (t0->tv_usec < t1->tv_usec)
|
||||
return -1;
|
||||
else if (t0->tv_usec > t1->tv_usec)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called with ints off */
|
||||
void __INLINE__ start_timer_trig(unsigned long delay_us)
|
||||
inline void start_timer_trig(unsigned long delay_us)
|
||||
{
|
||||
reg_timer_rw_ack_intr ack_intr = { 0 };
|
||||
reg_timer_rw_intr_mask intr_mask;
|
||||
reg_timer_rw_trig trig;
|
||||
reg_timer_rw_trig_cfg trig_cfg = { 0 };
|
||||
reg_timer_r_time r_time;
|
||||
reg_timer_r_time r_time0;
|
||||
reg_timer_r_time r_time1;
|
||||
unsigned char trig_wrap;
|
||||
unsigned char time_wrap;
|
||||
|
||||
r_time = REG_RD(timer, regi_timer, r_time);
|
||||
r_time0 = REG_RD(timer, regi_timer0, r_time);
|
||||
|
||||
D1(printk("start_timer_trig : %d us freq: %i div: %i\n",
|
||||
delay_us, freq_index, div));
|
||||
/* Clear trig irq */
|
||||
intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
|
||||
intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
|
||||
intr_mask.trig = 0;
|
||||
REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
|
||||
REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
|
||||
|
||||
/* Set timer values */
|
||||
/* r_time is 100MHz (10 ns resolution) */
|
||||
trig = r_time + delay_us*(1000/10);
|
||||
/* Set timer values and check if trigger wraps. */
|
||||
/* r_time is 100MHz (10 ns resolution) */
|
||||
trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0;
|
||||
|
||||
timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig;
|
||||
timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us;
|
||||
|
||||
/* Ack interrupt */
|
||||
ack_intr.trig = 1;
|
||||
REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
|
||||
REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
|
||||
|
||||
/* Start timer */
|
||||
REG_WR(timer, regi_timer, rw_trig, trig);
|
||||
REG_WR(timer, regi_timer0, rw_trig, trig);
|
||||
trig_cfg.tmr = regk_timer_time;
|
||||
REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
|
||||
REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
|
||||
|
||||
/* Check if we have already passed the trig time */
|
||||
r_time = REG_RD(timer, regi_timer, r_time);
|
||||
if (r_time < trig) {
|
||||
r_time1 = REG_RD(timer, regi_timer0, r_time);
|
||||
time_wrap = r_time1 < r_time0;
|
||||
|
||||
if ((trig_wrap && !time_wrap) || (r_time1 < trig)) {
|
||||
/* No, Enable trig irq */
|
||||
intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
|
||||
intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
|
||||
intr_mask.trig = 1;
|
||||
REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
|
||||
REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
|
||||
fast_timers_started++;
|
||||
fast_timer_running = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* We have passed the time, disable trig point, ack intr */
|
||||
trig_cfg.tmr = regk_timer_off;
|
||||
REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
|
||||
REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
|
||||
/* call the int routine directly */
|
||||
timer_trig_handler();
|
||||
REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
|
||||
REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
|
||||
/* call the int routine */
|
||||
INIT_WORK(&fast_work, timer_trig_handler);
|
||||
schedule_work(&fast_work);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -320,22 +203,20 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
do_gettimeofday_fast(&t->tv_set);
|
||||
tmp = fast_timer_list;
|
||||
|
||||
SANITYCHECK({ /* Check so this is not in the list already... */
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (tmp == t)
|
||||
{
|
||||
printk("timer name: %s data: 0x%08lX already in list!\n", name, data);
|
||||
sanity_failed++;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
tmp = fast_timer_list;
|
||||
});
|
||||
#ifdef FAST_TIMER_SANITY_CHECKS
|
||||
/* Check so this is not in the list already... */
|
||||
while (tmp != NULL) {
|
||||
if (tmp == t) {
|
||||
printk(KERN_DEBUG
|
||||
"timer name: %s data: 0x%08lX already "
|
||||
"in list!\n", name, data);
|
||||
sanity_failed++;
|
||||
goto done;
|
||||
} else
|
||||
tmp = tmp->next;
|
||||
}
|
||||
tmp = fast_timer_list;
|
||||
#endif
|
||||
|
||||
t->delay_us = delay_us;
|
||||
t->function = function;
|
||||
|
@ -343,11 +224,10 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
t->name = name;
|
||||
|
||||
t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000;
|
||||
t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000;
|
||||
if (t->tv_expires.tv_usec > 1000000)
|
||||
{
|
||||
t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ;
|
||||
if (t->tv_expires.tv_usec > 1000000) {
|
||||
t->tv_expires.tv_usec -= 1000000;
|
||||
t->tv_expires.tv_sec++;
|
||||
t->tv_expires.tv_jiff += HZ;
|
||||
}
|
||||
#ifdef FAST_TIMER_LOG
|
||||
timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t;
|
||||
|
@ -355,15 +235,12 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
fast_timers_added++;
|
||||
|
||||
/* Check if this should timeout before anything else */
|
||||
if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0)
|
||||
{
|
||||
if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) {
|
||||
/* Put first in list and modify the timer value */
|
||||
t->prev = NULL;
|
||||
t->next = fast_timer_list;
|
||||
if (fast_timer_list)
|
||||
{
|
||||
fast_timer_list->prev = t;
|
||||
}
|
||||
fast_timer_list = t;
|
||||
#ifdef FAST_TIMER_LOG
|
||||
timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
|
||||
|
@ -372,10 +249,8 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
} else {
|
||||
/* Put in correct place in list */
|
||||
while (tmp->next &&
|
||||
timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
|
||||
{
|
||||
fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0)
|
||||
tmp = tmp->next;
|
||||
}
|
||||
/* Insert t after tmp */
|
||||
t->prev = tmp;
|
||||
t->next = tmp->next;
|
||||
|
@ -388,6 +263,7 @@ void start_one_shot_timer(struct fast_timer *t,
|
|||
|
||||
D2(printk("start_one_shot_timer: %d us done\n", delay_us));
|
||||
|
||||
done:
|
||||
local_irq_restore(flags);
|
||||
} /* start_one_shot_timer */
|
||||
|
||||
|
@ -431,19 +307,18 @@ int del_fast_timer(struct fast_timer * t)
|
|||
/* Timer interrupt handler for trig interrupts */
|
||||
|
||||
static irqreturn_t
|
||||
timer_trig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
timer_trig_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
reg_timer_r_masked_intr masked_intr;
|
||||
|
||||
/* Check if the timer interrupt is for us (a trig int) */
|
||||
masked_intr = REG_RD(timer, regi_timer, r_masked_intr);
|
||||
masked_intr = REG_RD(timer, regi_timer0, r_masked_intr);
|
||||
if (!masked_intr.trig)
|
||||
return IRQ_NONE;
|
||||
timer_trig_handler();
|
||||
timer_trig_handler(NULL);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void timer_trig_handler(void)
|
||||
static void timer_trig_handler(struct work_struct *work)
|
||||
{
|
||||
reg_timer_rw_ack_intr ack_intr = { 0 };
|
||||
reg_timer_rw_intr_mask intr_mask;
|
||||
|
@ -451,38 +326,45 @@ static void timer_trig_handler(void)
|
|||
struct fast_timer *t;
|
||||
unsigned long flags;
|
||||
|
||||
/* We keep interrupts disabled not only when we modify the
|
||||
* fast timer list, but any time we hold a reference to a
|
||||
* timer in the list, since del_fast_timer may be called
|
||||
* from (another) interrupt context. Thus, the only time
|
||||
* when interrupts are enabled is when calling the timer
|
||||
* callback function.
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
/* Clear timer trig interrupt */
|
||||
intr_mask = REG_RD(timer, regi_timer, rw_intr_mask);
|
||||
intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask);
|
||||
intr_mask.trig = 0;
|
||||
REG_WR(timer, regi_timer, rw_intr_mask, intr_mask);
|
||||
REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask);
|
||||
|
||||
/* First stop timer, then ack interrupt */
|
||||
/* Stop timer */
|
||||
trig_cfg.tmr = regk_timer_off;
|
||||
REG_WR(timer, regi_timer, rw_trig_cfg, trig_cfg);
|
||||
REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg);
|
||||
|
||||
/* Ack interrupt */
|
||||
ack_intr.trig = 1;
|
||||
REG_WR(timer, regi_timer, rw_ack_intr, ack_intr);
|
||||
REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr);
|
||||
|
||||
fast_timer_running = 0;
|
||||
fast_timer_ints++;
|
||||
|
||||
local_irq_restore(flags);
|
||||
fast_timer_function_type *f;
|
||||
unsigned long d;
|
||||
|
||||
t = fast_timer_list;
|
||||
while (t)
|
||||
{
|
||||
struct timeval tv;
|
||||
while (t) {
|
||||
struct fasttime_t tv;
|
||||
|
||||
/* Has it really expired? */
|
||||
do_gettimeofday_fast(&tv);
|
||||
D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec));
|
||||
D1(printk(KERN_DEBUG
|
||||
"t: %is %06ius\n", tv.tv_jiff, tv.tv_usec));
|
||||
|
||||
if (timeval_cmp(&t->tv_expires, &tv) <= 0)
|
||||
{
|
||||
if (fasttime_cmp(&t->tv_expires, &tv) <= 0) {
|
||||
/* Yes it has expired */
|
||||
#ifdef FAST_TIMER_LOG
|
||||
timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t;
|
||||
|
@ -490,84 +372,77 @@ static void timer_trig_handler(void)
|
|||
fast_timers_expired++;
|
||||
|
||||
/* Remove this timer before call, since it may reuse the timer */
|
||||
local_irq_save(flags);
|
||||
if (t->prev)
|
||||
{
|
||||
t->prev->next = t->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
fast_timer_list = t->next;
|
||||
}
|
||||
if (t->next)
|
||||
{
|
||||
t->next->prev = t->prev;
|
||||
}
|
||||
t->prev = NULL;
|
||||
t->next = NULL;
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (t->function != NULL)
|
||||
{
|
||||
t->function(t->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Save function callback data before enabling
|
||||
* interrupts, since the timer may be removed and we
|
||||
* don't know how it was allocated (e.g. ->function
|
||||
* and ->data may become overwritten after deletion
|
||||
* if the timer was stack-allocated).
|
||||
*/
|
||||
f = t->function;
|
||||
d = t->data;
|
||||
|
||||
if (f != NULL) {
|
||||
/* Run the callback function with interrupts
|
||||
* enabled. */
|
||||
local_irq_restore(flags);
|
||||
f(d);
|
||||
local_irq_save(flags);
|
||||
} else
|
||||
DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Timer is to early, let's set it again using the normal routines */
|
||||
D1(printk(".\n"));
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
if ((t = fast_timer_list) != NULL)
|
||||
{
|
||||
t = fast_timer_list;
|
||||
if (t != NULL) {
|
||||
/* Start next timer.. */
|
||||
long us;
|
||||
struct timeval tv;
|
||||
long us = 0;
|
||||
struct fasttime_t tv;
|
||||
|
||||
do_gettimeofday_fast(&tv);
|
||||
us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 +
|
||||
t->tv_expires.tv_usec - tv.tv_usec);
|
||||
if (us > 0)
|
||||
{
|
||||
if (!fast_timer_running)
|
||||
{
|
||||
|
||||
/* time_after_eq takes care of wrapping */
|
||||
if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff))
|
||||
us = ((t->tv_expires.tv_jiff - tv.tv_jiff) *
|
||||
1000000 / HZ + t->tv_expires.tv_usec -
|
||||
tv.tv_usec);
|
||||
|
||||
if (us > 0) {
|
||||
if (!fast_timer_running) {
|
||||
#ifdef FAST_TIMER_LOG
|
||||
timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t;
|
||||
#endif
|
||||
start_timer_trig(us);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* Timer already expired, let's handle it better late than never.
|
||||
* The normal loop handles it
|
||||
*/
|
||||
D1(printk("e! %d\n", us));
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
if (!t)
|
||||
{
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (!t)
|
||||
D1(printk("ttrig stop!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
static void wake_up_func(unsigned long data)
|
||||
{
|
||||
#ifdef DECLARE_WAITQUEUE
|
||||
wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data;
|
||||
#else
|
||||
struct wait_queue **sleep_wait_p = (struct wait_queue **)data;
|
||||
#endif
|
||||
wake_up(sleep_wait_p);
|
||||
}
|
||||
|
||||
|
@ -577,28 +452,17 @@ static void wake_up_func(unsigned long data)
|
|||
void schedule_usleep(unsigned long us)
|
||||
{
|
||||
struct fast_timer t;
|
||||
#ifdef DECLARE_WAITQUEUE
|
||||
wait_queue_head_t sleep_wait;
|
||||
init_waitqueue_head(&sleep_wait);
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
#else
|
||||
struct wait_queue *sleep_wait = NULL;
|
||||
struct wait_queue wait = { current, NULL };
|
||||
#endif
|
||||
|
||||
D1(printk("schedule_usleep(%d)\n", us));
|
||||
add_wait_queue(&sleep_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us,
|
||||
"usleep");
|
||||
schedule();
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&sleep_wait, &wait);
|
||||
/* Uninterruptible sleep on the fast timer. (The condition is
|
||||
* somewhat redundant since the timer is what wakes us up.) */
|
||||
wait_event(sleep_wait, !fast_timer_pending(&t));
|
||||
|
||||
D1(printk("done schedule_usleep(%d)\n", us));
|
||||
#ifdef DECLARE_WAITQUEUE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
@ -618,20 +482,22 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
unsigned long flags;
|
||||
int i = 0;
|
||||
int num_to_show;
|
||||
struct timeval tv;
|
||||
struct fasttime_t tv;
|
||||
struct fast_timer *t, *nextt;
|
||||
static char *bigbuf = NULL;
|
||||
static unsigned long used;
|
||||
|
||||
if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE)))
|
||||
{
|
||||
used = 0;
|
||||
bigbuf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
if (!bigbuf) {
|
||||
bigbuf = vmalloc(BIG_BUF_SIZE);
|
||||
if (!bigbuf) {
|
||||
used = 0;
|
||||
if (buf)
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!offset || !used)
|
||||
{
|
||||
if (!offset || !used) {
|
||||
do_gettimeofday_fast(&tv);
|
||||
|
||||
used = 0;
|
||||
|
@ -648,7 +514,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
used += sprintf(bigbuf + used, "Fast timer running: %s\n",
|
||||
fast_timer_running ? "yes" : "no");
|
||||
used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n",
|
||||
(unsigned long)tv.tv_sec,
|
||||
(unsigned long)tv.tv_jiff,
|
||||
(unsigned long)tv.tv_usec);
|
||||
#ifdef FAST_TIMER_SANITY_CHECKS
|
||||
used += sprintf(bigbuf + used, "Sanity failed: %i\n",
|
||||
|
@ -661,10 +527,8 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
int end_i = debug_log_cnt;
|
||||
i = 0;
|
||||
|
||||
if (debug_log_cnt_wrapped)
|
||||
{
|
||||
if (debug_log_cnt_wrapped)
|
||||
i = debug_log_cnt;
|
||||
}
|
||||
|
||||
while ((i != end_i || (debug_log_cnt_wrapped && !used)) &&
|
||||
used+100 < BIG_BUF_SIZE)
|
||||
|
@ -697,9 +561,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
"d: %6li us data: 0x%08lX"
|
||||
"\n",
|
||||
t->name,
|
||||
(unsigned long)t->tv_set.tv_sec,
|
||||
(unsigned long)t->tv_set.tv_jiff,
|
||||
(unsigned long)t->tv_set.tv_usec,
|
||||
(unsigned long)t->tv_expires.tv_sec,
|
||||
(unsigned long)t->tv_expires.tv_jiff,
|
||||
(unsigned long)t->tv_expires.tv_usec,
|
||||
t->delay_us,
|
||||
t->data
|
||||
|
@ -719,9 +583,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
"d: %6li us data: 0x%08lX"
|
||||
"\n",
|
||||
t->name,
|
||||
(unsigned long)t->tv_set.tv_sec,
|
||||
(unsigned long)t->tv_set.tv_jiff,
|
||||
(unsigned long)t->tv_set.tv_usec,
|
||||
(unsigned long)t->tv_expires.tv_sec,
|
||||
(unsigned long)t->tv_expires.tv_jiff,
|
||||
(unsigned long)t->tv_expires.tv_usec,
|
||||
t->delay_us,
|
||||
t->data
|
||||
|
@ -739,9 +603,9 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
"d: %6li us data: 0x%08lX"
|
||||
"\n",
|
||||
t->name,
|
||||
(unsigned long)t->tv_set.tv_sec,
|
||||
(unsigned long)t->tv_set.tv_jiff,
|
||||
(unsigned long)t->tv_set.tv_usec,
|
||||
(unsigned long)t->tv_expires.tv_sec,
|
||||
(unsigned long)t->tv_expires.tv_jiff,
|
||||
(unsigned long)t->tv_expires.tv_usec,
|
||||
t->delay_us,
|
||||
t->data
|
||||
|
@ -752,26 +616,25 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
|
|||
|
||||
used += sprintf(bigbuf + used, "Active timers:\n");
|
||||
local_irq_save(flags);
|
||||
local_irq_save(flags);
|
||||
t = fast_timer_list;
|
||||
while (t != NULL && (used+100 < BIG_BUF_SIZE))
|
||||
{
|
||||
nextt = t->next;
|
||||
local_irq_restore(flags);
|
||||
used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu "
|
||||
"d: %6li us data: 0x%08lX"
|
||||
/* " func: 0x%08lX" */
|
||||
"\n",
|
||||
t->name,
|
||||
(unsigned long)t->tv_set.tv_sec,
|
||||
(unsigned long)t->tv_set.tv_usec,
|
||||
(unsigned long)t->tv_expires.tv_sec,
|
||||
(unsigned long)t->tv_expires.tv_usec,
|
||||
"d: %6li us data: 0x%08lX"
|
||||
/* " func: 0x%08lX" */
|
||||
"\n",
|
||||
t->name,
|
||||
(unsigned long)t->tv_set.tv_jiff,
|
||||
(unsigned long)t->tv_set.tv_usec,
|
||||
(unsigned long)t->tv_expires.tv_jiff,
|
||||
(unsigned long)t->tv_expires.tv_usec,
|
||||
t->delay_us,
|
||||
t->data
|
||||
/* , t->function */
|
||||
);
|
||||
local_irq_disable();
|
||||
local_irq_save(flags);
|
||||
if (t->next != nextt)
|
||||
{
|
||||
printk("timer removed!\n");
|
||||
|
@ -800,7 +663,7 @@ static volatile int num_test_timeout = 0;
|
|||
static struct fast_timer tr[10];
|
||||
static int exp_num[10];
|
||||
|
||||
static struct timeval tv_exp[100];
|
||||
static struct fasttime_t tv_exp[100];
|
||||
|
||||
static void test_timeout(unsigned long data)
|
||||
{
|
||||
|
@ -838,7 +701,7 @@ static void fast_timer_test(void)
|
|||
int prev_num;
|
||||
int j;
|
||||
|
||||
struct timeval tv, tv0, tv1, tv2;
|
||||
struct fasttime_t tv, tv0, tv1, tv2;
|
||||
|
||||
printk("fast_timer_test() start\n");
|
||||
do_gettimeofday_fast(&tv);
|
||||
|
@ -851,21 +714,22 @@ static void fast_timer_test(void)
|
|||
{
|
||||
do_gettimeofday_fast(&tv_exp[j]);
|
||||
}
|
||||
printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec);
|
||||
printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec);
|
||||
|
||||
for (j = 0; j < 1000; j++)
|
||||
{
|
||||
printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
|
||||
printk(KERN_DEBUG "%i %i %i %i %i\n",
|
||||
j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]);
|
||||
j += 4;
|
||||
}
|
||||
for (j = 0; j < 100; j++)
|
||||
{
|
||||
printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n",
|
||||
tv_exp[j].tv_sec,tv_exp[j].tv_usec,
|
||||
tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec,
|
||||
tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec,
|
||||
tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec,
|
||||
tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec);
|
||||
printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n",
|
||||
tv_exp[j].tv_jiff, tv_exp[j].tv_usec,
|
||||
tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec,
|
||||
tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec,
|
||||
tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec,
|
||||
tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec);
|
||||
j += 4;
|
||||
}
|
||||
do_gettimeofday_fast(&tv0);
|
||||
|
@ -892,14 +756,15 @@ static void fast_timer_test(void)
|
|||
while (num_test_timeout < i)
|
||||
{
|
||||
if (num_test_timeout != prev_num)
|
||||
{
|
||||
prev_num = num_test_timeout;
|
||||
}
|
||||
}
|
||||
do_gettimeofday_fast(&tv2);
|
||||
printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec);
|
||||
printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec);
|
||||
printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec);
|
||||
printk(KERN_INFO "Timers started %is %06i\n",
|
||||
tv0.tv_jiff, tv0.tv_usec);
|
||||
printk(KERN_INFO "Timers started at %is %06i\n",
|
||||
tv1.tv_jiff, tv1.tv_usec);
|
||||
printk(KERN_INFO "Timers done %is %06i\n",
|
||||
tv2.tv_jiff, tv2.tv_usec);
|
||||
DP(printk("buf0:\n");
|
||||
printk(buf0);
|
||||
printk("buf1:\n");
|
||||
|
@ -921,9 +786,9 @@ static void fast_timer_test(void)
|
|||
printk("%-10s set: %6is %06ius exp: %6is %06ius "
|
||||
"data: 0x%08X func: 0x%08X\n",
|
||||
t->name,
|
||||
t->tv_set.tv_sec,
|
||||
t->tv_set.tv_jiff,
|
||||
t->tv_set.tv_usec,
|
||||
t->tv_expires.tv_sec,
|
||||
t->tv_expires.tv_jiff,
|
||||
t->tv_expires.tv_usec,
|
||||
t->data,
|
||||
t->function
|
||||
|
@ -931,10 +796,12 @@ static void fast_timer_test(void)
|
|||
|
||||
printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n",
|
||||
t->delay_us,
|
||||
tv_exp[j].tv_sec,
|
||||
tv_exp[j].tv_jiff,
|
||||
tv_exp[j].tv_usec,
|
||||
exp_num[j],
|
||||
(tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec);
|
||||
(tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) *
|
||||
1000000 + tv_exp[j].tv_usec -
|
||||
t->tv_expires.tv_usec);
|
||||
}
|
||||
proc_fasttimer_read(buf5, NULL, 0, 0, 0);
|
||||
printk("buf5 after all done:\n");
|
||||
|
@ -944,7 +811,7 @@ static void fast_timer_test(void)
|
|||
#endif
|
||||
|
||||
|
||||
void fast_timer_init(void)
|
||||
int fast_timer_init(void)
|
||||
{
|
||||
/* For some reason, request_irq() hangs when called froom time_init() */
|
||||
if (!fast_timer_is_init)
|
||||
|
@ -952,18 +819,20 @@ void fast_timer_init(void)
|
|||
printk("fast_timer_init()\n");
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
|
||||
fasttimer_proc_entry->read_proc = proc_fasttimer_read;
|
||||
fasttimer_proc_entry = create_proc_entry("fasttimer", 0, 0);
|
||||
if (fasttimer_proc_entry)
|
||||
fasttimer_proc_entry->read_proc = proc_fasttimer_read;
|
||||
#endif /* PROC_FS */
|
||||
if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED,
|
||||
"fast timer int", NULL))
|
||||
{
|
||||
printk("err: timer1 irq\n");
|
||||
}
|
||||
if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
|
||||
IRQF_SHARED | IRQF_DISABLED,
|
||||
"fast timer int", &fast_timer_list))
|
||||
printk(KERN_ERR "err: fasttimer irq\n");
|
||||
fast_timer_is_init = 1;
|
||||
#ifdef FAST_TIMER_TEST
|
||||
printk("do test\n");
|
||||
fast_timer_test();
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
__initcall(fast_timer_init);
|
||||
|
|
|
@ -4,22 +4,25 @@
|
|||
* Copyright (C) 2003, Axis Communications AB
|
||||
*/
|
||||
|
||||
|
||||
#define ASSEMBLER_MACROS_ONLY
|
||||
|
||||
/*
|
||||
* The macros found in mmu_defs_asm.h uses the ## concatenation operator, so
|
||||
* -traditional must not be used when assembling this file.
|
||||
*/
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/asm/mmu_defs_asm.h>
|
||||
#include <asm/arch/hwregs/asm/reg_map_asm.h>
|
||||
#include <asm/arch/hwregs/asm/config_defs_asm.h>
|
||||
#include <asm/arch/hwregs/asm/bif_core_defs_asm.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/memmap.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
#include <hwregs/asm/mmu_defs_asm.h>
|
||||
#include <hwregs/asm/reg_map_asm.h>
|
||||
#include <asm/arch/mach/startup.inc>
|
||||
|
||||
#define CRAMFS_MAGIC 0x28cd3d45
|
||||
#define JHEAD_MAGIC 0x1FF528A6
|
||||
#define JHEAD_SIZE 8
|
||||
#define RAM_INIT_MAGIC 0x56902387
|
||||
#define COMMAND_LINE_MAGIC 0x87109563
|
||||
#define NAND_BOOT_MAGIC 0x9a9db001
|
||||
|
||||
;; NOTE: R8 and R9 carry information from the decompressor (if the
|
||||
;; kernel was compressed). They must not be used in the code below
|
||||
|
@ -30,12 +33,11 @@
|
|||
.global romfs_start
|
||||
.global romfs_length
|
||||
.global romfs_in_flash
|
||||
.global nand_boot
|
||||
.global swapper_pg_dir
|
||||
.global crisv32_nand_boot
|
||||
.global crisv32_nand_cramfs_offset
|
||||
|
||||
;; Dummy section to make it bootable with current VCS simulator
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
#ifdef CONFIG_ETRAX_VCS_SIM
|
||||
.section ".boot", "ax"
|
||||
ba tstart
|
||||
nop
|
||||
|
@ -51,33 +53,15 @@ tstart:
|
|||
;;
|
||||
di
|
||||
|
||||
;; Start clocks for used blocks.
|
||||
move.d REG_ADDR(config, regi_config, rw_clk_ctrl), $r1
|
||||
move.d [$r1], $r0
|
||||
or.d REG_STATE(config, rw_clk_ctrl, cpu, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, bif, yes) | \
|
||||
REG_STATE(config, rw_clk_ctrl, fix_io, yes), $r0
|
||||
move.d $r0, [$r1]
|
||||
START_CLOCKS
|
||||
|
||||
;; Set up waitstates etc
|
||||
move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r0
|
||||
move.d CONFIG_ETRAX_MEM_GRP1_CONFIG, $r1
|
||||
move.d $r1, [$r0]
|
||||
move.d REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg), $r0
|
||||
move.d CONFIG_ETRAX_MEM_GRP2_CONFIG, $r1
|
||||
move.d $r1, [$r0]
|
||||
move.d REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg), $r0
|
||||
move.d CONFIG_ETRAX_MEM_GRP3_CONFIG, $r1
|
||||
move.d $r1, [$r0]
|
||||
move.d REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
|
||||
move.d CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
|
||||
move.d $r1, [$r0]
|
||||
SETUP_WAIT_STATES
|
||||
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
;; Set up minimal flash waitstates
|
||||
move.d 0, $r10
|
||||
move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
|
||||
move.d $r10, [$r11]
|
||||
GIO_INIT
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
secondary_cpu_entry: /* Entry point for secondary CPUs */
|
||||
di
|
||||
#endif
|
||||
|
||||
;; Setup and enable the MMU. Use same configuration for both the data
|
||||
|
@ -85,7 +69,7 @@ tstart:
|
|||
;;
|
||||
;; Note; 3 cycles is needed for a bank-select to take effect. Further;
|
||||
;; bank 1 is the instruction MMU, bank 2 is the data MMU.
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
|
||||
|
@ -93,7 +77,7 @@ tstart:
|
|||
;; Map the virtual DRAM to the RW eprom area at address 0.
|
||||
;; Also map 0xa for the hook calls,
|
||||
move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \
|
||||
| REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
|
||||
#endif
|
||||
|
@ -104,7 +88,7 @@ tstart:
|
|||
|
||||
;; Enable certain page protections and setup linear mapping
|
||||
;; for f,e,c,b,4,0.
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
move.d REG_STATE(mmu, rw_mm_cfg, we, on) \
|
||||
| REG_STATE(mmu, rw_mm_cfg, acc, on) \
|
||||
| REG_STATE(mmu, rw_mm_cfg, ex, on) \
|
||||
|
@ -183,17 +167,11 @@ tstart:
|
|||
nop
|
||||
nop
|
||||
nop
|
||||
move $s10, $r0
|
||||
move $s12, $r0
|
||||
cmpq 0, $r0
|
||||
beq master_cpu
|
||||
nop
|
||||
slave_cpu:
|
||||
; A slave waits for cpu_now_booting to be equal to CPU ID.
|
||||
move.d cpu_now_booting, $r1
|
||||
slave_wait:
|
||||
cmp.d [$r1], $r0
|
||||
bne slave_wait
|
||||
nop
|
||||
; Time to boot-up. Get stack location provided by master CPU.
|
||||
move.d smp_init_current_idle_thread, $r1
|
||||
move.d [$r1], $sp
|
||||
|
@ -203,9 +181,16 @@ slave_wait:
|
|||
jsr smp_callin
|
||||
nop
|
||||
master_cpu:
|
||||
/* Set up entry point for secondary CPUs. The boot ROM has set up
|
||||
* EBP at start of internal memory. The CPU will get there
|
||||
* later when we issue an IPI to them... */
|
||||
move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0
|
||||
move.d secondary_cpu_entry, $r1
|
||||
move.d $r1, [$r0]
|
||||
#endif
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
;; Check if starting from DRAM or flash.
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
; Check if starting from DRAM (network->RAM boot or unpacked
|
||||
; compressed kernel), or directly from flash.
|
||||
lapcq ., $r0
|
||||
and.d 0x7fffffff, $r0 ; Mask off the non-cache bit.
|
||||
cmp.d 0x10000, $r0 ; Arbitrary, something above this code.
|
||||
|
@ -232,12 +217,13 @@ _inflash:
|
|||
beq _dram_initialized
|
||||
nop
|
||||
|
||||
#include "../lib/dram_init.S"
|
||||
#include "../mach/dram_init.S"
|
||||
|
||||
_dram_initialized:
|
||||
;; Copy the text and data section to DRAM. This depends on that the
|
||||
;; variables used below are correctly set up by the linker script.
|
||||
;; The calculated value stored in R4 is used below.
|
||||
;; Leave the cramfs file system (piggybacked after the kernel) in flash.
|
||||
moveq 0, $r0 ; Source.
|
||||
move.d text_start, $r1 ; Destination.
|
||||
move.d __vmlinux_end, $r2
|
||||
|
@ -249,7 +235,7 @@ _dram_initialized:
|
|||
blo 1b
|
||||
nop
|
||||
|
||||
;; Keep CRAMFS in flash.
|
||||
;; Check for cramfs.
|
||||
moveq 0, $r0
|
||||
move.d romfs_length, $r1
|
||||
move.d $r0, [$r1]
|
||||
|
@ -258,6 +244,7 @@ _dram_initialized:
|
|||
bne 1f
|
||||
nop
|
||||
|
||||
;; Set length and start of cramfs, set romfs_in_flash flag
|
||||
addoq +4, $r4, $acr
|
||||
move.d [$acr], $r0
|
||||
move.d romfs_length, $r1
|
||||
|
@ -273,35 +260,32 @@ _dram_initialized:
|
|||
nop
|
||||
|
||||
_inram:
|
||||
;; Check if booting from NAND flash (in that case we just remember the offset
|
||||
;; into the flash where cramfs should be).
|
||||
move.d REG_ADDR(config, regi_config, r_bootsel), $r0
|
||||
move.d [$r0], $r0
|
||||
and.d REG_MASK(config, r_bootsel, boot_mode), $r0
|
||||
cmp.d REG_STATE(config, r_bootsel, boot_mode, nand), $r0
|
||||
bne move_cramfs
|
||||
moveq 1,$r0
|
||||
move.d crisv32_nand_boot, $r1
|
||||
move.d $r0, [$r1]
|
||||
move.d crisv32_nand_cramfs_offset, $r1
|
||||
move.d $r9, [$r1]
|
||||
;; Check if booting from NAND flash; if so, set appropriate flags
|
||||
;; and move on.
|
||||
cmp.d NAND_BOOT_MAGIC, $r12
|
||||
bne move_cramfs ; not nand, jump
|
||||
moveq 1, $r0
|
||||
move.d romfs_in_flash, $r1
|
||||
move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND
|
||||
move.d $r0, [$r1]
|
||||
jump _start_it
|
||||
moveq 0, $r0 ; tell axisflashmap romfs is not in
|
||||
move.d romfs_in_flash, $r1 ; (directly accessed) flash
|
||||
move.d $r0, [$r1]
|
||||
jump _start_it ; continue with boot
|
||||
nop
|
||||
|
||||
move_cramfs:
|
||||
;; Move the cramfs after BSS.
|
||||
;; kernel is in DRAM.
|
||||
;; Must figure out if there is a piggybacked rootfs image or not.
|
||||
;; Set romfs_length to 0 => no rootfs image available by default.
|
||||
moveq 0, $r0
|
||||
move.d romfs_length, $r1
|
||||
move.d $r0, [$r1]
|
||||
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
;; The kernel could have been unpacked to DRAM by the loader, but
|
||||
;; the cramfs image could still be inte the flash immediately
|
||||
;; following the compressed kernel image. The loaded passes the address
|
||||
;; of the bute succeeding the last compressed byte in the flash in
|
||||
;; the cramfs image could still be in the flash immediately
|
||||
;; following the compressed kernel image. The loader passes the address
|
||||
;; of the byte succeeding the last compressed byte in the flash in
|
||||
;; register R9 when starting the kernel.
|
||||
cmp.d 0x0ffffff8, $r9
|
||||
bhs _no_romfs_in_flash ; R9 points outside the flash area.
|
||||
|
@ -310,11 +294,13 @@ move_cramfs:
|
|||
ba _no_romfs_in_flash
|
||||
nop
|
||||
#endif
|
||||
;; cramfs rootfs might to be in flash. Check for it.
|
||||
move.d [$r9], $r0 ; cramfs_super.magic
|
||||
cmp.d CRAMFS_MAGIC, $r0
|
||||
bne _no_romfs_in_flash
|
||||
nop
|
||||
|
||||
;; found cramfs in flash. set address and size, and romfs_in_flash flag.
|
||||
addoq +4, $r9, $acr
|
||||
move.d [$acr], $r0
|
||||
move.d romfs_length, $r1
|
||||
|
@ -330,27 +316,43 @@ move_cramfs:
|
|||
nop
|
||||
|
||||
_no_romfs_in_flash:
|
||||
;; Look for cramfs.
|
||||
;; No romfs in flash, so look for cramfs, or jffs2 with jhead,
|
||||
;; after kernel in RAM, as is the case with network->RAM boot.
|
||||
;; For cramfs, partition starts with magic and length.
|
||||
;; For jffs2, a jhead is prepended which contains with magic and length.
|
||||
;; The jhead is not part of the jffs2 partition however.
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
move.d __vmlinux_end, $r0
|
||||
#else
|
||||
move.d __end, $r0
|
||||
#endif
|
||||
move.d [$r0], $r1
|
||||
cmp.d CRAMFS_MAGIC, $r1
|
||||
bne 2f
|
||||
cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic?
|
||||
beq 2f ; yes, jump
|
||||
nop
|
||||
cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic?
|
||||
bne 4f ; no, skip copy
|
||||
nop
|
||||
addq 4, $r0 ; location of jffs2 size
|
||||
move.d [$r0+], $r2 ; fetch jffs2 size -> r2
|
||||
; r0 now points to start of jffs2
|
||||
ba 3f
|
||||
nop
|
||||
2:
|
||||
addoq +4, $r0, $acr ; location of cramfs size
|
||||
move.d [$acr], $r2 ; fetch cramfs size -> r2
|
||||
; r0 still points to start of cramfs
|
||||
3:
|
||||
;; Now, move the root fs to after kernel's BSS
|
||||
|
||||
addoq +4, $r0, $acr
|
||||
move.d [$acr], $r2
|
||||
move.d _end, $r1
|
||||
move.d _end, $r1 ; start of cramfs -> r1
|
||||
move.d romfs_start, $r3
|
||||
move.d $r1, [$r3]
|
||||
move.d $r1, [$r3] ; store at romfs_start (for axisflashmap)
|
||||
move.d romfs_length, $r3
|
||||
move.d $r2, [$r3]
|
||||
move.d $r2, [$r3] ; store size at romfs_length
|
||||
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
add.d $r2, $r0
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
add.d $r2, $r0 ; copy from end and downwards
|
||||
add.d $r2, $r1
|
||||
|
||||
lsrq 1, $r2 ; Size is in bytes, we copy words.
|
||||
|
@ -365,10 +367,17 @@ _no_romfs_in_flash:
|
|||
nop
|
||||
#endif
|
||||
|
||||
2:
|
||||
4:
|
||||
;; BSS move done.
|
||||
;; Clear romfs_in_flash flag, as we now know romfs is in DRAM
|
||||
;; Also clear nand_boot flag; if we got here, we know we've not
|
||||
;; booted from NAND flash.
|
||||
moveq 0, $r0
|
||||
move.d romfs_in_flash, $r1
|
||||
move.d $r0, [$r1]
|
||||
moveq 0, $r0
|
||||
move.d nand_boot, $r1
|
||||
move.d $r0, [$r1]
|
||||
|
||||
jump _start_it ; Jump to cached code.
|
||||
nop
|
||||
|
@ -384,8 +393,8 @@ _start_it:
|
|||
move.d cris_command_line, $r10
|
||||
or.d 0x80000000, $r11 ; Make it virtual
|
||||
1:
|
||||
move.b [$r11+], $r12
|
||||
move.b $r12, [$r10+]
|
||||
move.b [$r11+], $r1
|
||||
move.b $r1, [$r10+]
|
||||
subq 1, $r13
|
||||
bne 1b
|
||||
nop
|
||||
|
@ -401,7 +410,7 @@ no_command_line:
|
|||
move.d etrax_irv, $r1 ; Set the exception base register and pointer.
|
||||
move.d $r0, [$r1]
|
||||
|
||||
#ifndef CONFIG_ETRAXFS_SIM
|
||||
#ifndef CONFIG_ETRAX_VCS_SIM
|
||||
;; Clear the BSS region from _bss_start to _end.
|
||||
move.d __bss_start, $r0
|
||||
move.d _end, $r1
|
||||
|
@ -411,7 +420,7 @@ no_command_line:
|
|||
nop
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
#ifdef CONFIG_ETRAX_VCS_SIM
|
||||
/* Set the watchdog timeout to something big. Will be removed when */
|
||||
/* watchdog can be disabled with command line option */
|
||||
move.d 0x7fffffff, $r10
|
||||
|
@ -423,25 +432,44 @@ no_command_line:
|
|||
move.d __bss_start, $r0
|
||||
movem [$r0], $r13
|
||||
|
||||
#ifdef CONFIG_ETRAX_L2CACHE
|
||||
jsr l2cache_init
|
||||
nop
|
||||
#endif
|
||||
|
||||
jump start_kernel ; Jump to start_kernel() in init/main.c.
|
||||
nop
|
||||
|
||||
.data
|
||||
etrax_irv:
|
||||
.dword 0
|
||||
|
||||
; Variables for communication with the Axis flash map driver (axisflashmap),
|
||||
; and for setting up memory in arch/cris/kernel/setup.c .
|
||||
|
||||
; romfs_start is set to the start of the root file system, if it exists
|
||||
; in directly accessible memory (i.e. NOR Flash when booting from Flash,
|
||||
; or RAM when booting directly from a network-downloaded RAM image)
|
||||
romfs_start:
|
||||
.dword 0
|
||||
|
||||
; romfs_length is set to the size of the root file system image, if it exists
|
||||
; in directly accessible memory (see romfs_start). Otherwise it is set to 0.
|
||||
romfs_length:
|
||||
.dword 0
|
||||
|
||||
; romfs_in_flash is set to 1 if the root file system resides in directly
|
||||
; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot
|
||||
; or NAND flash boot.
|
||||
romfs_in_flash:
|
||||
.dword 0
|
||||
crisv32_nand_boot:
|
||||
.dword 0
|
||||
crisv32_nand_cramfs_offset:
|
||||
|
||||
; nand_boot is set to 1 when the kernel has been booted from NAND flash
|
||||
nand_boot:
|
||||
.dword 0
|
||||
|
||||
swapper_pg_dir = 0xc0002000
|
||||
|
||||
.section ".init.data", "aw"
|
||||
|
||||
#include "../lib/hw_settings.S"
|
||||
#include "../mach/hw_settings.S"
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* Helper functions for I/O pins.
|
||||
*
|
||||
* Copyright (c) 2004 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
#include <asm/arch/hwregs/gio_defs.h>
|
||||
|
||||
struct crisv32_ioport crisv32_ioports[] =
|
||||
{
|
||||
{
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_oe),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pa_dout),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, r_pa_din),
|
||||
8
|
||||
},
|
||||
{
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_oe),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pb_dout),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, r_pb_din),
|
||||
18
|
||||
},
|
||||
{
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_oe),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pc_dout),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, r_pc_din),
|
||||
18
|
||||
},
|
||||
{
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_oe),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pd_dout),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, r_pd_din),
|
||||
18
|
||||
},
|
||||
{
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_oe),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, rw_pe_dout),
|
||||
(unsigned long*)REG_ADDR(gio, regi_gio, r_pe_din),
|
||||
18
|
||||
}
|
||||
};
|
||||
|
||||
#define NBR_OF_PORTS ARRAY_SIZE(crisv32_ioports)
|
||||
|
||||
struct crisv32_iopin crisv32_led1_green;
|
||||
struct crisv32_iopin crisv32_led1_red;
|
||||
struct crisv32_iopin crisv32_led2_green;
|
||||
struct crisv32_iopin crisv32_led2_red;
|
||||
struct crisv32_iopin crisv32_led3_green;
|
||||
struct crisv32_iopin crisv32_led3_red;
|
||||
|
||||
/* Dummy port used when green LED and red LED is on the same bit */
|
||||
static unsigned long io_dummy;
|
||||
static struct crisv32_ioport dummy_port =
|
||||
{
|
||||
&io_dummy,
|
||||
&io_dummy,
|
||||
&io_dummy,
|
||||
18
|
||||
};
|
||||
static struct crisv32_iopin dummy_led =
|
||||
{
|
||||
&dummy_port,
|
||||
0
|
||||
};
|
||||
|
||||
static int __init crisv32_io_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
/* Initialize LEDs */
|
||||
ret += crisv32_io_get_name(&crisv32_led1_green, CONFIG_ETRAX_LED1G);
|
||||
ret += crisv32_io_get_name(&crisv32_led1_red, CONFIG_ETRAX_LED1R);
|
||||
ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_LED2G);
|
||||
ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_LED2R);
|
||||
ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_LED3G);
|
||||
ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_LED3R);
|
||||
crisv32_io_set_dir(&crisv32_led1_green, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led1_red, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
|
||||
|
||||
if (!strcmp(CONFIG_ETRAX_LED1G, CONFIG_ETRAX_LED1R))
|
||||
crisv32_led1_red = dummy_led;
|
||||
if (!strcmp(CONFIG_ETRAX_LED2G, CONFIG_ETRAX_LED2R))
|
||||
crisv32_led2_red = dummy_led;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
__initcall(crisv32_io_init);
|
||||
|
||||
int crisv32_io_get(struct crisv32_iopin* iopin,
|
||||
unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port > NBR_OF_PORTS)
|
||||
return -EINVAL;
|
||||
if (port > crisv32_ioports[port].pin_count)
|
||||
return -EINVAL;
|
||||
|
||||
iopin->bit = 1 << pin;
|
||||
iopin->port = &crisv32_ioports[port];
|
||||
|
||||
if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crisv32_io_get_name(struct crisv32_iopin* iopin,
|
||||
char* name)
|
||||
{
|
||||
int port;
|
||||
int pin;
|
||||
|
||||
if (toupper(*name) == 'P')
|
||||
name++;
|
||||
|
||||
if (toupper(*name) < 'A' || toupper(*name) > 'E')
|
||||
return -EINVAL;
|
||||
|
||||
port = toupper(*name) - 'A';
|
||||
name++;
|
||||
pin = simple_strtoul(name, NULL, 10);
|
||||
|
||||
if (pin < 0 || pin > crisv32_ioports[port].pin_count)
|
||||
return -EINVAL;
|
||||
|
||||
iopin->bit = 1 << pin;
|
||||
iopin->port = &crisv32_ioports[port];
|
||||
|
||||
if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/* PCI I/O access stuff */
|
||||
struct cris_io_operations* cris_iops = NULL;
|
||||
EXPORT_SYMBOL(cris_iops);
|
||||
#endif
|
||||
|
|
@ -15,15 +15,21 @@
|
|||
#include <linux/threads.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/intr_vect.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
|
||||
#define CPU_FIXED -1
|
||||
|
||||
/* IRQ masks (refer to comment for crisv32_do_multiple) */
|
||||
#define TIMER_MASK (1 << (TIMER_INTR_VECT - FIRST_IRQ))
|
||||
#if TIMER0_INTR_VECT - FIRST_IRQ < 32
|
||||
#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ))
|
||||
#undef TIMER_VECT1
|
||||
#else
|
||||
#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32))
|
||||
#define TIMER_VECT1
|
||||
#endif
|
||||
#ifdef CONFIG_ETRAX_KGDB
|
||||
#if defined(CONFIG_ETRAX_KGDB_PORT0)
|
||||
#define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ))
|
||||
|
@ -44,8 +50,8 @@ struct cris_irq_allocation
|
|||
cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */
|
||||
};
|
||||
|
||||
struct cris_irq_allocation irq_allocations[NR_IRQS] =
|
||||
{[0 ... NR_IRQS - 1] = {0, CPU_MASK_ALL}};
|
||||
struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] =
|
||||
{ [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} };
|
||||
|
||||
static unsigned long irq_regs[NR_CPUS] =
|
||||
{
|
||||
|
@ -55,6 +61,12 @@ static unsigned long irq_regs[NR_CPUS] =
|
|||
#endif
|
||||
};
|
||||
|
||||
#if NR_REAL_IRQS > 32
|
||||
#define NBR_REGS 2
|
||||
#else
|
||||
#define NBR_REGS 1
|
||||
#endif
|
||||
|
||||
unsigned long cpu_irq_counters[NR_CPUS];
|
||||
unsigned long irq_counters[NR_REAL_IRQS];
|
||||
|
||||
|
@ -79,45 +91,81 @@ extern void d_mmu_write(void);
|
|||
extern void kgdb_init(void);
|
||||
extern void breakpoint(void);
|
||||
|
||||
/* From traps.c. */
|
||||
extern void breakh_BUG(void);
|
||||
|
||||
/*
|
||||
* Build the IRQ handler stubs using macros from irq.h. First argument is the
|
||||
* IRQ number, the second argument is the corresponding bit in
|
||||
* intr_rw_vect_mask found in asm/arch/hwregs/intr_vect_defs.h.
|
||||
* Build the IRQ handler stubs using macros from irq.h.
|
||||
*/
|
||||
BUILD_IRQ(0x31, (1 << 0)) /* memarb */
|
||||
BUILD_IRQ(0x32, (1 << 1)) /* gen_io */
|
||||
BUILD_IRQ(0x33, (1 << 2)) /* iop0 */
|
||||
BUILD_IRQ(0x34, (1 << 3)) /* iop1 */
|
||||
BUILD_IRQ(0x35, (1 << 4)) /* iop2 */
|
||||
BUILD_IRQ(0x36, (1 << 5)) /* iop3 */
|
||||
BUILD_IRQ(0x37, (1 << 6)) /* dma0 */
|
||||
BUILD_IRQ(0x38, (1 << 7)) /* dma1 */
|
||||
BUILD_IRQ(0x39, (1 << 8)) /* dma2 */
|
||||
BUILD_IRQ(0x3a, (1 << 9)) /* dma3 */
|
||||
BUILD_IRQ(0x3b, (1 << 10)) /* dma4 */
|
||||
BUILD_IRQ(0x3c, (1 << 11)) /* dma5 */
|
||||
BUILD_IRQ(0x3d, (1 << 12)) /* dma6 */
|
||||
BUILD_IRQ(0x3e, (1 << 13)) /* dma7 */
|
||||
BUILD_IRQ(0x3f, (1 << 14)) /* dma8 */
|
||||
BUILD_IRQ(0x40, (1 << 15)) /* dma9 */
|
||||
BUILD_IRQ(0x41, (1 << 16)) /* ata */
|
||||
BUILD_IRQ(0x42, (1 << 17)) /* sser0 */
|
||||
BUILD_IRQ(0x43, (1 << 18)) /* sser1 */
|
||||
BUILD_IRQ(0x44, (1 << 19)) /* ser0 */
|
||||
BUILD_IRQ(0x45, (1 << 20)) /* ser1 */
|
||||
BUILD_IRQ(0x46, (1 << 21)) /* ser2 */
|
||||
BUILD_IRQ(0x47, (1 << 22)) /* ser3 */
|
||||
BUILD_IRQ(0x48, (1 << 23))
|
||||
BUILD_IRQ(0x49, (1 << 24)) /* eth0 */
|
||||
BUILD_IRQ(0x4a, (1 << 25)) /* eth1 */
|
||||
BUILD_TIMER_IRQ(0x4b, (1 << 26))/* timer */
|
||||
BUILD_IRQ(0x4c, (1 << 27)) /* bif_arb */
|
||||
BUILD_IRQ(0x4d, (1 << 28)) /* bif_dma */
|
||||
BUILD_IRQ(0x4e, (1 << 29)) /* ext */
|
||||
BUILD_IRQ(0x4f, (1 << 29)) /* ipi */
|
||||
BUILD_IRQ(0x31)
|
||||
BUILD_IRQ(0x32)
|
||||
BUILD_IRQ(0x33)
|
||||
BUILD_IRQ(0x34)
|
||||
BUILD_IRQ(0x35)
|
||||
BUILD_IRQ(0x36)
|
||||
BUILD_IRQ(0x37)
|
||||
BUILD_IRQ(0x38)
|
||||
BUILD_IRQ(0x39)
|
||||
BUILD_IRQ(0x3a)
|
||||
BUILD_IRQ(0x3b)
|
||||
BUILD_IRQ(0x3c)
|
||||
BUILD_IRQ(0x3d)
|
||||
BUILD_IRQ(0x3e)
|
||||
BUILD_IRQ(0x3f)
|
||||
BUILD_IRQ(0x40)
|
||||
BUILD_IRQ(0x41)
|
||||
BUILD_IRQ(0x42)
|
||||
BUILD_IRQ(0x43)
|
||||
BUILD_IRQ(0x44)
|
||||
BUILD_IRQ(0x45)
|
||||
BUILD_IRQ(0x46)
|
||||
BUILD_IRQ(0x47)
|
||||
BUILD_IRQ(0x48)
|
||||
BUILD_IRQ(0x49)
|
||||
BUILD_IRQ(0x4a)
|
||||
BUILD_IRQ(0x4b)
|
||||
BUILD_IRQ(0x4c)
|
||||
BUILD_IRQ(0x4d)
|
||||
BUILD_IRQ(0x4e)
|
||||
BUILD_IRQ(0x4f)
|
||||
BUILD_IRQ(0x50)
|
||||
#if MACH_IRQS > 32
|
||||
BUILD_IRQ(0x51)
|
||||
BUILD_IRQ(0x52)
|
||||
BUILD_IRQ(0x53)
|
||||
BUILD_IRQ(0x54)
|
||||
BUILD_IRQ(0x55)
|
||||
BUILD_IRQ(0x56)
|
||||
BUILD_IRQ(0x57)
|
||||
BUILD_IRQ(0x58)
|
||||
BUILD_IRQ(0x59)
|
||||
BUILD_IRQ(0x5a)
|
||||
BUILD_IRQ(0x5b)
|
||||
BUILD_IRQ(0x5c)
|
||||
BUILD_IRQ(0x5d)
|
||||
BUILD_IRQ(0x5e)
|
||||
BUILD_IRQ(0x5f)
|
||||
BUILD_IRQ(0x60)
|
||||
BUILD_IRQ(0x61)
|
||||
BUILD_IRQ(0x62)
|
||||
BUILD_IRQ(0x63)
|
||||
BUILD_IRQ(0x64)
|
||||
BUILD_IRQ(0x65)
|
||||
BUILD_IRQ(0x66)
|
||||
BUILD_IRQ(0x67)
|
||||
BUILD_IRQ(0x68)
|
||||
BUILD_IRQ(0x69)
|
||||
BUILD_IRQ(0x6a)
|
||||
BUILD_IRQ(0x6b)
|
||||
BUILD_IRQ(0x6c)
|
||||
BUILD_IRQ(0x6d)
|
||||
BUILD_IRQ(0x6e)
|
||||
BUILD_IRQ(0x6f)
|
||||
BUILD_IRQ(0x70)
|
||||
#endif
|
||||
|
||||
/* Pointers to the low-level handlers. */
|
||||
static void (*interrupt[NR_IRQS])(void) = {
|
||||
static void (*interrupt[MACH_IRQS])(void) = {
|
||||
IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt,
|
||||
IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt,
|
||||
IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt,
|
||||
|
@ -128,7 +176,20 @@ static void (*interrupt[NR_IRQS])(void) = {
|
|||
IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt,
|
||||
IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt,
|
||||
IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt,
|
||||
IRQ0x4f_interrupt
|
||||
IRQ0x4f_interrupt, IRQ0x50_interrupt,
|
||||
#if MACH_IRQS > 32
|
||||
IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt,
|
||||
IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt,
|
||||
IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt,
|
||||
IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt,
|
||||
IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt,
|
||||
IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt,
|
||||
IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt,
|
||||
IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt,
|
||||
IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt,
|
||||
IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt,
|
||||
IRQ0x6f_interrupt, IRQ0x70_interrupt,
|
||||
#endif
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -137,13 +198,26 @@ block_irq(int irq, int cpu)
|
|||
int intr_mask;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irq_lock, flags);
|
||||
intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
|
||||
spin_lock_irqsave(&irq_lock, flags);
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
|
||||
rw_mask, 0);
|
||||
else
|
||||
intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
|
||||
rw_mask, 1);
|
||||
|
||||
/* Remember; 1 let through, 0 block. */
|
||||
intr_mask &= ~(1 << (irq - FIRST_IRQ));
|
||||
/* Remember; 1 let thru, 0 block. */
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
intr_mask &= ~(1 << (irq - FIRST_IRQ));
|
||||
else
|
||||
intr_mask &= ~(1 << (irq - FIRST_IRQ - 32));
|
||||
|
||||
REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
|
||||
0, intr_mask);
|
||||
else
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
|
||||
1, intr_mask);
|
||||
spin_unlock_irqrestore(&irq_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -154,12 +228,26 @@ unblock_irq(int irq, int cpu)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&irq_lock, flags);
|
||||
intr_mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
|
||||
rw_mask, 0);
|
||||
else
|
||||
intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
|
||||
rw_mask, 1);
|
||||
|
||||
/* Remember; 1 let through, 0 block. */
|
||||
intr_mask |= (1 << (irq - FIRST_IRQ));
|
||||
/* Remember; 1 let thru, 0 block. */
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
intr_mask |= (1 << (irq - FIRST_IRQ));
|
||||
else
|
||||
intr_mask |= (1 << (irq - FIRST_IRQ - 32));
|
||||
|
||||
if (irq - FIRST_IRQ < 32)
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
|
||||
0, intr_mask);
|
||||
else
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask,
|
||||
1, intr_mask);
|
||||
|
||||
REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, intr_mask);
|
||||
spin_unlock_irqrestore(&irq_lock, flags);
|
||||
}
|
||||
|
||||
|
@ -298,8 +386,9 @@ crisv32_do_multiple(struct pt_regs* regs)
|
|||
{
|
||||
int cpu;
|
||||
int mask;
|
||||
int masked;
|
||||
int masked[NBR_REGS];
|
||||
int bit;
|
||||
int i;
|
||||
|
||||
cpu = smp_processor_id();
|
||||
|
||||
|
@ -308,42 +397,59 @@ crisv32_do_multiple(struct pt_regs* regs)
|
|||
*/
|
||||
irq_enter();
|
||||
|
||||
/* Get which IRQs that happened. */
|
||||
masked = REG_RD_INT(intr_vect, irq_regs[cpu], r_masked_vect);
|
||||
for (i = 0; i < NBR_REGS; i++) {
|
||||
/* Get which IRQs that happend. */
|
||||
masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu],
|
||||
r_masked_vect, i);
|
||||
|
||||
/* Calculate new IRQ mask with these IRQs disabled. */
|
||||
mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
|
||||
mask &= ~masked;
|
||||
/* Calculate new IRQ mask with these IRQs disabled. */
|
||||
mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
|
||||
mask &= ~masked[i];
|
||||
|
||||
/* Timer IRQ is never masked */
|
||||
if (masked & TIMER_MASK)
|
||||
mask |= TIMER_MASK;
|
||||
|
||||
/* Block all the IRQs */
|
||||
REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
|
||||
#ifdef TIMER_VECT1
|
||||
if ((i == 1) && (masked[0] & TIMER_MASK))
|
||||
mask |= TIMER_MASK;
|
||||
#else
|
||||
if ((i == 0) && (masked[0] & TIMER_MASK))
|
||||
mask |= TIMER_MASK;
|
||||
#endif
|
||||
/* Block all the IRQs */
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
|
||||
|
||||
/* Check for timer IRQ and handle it special. */
|
||||
if (masked & TIMER_MASK) {
|
||||
masked &= ~TIMER_MASK;
|
||||
do_IRQ(TIMER_INTR_VECT, regs);
|
||||
#ifdef TIMER_VECT1
|
||||
if ((i == 1) && (masked[i] & TIMER_MASK)) {
|
||||
masked[i] &= ~TIMER_MASK;
|
||||
do_IRQ(TIMER0_INTR_VECT, regs);
|
||||
}
|
||||
#else
|
||||
if ((i == 0) && (masked[i] & TIMER_MASK)) {
|
||||
masked[i] &= ~TIMER_MASK;
|
||||
do_IRQ(TIMER0_INTR_VECT, regs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IGNORE_MASK
|
||||
/* Remove IRQs that can't be handled as multiple. */
|
||||
masked &= ~IGNORE_MASK;
|
||||
masked[0] &= ~IGNORE_MASK;
|
||||
#endif
|
||||
|
||||
/* Handle the rest of the IRQs. */
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (masked & (1 << bit))
|
||||
do_IRQ(bit + FIRST_IRQ, regs);
|
||||
for (i = 0; i < NBR_REGS; i++) {
|
||||
for (bit = 0; bit < 32; bit++) {
|
||||
if (masked[i] & (1 << bit))
|
||||
do_IRQ(bit + FIRST_IRQ + i*32, regs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unblock all the IRQs. */
|
||||
mask = REG_RD_INT(intr_vect, irq_regs[cpu], rw_mask);
|
||||
mask |= masked;
|
||||
REG_WR_INT(intr_vect, irq_regs[cpu], rw_mask, mask);
|
||||
for (i = 0; i < NBR_REGS; i++) {
|
||||
mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i);
|
||||
mask |= masked[i];
|
||||
REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask);
|
||||
}
|
||||
|
||||
/* This irq_exit() will trigger the soft IRQs. */
|
||||
irq_exit();
|
||||
|
@ -361,20 +467,21 @@ init_IRQ(void)
|
|||
reg_intr_vect_rw_mask vect_mask = {0};
|
||||
|
||||
/* Clear all interrupts masks. */
|
||||
REG_WR(intr_vect, regi_irq, rw_mask, vect_mask);
|
||||
for (i = 0; i < NBR_REGS; i++)
|
||||
REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask);
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
etrax_irv->v[i] = weird_irq;
|
||||
|
||||
/* Point all IRQs to bad handlers. */
|
||||
/* Point all IRQ's to bad handlers. */
|
||||
for (i = FIRST_IRQ, j = 0; j < NR_IRQS; i++, j++) {
|
||||
irq_desc[j].chip = &crisv32_irq_type;
|
||||
set_exception_vector(i, interrupt[j]);
|
||||
}
|
||||
|
||||
/* Mark Timer and IPI IRQs as CPU local */
|
||||
irq_allocations[TIMER_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
|
||||
irq_desc[TIMER_INTR_VECT].status |= IRQ_PER_CPU;
|
||||
irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
|
||||
irq_desc[TIMER0_INTR_VECT].status |= IRQ_PER_CPU;
|
||||
irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED;
|
||||
irq_desc[IPI_INTR_VECT].status |= IRQ_PER_CPU;
|
||||
|
||||
|
@ -391,6 +498,11 @@ init_IRQ(void)
|
|||
set_exception_vector(0x0a, d_mmu_access);
|
||||
set_exception_vector(0x0b, d_mmu_write);
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
/* Break 14 handler, used to implement cheap BUG(). */
|
||||
set_exception_vector(0x1e, breakh_BUG);
|
||||
#endif
|
||||
|
||||
/* The system-call trap is reached by "break 13". */
|
||||
set_exception_vector(0x1d, system_call);
|
||||
|
||||
|
|
|
@ -381,7 +381,7 @@ static int read_register(char regno, unsigned int *valptr);
|
|||
/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
|
||||
int getDebugChar(void);
|
||||
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
#ifdef CONFIG_ETRAX_VCS_SIM
|
||||
int getDebugChar(void)
|
||||
{
|
||||
return socketread();
|
||||
|
@ -391,7 +391,7 @@ int getDebugChar(void)
|
|||
/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
|
||||
void putDebugChar(int val);
|
||||
|
||||
#ifdef CONFIG_ETRAXFS_SIM
|
||||
#ifdef CONFIG_ETRAX_VCS_SIM
|
||||
void putDebugChar(int val)
|
||||
{
|
||||
socketwrite((char *)&val, 1);
|
||||
|
@ -1599,7 +1599,7 @@ kgdb_init(void)
|
|||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
|
||||
ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask);
|
||||
ser_intr_mask.data_avail = regk_ser_yes;
|
||||
ser_intr_mask.dav = regk_ser_yes;
|
||||
REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask);
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT1)
|
||||
/* Note: no shortcut registered (not handled by multiple_interrupt).
|
||||
|
@ -1611,7 +1611,7 @@ kgdb_init(void)
|
|||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
|
||||
ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask);
|
||||
ser_intr_mask.data_avail = regk_ser_yes;
|
||||
ser_intr_mask.dav = regk_ser_yes;
|
||||
REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask);
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT2)
|
||||
/* Note: no shortcut registered (not handled by multiple_interrupt).
|
||||
|
@ -1623,7 +1623,7 @@ kgdb_init(void)
|
|||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
|
||||
ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask);
|
||||
ser_intr_mask.data_avail = regk_ser_yes;
|
||||
ser_intr_mask.dav = regk_ser_yes;
|
||||
REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask);
|
||||
#elif defined(CONFIG_ETRAX_KGDB_PORT3)
|
||||
/* Note: no shortcut registered (not handled by multiple_interrupt).
|
||||
|
@ -1635,7 +1635,7 @@ kgdb_init(void)
|
|||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
|
||||
ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask);
|
||||
ser_intr_mask.data_avail = regk_ser_yes;
|
||||
ser_intr_mask.dav = regk_ser_yes;
|
||||
REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -12,17 +12,13 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/timer_defs.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/timer_defs.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
|
||||
extern void stop_watchdog(void);
|
||||
|
||||
#ifdef CONFIG_ETRAX_GPIO
|
||||
extern void etrax_gpio_wake_up_check(void); /* Defined in drivers/gpio.c. */
|
||||
#endif
|
||||
|
||||
extern int cris_hlt_counter;
|
||||
|
||||
/* We use this if we don't have any better idle routine. */
|
||||
|
@ -82,7 +78,7 @@ hard_reset_now(void)
|
|||
wd_ctrl.cmd = regk_timer_start;
|
||||
|
||||
arch_enable_nmi();
|
||||
REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
|
||||
REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2000-2003, Axis Communications AB.
|
||||
* Copyright (C) 2000-2007, Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -149,7 +149,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
ret = generic_ptrace_pokedata(child, addr, data);
|
||||
break;
|
||||
|
||||
/* Write the word at location address in the USER area. */
|
||||
/* Write the word at location address in the USER area. */
|
||||
case PTRACE_POKEUSR:
|
||||
ret = -EIO;
|
||||
if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
|
||||
|
@ -201,7 +201,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
|
||||
break;
|
||||
|
||||
/* Make the child exit by sending it a sigkill. */
|
||||
/* Make the child exit by sending it a sigkill. */
|
||||
case PTRACE_KILL:
|
||||
ret = 0;
|
||||
|
||||
|
@ -245,9 +245,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
break;
|
||||
|
||||
}
|
||||
|
||||
/* Get all GP registers from the child. */
|
||||
case PTRACE_GETREGS: {
|
||||
int i;
|
||||
int i;
|
||||
unsigned long tmp;
|
||||
|
||||
for (i = 0; i <= PT_MAX; i++) {
|
||||
|
@ -294,6 +295,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
break;
|
||||
}
|
||||
|
||||
out_tsk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ struct rt_signal_frame {
|
|||
unsigned char retcode[8]; /* Trampoline code. */
|
||||
};
|
||||
|
||||
int do_signal(int restart, sigset_t *oldset, struct pt_regs *regs);
|
||||
void do_signal(int restart, struct pt_regs *regs);
|
||||
void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
|
||||
struct pt_regs *regs);
|
||||
/*
|
||||
|
@ -61,74 +61,16 @@ int
|
|||
sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
|
||||
long srp, struct pt_regs *regs)
|
||||
{
|
||||
sigset_t saveset;
|
||||
|
||||
mask &= _BLOCKABLE;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
|
||||
saveset = current->blocked;
|
||||
|
||||
current->saved_sigmask = current->blocked;
|
||||
siginitset(¤t->blocked, mask);
|
||||
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
regs->r10 = -EINTR;
|
||||
|
||||
while (1) {
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
|
||||
if (do_signal(0, &saveset, regs)) {
|
||||
/*
|
||||
* This point is reached twice: once to call
|
||||
* the signal handler, then again to return
|
||||
* from the sigsuspend system call. When
|
||||
* calling the signal handler, R10 hold the
|
||||
* signal number as set by do_signal(). The
|
||||
* sigsuspend call will always return with
|
||||
* the restored value above; -EINTR.
|
||||
*/
|
||||
return regs->r10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Define some dummy arguments to be able to reach the regs argument. */
|
||||
int
|
||||
sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13,
|
||||
long mof, long srp, struct pt_regs *regs)
|
||||
{
|
||||
sigset_t saveset;
|
||||
sigset_t newset;
|
||||
|
||||
if (sigsetsize != sizeof(sigset_t))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&newset, unewset, sizeof(newset)))
|
||||
return -EFAULT;
|
||||
|
||||
sigdelsetmask(&newset, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
|
||||
saveset = current->blocked;
|
||||
current->blocked = newset;
|
||||
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
regs->r10 = -EINTR;
|
||||
|
||||
while (1) {
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
|
||||
if (do_signal(0, &saveset, regs)) {
|
||||
/* See comment in function above. */
|
||||
return regs->r10;
|
||||
}
|
||||
}
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
set_thread_flag(TIF_RESTORE_SIGMASK);
|
||||
return -ERESTARTNOHAND;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -290,7 +232,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
|
|||
goto badframe;
|
||||
|
||||
if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT)
|
||||
goto badframe;
|
||||
goto badframe;
|
||||
|
||||
keep_debug_flags(oldccs, oldspc, regs);
|
||||
|
||||
|
@ -347,11 +289,11 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
|
|||
/* Grab and setup a signal frame.
|
||||
*
|
||||
* Basically a lot of state-info is stacked, and arranged for the
|
||||
* user-mode program to return to the kernel using either a trampoline
|
||||
* user-mode program to return to the kernel using either a trampiline
|
||||
* which performs the syscall sigreturn(), or a provided user-mode
|
||||
* trampoline.
|
||||
*/
|
||||
static void
|
||||
static int
|
||||
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
||||
struct pt_regs * regs)
|
||||
{
|
||||
|
@ -417,16 +359,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|||
/* Actually move the USP to reflect the stacked frame. */
|
||||
wrusp((unsigned long)frame);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == SIGSEGV)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
sigset_t *set, struct pt_regs * regs)
|
||||
{
|
||||
|
@ -503,21 +446,24 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|||
/* Actually move the usp to reflect the stacked frame. */
|
||||
wrusp((unsigned long)frame);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
give_sigsegv:
|
||||
if (sig == SIGSEGV)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
|
||||
force_sig(SIGSEGV, current);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Invoke a singal handler to, well, handle the signal. */
|
||||
static inline void
|
||||
static inline int
|
||||
handle_signal(int canrestart, unsigned long sig,
|
||||
siginfo_t *info, struct k_sigaction *ka,
|
||||
sigset_t *oldset, struct pt_regs * regs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Check if this got called from a system call. */
|
||||
if (canrestart) {
|
||||
/* If so, check system call restarting. */
|
||||
|
@ -561,19 +507,24 @@ handle_signal(int canrestart, unsigned long sig,
|
|||
|
||||
/* Set up the stack frame. */
|
||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||
setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
||||
else
|
||||
setup_frame(sig, ka, oldset, regs);
|
||||
ret = setup_frame(sig, ka, oldset, regs);
|
||||
|
||||
if (ka->sa.sa_flags & SA_ONESHOT)
|
||||
ka->sa.sa_handler = SIG_DFL;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -587,12 +538,13 @@ handle_signal(int canrestart, unsigned long sig,
|
|||
* we can use user_mode(regs) to see if we came directly from kernel or user
|
||||
* mode below.
|
||||
*/
|
||||
int
|
||||
do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
|
||||
void
|
||||
do_signal(int canrestart, struct pt_regs *regs)
|
||||
{
|
||||
int signr;
|
||||
siginfo_t info;
|
||||
struct k_sigaction ka;
|
||||
sigset_t *oldset;
|
||||
|
||||
/*
|
||||
* The common case should go fast, which is why this point is
|
||||
|
@ -600,17 +552,28 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
|
|||
* without doing anything.
|
||||
*/
|
||||
if (!user_mode(regs))
|
||||
return 1;
|
||||
return;
|
||||
|
||||
if (!oldset)
|
||||
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) {
|
||||
/* Deliver the signal. */
|
||||
handle_signal(canrestart, signr, &info, &ka, oldset, regs);
|
||||
return 1;
|
||||
/* Whee! Actually deliver the signal. */
|
||||
if (handle_signal(canrestart, signr, &info, &ka,
|
||||
oldset, regs)) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Got here from a system call? */
|
||||
|
@ -628,7 +591,12 @@ do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
|
|||
}
|
||||
}
|
||||
|
||||
return 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);
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage void
|
||||
|
@ -641,7 +609,7 @@ ugdb_trap_user(struct thread_info *ti, int sig)
|
|||
user_regs(ti)->spc = 0;
|
||||
}
|
||||
/* FIXME: Filter out false h/w breakpoint hits (i.e. EDA
|
||||
not within any configured h/w breakpoint range). Synchronize with
|
||||
not withing any configured h/w breakpoint range). Synchronize with
|
||||
what already exists for kernel debugging. */
|
||||
if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) {
|
||||
/* Break 8: subtract 2 from ERP unless in a delay slot. */
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <linux/types.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/arch/irq.h>
|
||||
#include <asm/arch/hwregs/intr_vect.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <irq.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/arch/hwregs/mmu_defs_asm.h>
|
||||
#include <asm/arch/hwregs/supp_reg.h>
|
||||
#include <hwregs/asm/mmu_defs_asm.h>
|
||||
#include <hwregs/supp_reg.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include <linux/err.h>
|
||||
|
@ -20,6 +21,7 @@
|
|||
#define IPI_SCHEDULE 1
|
||||
#define IPI_CALL 2
|
||||
#define IPI_FLUSH_TLB 4
|
||||
#define IPI_BOOT 8
|
||||
|
||||
#define FLUSH_ALL (void*)0xffffffff
|
||||
|
||||
|
@ -30,6 +32,8 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED};
|
|||
cpumask_t cpu_online_map = CPU_MASK_NONE;
|
||||
EXPORT_SYMBOL(cpu_online_map);
|
||||
cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
|
||||
cpumask_t cpu_possible_map;
|
||||
EXPORT_SYMBOL(cpu_possible_map);
|
||||
EXPORT_SYMBOL(phys_cpu_present_map);
|
||||
|
||||
/* Variables used during SMP boot */
|
||||
|
@ -55,13 +59,12 @@ static unsigned long flush_addr;
|
|||
extern int setup_irq(int, struct irqaction *);
|
||||
|
||||
/* Mode registers */
|
||||
static unsigned long irq_regs[NR_CPUS] =
|
||||
{
|
||||
static unsigned long irq_regs[NR_CPUS] = {
|
||||
regi_irq,
|
||||
regi_irq2
|
||||
};
|
||||
|
||||
static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
||||
static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id);
|
||||
static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
|
||||
static struct irqaction irq_ipi = {
|
||||
.handler = crisv32_ipi_interrupt,
|
||||
|
@ -101,6 +104,7 @@ void __devinit smp_prepare_boot_cpu(void)
|
|||
|
||||
cpu_set(0, cpu_online_map);
|
||||
cpu_set(0, phys_cpu_present_map);
|
||||
cpu_set(0, cpu_possible_map);
|
||||
}
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
|
@ -113,6 +117,7 @@ smp_boot_one_cpu(int cpuid)
|
|||
{
|
||||
unsigned timeout;
|
||||
struct task_struct *idle;
|
||||
cpumask_t cpu_mask = CPU_MASK_NONE;
|
||||
|
||||
idle = fork_idle(cpuid);
|
||||
if (IS_ERR(idle))
|
||||
|
@ -124,6 +129,12 @@ smp_boot_one_cpu(int cpuid)
|
|||
smp_init_current_idle_thread = task_thread_info(idle);
|
||||
cpu_now_booting = cpuid;
|
||||
|
||||
/* Kick it */
|
||||
cpu_set(cpuid, cpu_online_map);
|
||||
cpu_set(cpuid, cpu_mask);
|
||||
send_ipi(IPI_BOOT, 0, cpu_mask);
|
||||
cpu_clear(cpuid, cpu_online_map);
|
||||
|
||||
/* Wait for CPU to come online */
|
||||
for (timeout = 0; timeout < 10000; timeout++) {
|
||||
if(cpu_online(cpuid)) {
|
||||
|
@ -165,7 +176,7 @@ void __init smp_callin(void)
|
|||
/* Enable IRQ and idle */
|
||||
REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
|
||||
unmask_irq(IPI_INTR_VECT);
|
||||
unmask_irq(TIMER_INTR_VECT);
|
||||
unmask_irq(TIMER0_INTR_VECT);
|
||||
preempt_disable();
|
||||
local_irq_enable();
|
||||
|
||||
|
@ -328,7 +339,7 @@ int smp_call_function(void (*func)(void *info), void *info,
|
|||
return ret;
|
||||
}
|
||||
|
||||
irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
void (*func) (void *info) = call_data->func;
|
||||
void *info = call_data->info;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* $Id: time.c,v 1.19 2005/04/29 05:40:09 starvik Exp $
|
||||
*
|
||||
/*
|
||||
* linux/arch/cris/arch-v32/kernel/time.c
|
||||
*
|
||||
* Copyright (C) 2003 Axis Communications AB
|
||||
* Copyright (C) 2003-2007 Axis Communications AB
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -14,28 +13,34 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/threads.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/timer_defs.h>
|
||||
#include <asm/arch/hwregs/intr_vect_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/timer_defs.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
#ifdef CONFIG_CRIS_MACH_ARTPEC3
|
||||
#include <hwregs/clkgen_defs.h>
|
||||
#endif
|
||||
|
||||
/* Watchdog defines */
|
||||
#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
|
||||
#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */
|
||||
#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) /* Number of 763 counts before watchdog bites */
|
||||
#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */
|
||||
#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */
|
||||
/* Number of 763 counts before watchdog bites */
|
||||
#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1)
|
||||
|
||||
unsigned long timer_regs[NR_CPUS] =
|
||||
{
|
||||
regi_timer,
|
||||
regi_timer0,
|
||||
#ifdef CONFIG_SMP
|
||||
regi_timer2
|
||||
regi_timer2
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -44,12 +49,22 @@ extern int set_rtc_mmss(unsigned long nowtime);
|
|||
extern int setup_irq(int, struct irqaction *);
|
||||
extern int have_rtc;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static int
|
||||
cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data);
|
||||
|
||||
static struct notifier_block cris_time_freq_notifier_block = {
|
||||
.notifier_call = cris_time_freq_notifier,
|
||||
};
|
||||
#endif
|
||||
|
||||
unsigned long get_ns_in_jiffie(void)
|
||||
{
|
||||
reg_timer_r_tmr0_data data;
|
||||
unsigned long ns;
|
||||
|
||||
data = REG_RD(timer, regi_timer, r_tmr0_data);
|
||||
data = REG_RD(timer, regi_timer0, r_tmr0_data);
|
||||
ns = (TIMER0_DIV - data) * 10;
|
||||
return ns;
|
||||
}
|
||||
|
@ -59,31 +74,27 @@ unsigned long do_slow_gettimeoffset(void)
|
|||
unsigned long count;
|
||||
unsigned long usec_count = 0;
|
||||
|
||||
static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */
|
||||
/* For the first call after boot */
|
||||
static unsigned long count_p = TIMER0_DIV;
|
||||
static unsigned long jiffies_p = 0;
|
||||
|
||||
/*
|
||||
* cache volatile jiffies temporarily; we have IRQs turned off.
|
||||
*/
|
||||
/* Cache volatile jiffies temporarily; we have IRQs turned off. */
|
||||
unsigned long jiffies_t;
|
||||
|
||||
/* The timer interrupt comes from Etrax timer 0. In order to get
|
||||
* better precision, we check the current value. It might have
|
||||
* underflowed already though.
|
||||
*/
|
||||
* underflowed already though. */
|
||||
count = REG_RD(timer, regi_timer0, r_tmr0_data);
|
||||
jiffies_t = jiffies;
|
||||
|
||||
count = REG_RD(timer, regi_timer, r_tmr0_data);
|
||||
jiffies_t = jiffies;
|
||||
|
||||
/*
|
||||
* avoiding timer inconsistencies (they are rare, but they happen)...
|
||||
* there are one problem that must be avoided here:
|
||||
* 1. the timer counter underflows
|
||||
/* Avoiding timer inconsistencies (they are rare, but they happen)
|
||||
* There is one problem that must be avoided here:
|
||||
* 1. the timer counter underflows
|
||||
*/
|
||||
if( jiffies_t == jiffies_p ) {
|
||||
if( count > count_p ) {
|
||||
/* Timer wrapped, use new count and prescale
|
||||
* increase the time corresponding to one jiffie
|
||||
/* Timer wrapped, use new count and prescale.
|
||||
* Increase the time corresponding to one jiffy.
|
||||
*/
|
||||
usec_count = 1000000/HZ;
|
||||
}
|
||||
|
@ -106,17 +117,15 @@ unsigned long do_slow_gettimeoffset(void)
|
|||
*/
|
||||
/* This gives us 1.3 ms to do something useful when the NMI comes */
|
||||
|
||||
/* right now, starting the watchdog is the same as resetting it */
|
||||
/* Right now, starting the watchdog is the same as resetting it */
|
||||
#define start_watchdog reset_watchdog
|
||||
|
||||
#if defined(CONFIG_ETRAX_WATCHDOG)
|
||||
static short int watchdog_key = 42; /* arbitrary 7 bit number */
|
||||
#endif
|
||||
|
||||
/* number of pages to consider "out of memory". it is normal that the memory
|
||||
* is used though, so put this really low.
|
||||
*/
|
||||
|
||||
/* Number of pages to consider "out of memory". It is normal that the memory
|
||||
* is used though, so set this really low. */
|
||||
#define WATCHDOG_MIN_FREE_PAGES 8
|
||||
|
||||
void
|
||||
|
@ -125,14 +134,15 @@ reset_watchdog(void)
|
|||
#if defined(CONFIG_ETRAX_WATCHDOG)
|
||||
reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
|
||||
|
||||
/* only keep watchdog happy as long as we have memory left! */
|
||||
/* Only keep watchdog happy as long as we have memory left! */
|
||||
if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
|
||||
/* reset the watchdog with the inverse of the old key */
|
||||
watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */
|
||||
/* Reset the watchdog with the inverse of the old key */
|
||||
/* Invert key, which is 7 bits */
|
||||
watchdog_key ^= ETRAX_WD_KEY_MASK;
|
||||
wd_ctrl.cnt = ETRAX_WD_CNT;
|
||||
wd_ctrl.cmd = regk_timer_start;
|
||||
wd_ctrl.key = watchdog_key;
|
||||
REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
|
||||
REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -148,7 +158,7 @@ stop_watchdog(void)
|
|||
wd_ctrl.cnt = ETRAX_WD_CNT;
|
||||
wd_ctrl.cmd = regk_timer_stop;
|
||||
wd_ctrl.key = watchdog_key;
|
||||
REG_WR(timer, regi_timer, rw_wd_ctrl, wd_ctrl);
|
||||
REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -160,17 +170,28 @@ handle_watchdog_bite(struct pt_regs* regs)
|
|||
#if defined(CONFIG_ETRAX_WATCHDOG)
|
||||
extern int cause_of_death;
|
||||
|
||||
raw_printk("Watchdog bite\n");
|
||||
oops_in_progress = 1;
|
||||
printk(KERN_WARNING "Watchdog bite\n");
|
||||
|
||||
/* Check if forced restart or unexpected watchdog */
|
||||
if (cause_of_death == 0xbedead) {
|
||||
#ifdef CONFIG_CRIS_MACH_ARTPEC3
|
||||
/* There is a bug in Artpec-3 (voodoo TR 78) that requires
|
||||
* us to go to lower frequency for the reset to be reliable
|
||||
*/
|
||||
reg_clkgen_rw_clk_ctrl ctrl =
|
||||
REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
ctrl.pll = 0;
|
||||
REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl);
|
||||
#endif
|
||||
while(1);
|
||||
}
|
||||
|
||||
/* Unexpected watchdog, stop the watchdog and dump registers*/
|
||||
/* Unexpected watchdog, stop the watchdog and dump registers. */
|
||||
stop_watchdog();
|
||||
raw_printk("Oops: bitten by watchdog\n");
|
||||
show_registers(regs);
|
||||
printk(KERN_WARNING "Oops: bitten by watchdog\n");
|
||||
show_registers(regs);
|
||||
oops_in_progress = 0;
|
||||
#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
reset_watchdog();
|
||||
#endif
|
||||
|
@ -178,21 +199,19 @@ handle_watchdog_bite(struct pt_regs* regs)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* last time the cmos clock got updated */
|
||||
/* Last time the cmos clock got updated. */
|
||||
static long last_rtc_update = 0;
|
||||
|
||||
/*
|
||||
* timer_interrupt() needs to keep up the real-time clock,
|
||||
* as well as call the "do_timer()" routine every clocktick
|
||||
* as well as call the "do_timer()" routine every clocktick.
|
||||
*/
|
||||
|
||||
//static unsigned short myjiff; /* used by our debug routine print_timestamp */
|
||||
|
||||
extern void cris_do_profile(struct pt_regs *regs);
|
||||
|
||||
static inline irqreturn_t
|
||||
timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct pt_regs *regs = get_irq_regs();
|
||||
int cpu = smp_processor_id();
|
||||
reg_timer_r_masked_intr masked_intr;
|
||||
reg_timer_rw_ack_intr ack_intr = { 0 };
|
||||
|
@ -202,11 +221,11 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
if (!masked_intr.tmr0)
|
||||
return IRQ_NONE;
|
||||
|
||||
/* acknowledge the timer irq */
|
||||
/* Acknowledge the timer irq. */
|
||||
ack_intr.tmr0 = 1;
|
||||
REG_WR(timer, timer_regs[cpu], rw_ack_intr, ack_intr);
|
||||
|
||||
/* reset watchdog otherwise it resets us! */
|
||||
/* Reset watchdog otherwise it resets us! */
|
||||
reset_watchdog();
|
||||
|
||||
/* Update statistics. */
|
||||
|
@ -218,7 +237,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
if (cpu != 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* call the real timer interrupt handler */
|
||||
/* Call the real timer interrupt handler */
|
||||
do_timer(1);
|
||||
|
||||
/*
|
||||
|
@ -236,17 +255,17 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|||
if (set_rtc_mmss(xtime.tv_sec) == 0)
|
||||
last_rtc_update = xtime.tv_sec;
|
||||
else
|
||||
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
|
||||
/* Do it again in 60 s */
|
||||
last_rtc_update = xtime.tv_sec - 600;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain
|
||||
* it needs to be IRQF_DISABLED to make the jiffies update work properly
|
||||
/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain.
|
||||
* It needs to be IRQF_DISABLED to make the jiffies update work properly.
|
||||
*/
|
||||
|
||||
static struct irqaction irq_timer = {
|
||||
.mask = timer_interrupt,
|
||||
static struct irqaction irq_timer = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_SHARED | IRQF_DISABLED,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "timer"
|
||||
|
@ -256,27 +275,27 @@ void __init
|
|||
cris_timer_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
|
||||
reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
|
||||
reg_timer_rw_tmr0_ctrl tmr0_ctrl = { 0 };
|
||||
reg_timer_rw_tmr0_div tmr0_div = TIMER0_DIV;
|
||||
reg_timer_rw_intr_mask timer_intr_mask;
|
||||
|
||||
/* Setup the etrax timers
|
||||
/* Setup the etrax timers.
|
||||
* Base frequency is 100MHz, divider 1000000 -> 100 HZ
|
||||
* We use timer0, so timer1 is free.
|
||||
* The trig timer is used by the fasttimer API if enabled.
|
||||
*/
|
||||
|
||||
tmr0_ctrl.op = regk_timer_ld;
|
||||
tmr0_ctrl.op = regk_timer_ld;
|
||||
tmr0_ctrl.freq = regk_timer_f100;
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
|
||||
tmr0_ctrl.op = regk_timer_run;
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_div, tmr0_div);
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Load */
|
||||
tmr0_ctrl.op = regk_timer_run;
|
||||
REG_WR(timer, timer_regs[cpu], rw_tmr0_ctrl, tmr0_ctrl); /* Start */
|
||||
|
||||
/* enable the timer irq */
|
||||
timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
|
||||
timer_intr_mask.tmr0 = 1;
|
||||
REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
|
||||
/* Enable the timer irq. */
|
||||
timer_intr_mask = REG_RD(timer, timer_regs[cpu], rw_intr_mask);
|
||||
timer_intr_mask.tmr0 = 1;
|
||||
REG_WR(timer, timer_regs[cpu], rw_intr_mask, timer_intr_mask);
|
||||
}
|
||||
|
||||
void __init
|
||||
|
@ -284,7 +303,7 @@ time_init(void)
|
|||
{
|
||||
reg_intr_vect_rw_mask intr_mask;
|
||||
|
||||
/* probe for the RTC and read it if it exists
|
||||
/* Probe for the RTC and read it if it exists.
|
||||
* Before the RTC can be probed the loops_per_usec variable needs
|
||||
* to be initialized to make usleep work. A better value for
|
||||
* loops_per_usec is calculated by the kernel later once the
|
||||
|
@ -293,52 +312,74 @@ time_init(void)
|
|||
loops_per_usec = 50;
|
||||
|
||||
if(RTC_INIT() < 0) {
|
||||
/* no RTC, start at 1980 */
|
||||
/* No RTC, start at 1980 */
|
||||
xtime.tv_sec = 0;
|
||||
xtime.tv_nsec = 0;
|
||||
have_rtc = 0;
|
||||
} else {
|
||||
/* get the current time */
|
||||
/* Get the current time */
|
||||
have_rtc = 1;
|
||||
update_xtime_from_cmos();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
|
||||
* tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
|
||||
* Initialize wall_to_monotonic such that adding it to
|
||||
* xtime will yield zero, the tv_nsec field must be normalized
|
||||
* (i.e., 0 <= nsec < NSEC_PER_SEC).
|
||||
*/
|
||||
set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
|
||||
|
||||
/* Start CPU local timer */
|
||||
/* Start CPU local timer. */
|
||||
cris_timer_init();
|
||||
|
||||
/* enable the timer irq in global config */
|
||||
intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
|
||||
intr_mask.timer = 1;
|
||||
REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
|
||||
/* Enable the timer irq in global config. */
|
||||
intr_mask = REG_RD_VECT(intr_vect, regi_irq, rw_mask, 1);
|
||||
intr_mask.timer0 = 1;
|
||||
REG_WR_VECT(intr_vect, regi_irq, rw_mask, 1, intr_mask);
|
||||
|
||||
/* now actually register the timer irq handler that calls timer_interrupt() */
|
||||
/* Now actually register the timer irq handler that calls
|
||||
* timer_interrupt(). */
|
||||
setup_irq(TIMER0_INTR_VECT, &irq_timer);
|
||||
|
||||
setup_irq(TIMER_INTR_VECT, &irq_timer);
|
||||
|
||||
/* enable watchdog if we should use one */
|
||||
/* Enable watchdog if we should use one. */
|
||||
|
||||
#if defined(CONFIG_ETRAX_WATCHDOG)
|
||||
printk("Enabling watchdog...\n");
|
||||
printk(KERN_INFO "Enabling watchdog...\n");
|
||||
start_watchdog();
|
||||
|
||||
/* If we use the hardware watchdog, we want to trap it as an NMI
|
||||
and dump registers before it resets us. For this to happen, we
|
||||
must set the "m" NMI enable flag (which once set, is unset only
|
||||
when an NMI is taken).
|
||||
* and dump registers before it resets us. For this to happen, we
|
||||
* must set the "m" NMI enable flag (which once set, is unset only
|
||||
* when an NMI is taken). */
|
||||
{
|
||||
unsigned long flags;
|
||||
local_save_flags(flags);
|
||||
flags |= (1<<30); /* NMI M flag is at bit 30 */
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
The same goes for the external NMI, but that doesn't have any
|
||||
driver or infrastructure support yet. */
|
||||
{
|
||||
unsigned long flags;
|
||||
local_save_flags(flags);
|
||||
flags |= (1<<30); /* NMI M flag is at bit 30 */
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
cpufreq_register_notifier(&cris_time_freq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
static int
|
||||
cris_time_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_freqs *freqs = data;
|
||||
if (val == CPUFREQ_POSTCHANGE) {
|
||||
reg_timer_r_tmr0_data data;
|
||||
reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ;
|
||||
do {
|
||||
data = REG_RD(timer, timer_regs[freqs->cpu],
|
||||
r_tmr0_data);
|
||||
} while (data > 20);
|
||||
REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,50 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2003, Axis Communications AB.
|
||||
* Copyright (C) 2003-2006, Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <asm/arch/hwregs/supp_reg.h>
|
||||
|
||||
extern void reset_watchdog(void);
|
||||
extern void stop_watchdog(void);
|
||||
|
||||
extern int raw_printk(const char *fmt, ...);
|
||||
#include <hwregs/supp_reg.h>
|
||||
#include <hwregs/intr_vect_defs.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
void
|
||||
show_registers(struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* It's possible to use either the USP register or current->thread.usp.
|
||||
* USP might not correspond to the current proccess for all cases this
|
||||
* USP might not correspond to the current process for all cases this
|
||||
* function is called, and current->thread.usp isn't up to date for the
|
||||
* current proccess. Experience shows that using USP is the way to go.
|
||||
* current process. Experience shows that using USP is the way to go.
|
||||
*/
|
||||
unsigned long usp;
|
||||
unsigned long usp = rdusp();
|
||||
unsigned long d_mmu_cause;
|
||||
unsigned long i_mmu_cause;
|
||||
|
||||
usp = rdusp();
|
||||
printk("CPU: %d\n", smp_processor_id());
|
||||
|
||||
raw_printk("CPU: %d\n", smp_processor_id());
|
||||
printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
|
||||
regs->erp, regs->srp, regs->ccs, usp, regs->mof);
|
||||
|
||||
raw_printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
|
||||
regs->erp, regs->srp, regs->ccs, usp, regs->mof);
|
||||
printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
|
||||
raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
|
||||
regs->r0, regs->r1, regs->r2, regs->r3);
|
||||
printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
|
||||
raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
|
||||
regs->r4, regs->r5, regs->r6, regs->r7);
|
||||
printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
|
||||
regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
|
||||
raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
|
||||
regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
|
||||
regs->r12, regs->r13, regs->orig_r10, regs->acr);
|
||||
|
||||
raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
|
||||
regs->r12, regs->r13, regs->orig_r10, regs->acr);
|
||||
|
||||
raw_printk("sp: %08lx\n", regs);
|
||||
printk(" sp: %08lx\n", (unsigned long)regs);
|
||||
|
||||
SUPP_BANK_SEL(BANK_IM);
|
||||
SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause);
|
||||
|
@ -52,18 +47,20 @@ show_registers(struct pt_regs *regs)
|
|||
SUPP_BANK_SEL(BANK_DM);
|
||||
SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause);
|
||||
|
||||
raw_printk(" Data MMU Cause: %08lx\n", d_mmu_cause);
|
||||
raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
|
||||
printk(" Data MMU Cause: %08lx\n", d_mmu_cause);
|
||||
printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
|
||||
|
||||
raw_printk("Process %s (pid: %d, stackpage: %08lx)\n",
|
||||
current->comm, current->pid, (unsigned long) current);
|
||||
printk("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
current->comm, current->pid, (unsigned long)current);
|
||||
|
||||
/* Show additional info if in kernel-mode. */
|
||||
/*
|
||||
* When in-kernel, we also print out the stack and code at the
|
||||
* time of the fault..
|
||||
*/
|
||||
if (!user_mode(regs)) {
|
||||
int i;
|
||||
unsigned char c;
|
||||
|
||||
show_stack(NULL, (unsigned long *) usp);
|
||||
show_stack(NULL, (unsigned long *)usp);
|
||||
|
||||
/*
|
||||
* If the previous stack-dump wasn't a kernel one, dump the
|
||||
|
@ -72,7 +69,7 @@ show_registers(struct pt_regs *regs)
|
|||
if (usp != 0)
|
||||
show_stack(NULL, NULL);
|
||||
|
||||
raw_printk("\nCode: ");
|
||||
printk("\nCode: ");
|
||||
|
||||
if (regs->erp < PAGE_OFFSET)
|
||||
goto bad_value;
|
||||
|
@ -84,76 +81,115 @@ show_registers(struct pt_regs *regs)
|
|||
* instruction decoding should be in sync at the interesting
|
||||
* point, but small enough to fit on a row. The regs->erp
|
||||
* location is pointed out in a ksymoops-friendly way by
|
||||
* wrapping the byte for that address in parenthesis.
|
||||
* wrapping the byte for that address in parenthesises.
|
||||
*/
|
||||
for (i = -12; i < 12; i++) {
|
||||
if (__get_user(c, &((unsigned char *) regs->erp)[i])) {
|
||||
unsigned char c;
|
||||
|
||||
if (__get_user(c, &((unsigned char *)regs->erp)[i])) {
|
||||
bad_value:
|
||||
raw_printk(" Bad IP value.");
|
||||
printk(" Bad IP value.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
raw_printk("(%02x) ", c);
|
||||
printk("(%02x) ", c);
|
||||
else
|
||||
raw_printk("%02x ", c);
|
||||
printk("%02x ", c);
|
||||
}
|
||||
|
||||
raw_printk("\n");
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets called from entry.S when the watchdog has bitten. Show something
|
||||
* similar to an Oops dump, and if the kernel is configured to be a nice doggy;
|
||||
* halt instead of reboot.
|
||||
*/
|
||||
void
|
||||
watchdog_bite_hook(struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
local_irq_disable();
|
||||
stop_watchdog();
|
||||
show_registers(regs);
|
||||
|
||||
while (1)
|
||||
; /* Do nothing. */
|
||||
#else
|
||||
show_registers(regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This is normally the Oops function. */
|
||||
void
|
||||
die_if_kernel(const char *str, struct pt_regs *regs, long err)
|
||||
{
|
||||
if (user_mode(regs))
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
/*
|
||||
* This printout might take too long and could trigger
|
||||
* the watchdog normally. If NICE_DOGGY is set, simply
|
||||
* stop the watchdog during the printout.
|
||||
*/
|
||||
stop_watchdog();
|
||||
#endif
|
||||
|
||||
raw_printk("%s: %04lx\n", str, err & 0xffff);
|
||||
|
||||
show_registers(regs);
|
||||
|
||||
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
|
||||
reset_watchdog();
|
||||
#endif
|
||||
|
||||
do_exit(SIGSEGV);
|
||||
}
|
||||
|
||||
void arch_enable_nmi(void)
|
||||
arch_enable_nmi(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_save_flags(flags);
|
||||
flags |= (1<<30); /* NMI M flag is at bit 30 */
|
||||
flags |= (1 << 30); /* NMI M flag is at bit 30 */
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
extern void (*nmi_handler)(struct pt_regs *);
|
||||
void handle_nmi(struct pt_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_ETRAXFS
|
||||
reg_intr_vect_r_nmi r;
|
||||
#endif
|
||||
|
||||
if (nmi_handler)
|
||||
nmi_handler(regs);
|
||||
|
||||
#ifdef CONFIG_ETRAXFS
|
||||
/* Wait until nmi is no longer active. */
|
||||
do {
|
||||
r = REG_RD(intr_vect, regi_irq, r_nmi);
|
||||
} while (r.ext == regk_intr_vect_on);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
|
||||
|
||||
/* Copy of the regs at BUG() time. */
|
||||
struct pt_regs BUG_regs;
|
||||
|
||||
void do_BUG(char *file, unsigned int line)
|
||||
{
|
||||
printk("kernel BUG at %s:%d!\n", file, line);
|
||||
die_if_kernel("Oops", &BUG_regs, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(do_BUG);
|
||||
|
||||
void fixup_BUG(struct pt_regs *regs)
|
||||
{
|
||||
BUG_regs = *regs;
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
/*
|
||||
* Fixup the BUG arguments through exception handlers.
|
||||
*/
|
||||
{
|
||||
const struct exception_table_entry *fixup;
|
||||
|
||||
/*
|
||||
* ERP points at the "break 14" + 2, compensate for the 2
|
||||
* bytes.
|
||||
*/
|
||||
fixup = search_exception_tables(instruction_pointer(regs) - 2);
|
||||
if (fixup) {
|
||||
/* Adjust the instruction pointer in the stackframe. */
|
||||
instruction_pointer(regs) = fixup->fixup;
|
||||
arch_fixup(regs);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Dont try to lookup the filename + line, just dump regs. */
|
||||
do_BUG("unknown", 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Break 14 handler. Save regs and jump into the fixup_BUG.
|
||||
*/
|
||||
__asm__ ( ".text\n\t"
|
||||
".global breakh_BUG\n\t"
|
||||
"breakh_BUG:\n\t"
|
||||
SAVE_ALL
|
||||
KGDB_FIXUP
|
||||
"move.d $sp, $r10\n\t"
|
||||
"jsr fixup_BUG\n\t"
|
||||
"nop\n\t"
|
||||
"jump ret_from_intr\n\t"
|
||||
"nop\n\t");
|
||||
|
||||
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
void
|
||||
handle_BUG(struct pt_regs *regs)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
// $Id: vcs_hook.c,v 1.2 2003/08/12 12:01:06 starvik Exp $
|
||||
//
|
||||
// Call simulator hook. This is the part running in the
|
||||
// simulated program.
|
||||
//
|
||||
|
||||
#include "vcs_hook.h"
|
||||
#include <stdarg.h>
|
||||
#include <asm/arch-v32/hwregs/reg_map.h>
|
||||
#include <asm/arch-v32/hwregs/intr_vect_defs.h>
|
||||
|
||||
#define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */
|
||||
#define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */
|
||||
|
||||
#define HOOK_DATA(offset) ((unsigned*) HOOK_MEM_BASE_ADDR)[offset]
|
||||
#define VHOOK_DATA(offset) ((volatile unsigned*) HOOK_MEM_BASE_ADDR)[offset]
|
||||
#define HOOK_TRIG(funcid) do { *((unsigned *) HOOK_TRIG_ADDR) = funcid; } while(0)
|
||||
#define HOOK_DATA_BYTE(offset) ((unsigned char*) HOOK_MEM_BASE_ADDR)[offset]
|
||||
|
||||
|
||||
// ------------------------------------------------------------------ hook_call
|
||||
int hook_call( unsigned id, unsigned pcnt, ...) {
|
||||
va_list ap;
|
||||
unsigned i;
|
||||
unsigned ret;
|
||||
#ifdef USING_SOS
|
||||
PREEMPT_OFF_SAVE();
|
||||
#endif
|
||||
|
||||
// pass parameters
|
||||
HOOK_DATA(0) = id;
|
||||
|
||||
/* Have to make hook_print_str a special case since we call with a
|
||||
parameter of byte type. Should perhaps be a separate
|
||||
hook_call. */
|
||||
|
||||
if (id == hook_print_str) {
|
||||
int i;
|
||||
char *str;
|
||||
|
||||
HOOK_DATA(1) = pcnt;
|
||||
|
||||
va_start(ap, pcnt);
|
||||
str = (char*)va_arg(ap,unsigned);
|
||||
|
||||
for (i=0; i!=pcnt; i++) {
|
||||
HOOK_DATA_BYTE(8+i) = str[i];
|
||||
}
|
||||
HOOK_DATA_BYTE(8+i) = 0; /* null byte */
|
||||
}
|
||||
else {
|
||||
va_start(ap, pcnt);
|
||||
for( i = 1; i <= pcnt; i++ ) HOOK_DATA(i) = va_arg(ap,unsigned);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// read from mem to make sure data has propagated to memory before trigging
|
||||
*((volatile unsigned*) HOOK_MEM_BASE_ADDR);
|
||||
|
||||
// trigger hook
|
||||
HOOK_TRIG(id);
|
||||
|
||||
// wait for call to finish
|
||||
while( VHOOK_DATA(0) > 0 ) {}
|
||||
|
||||
// extract return value
|
||||
|
||||
ret = VHOOK_DATA(1);
|
||||
|
||||
#ifdef USING_SOS
|
||||
PREEMPT_RESTORE();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned
|
||||
hook_buf(unsigned i)
|
||||
{
|
||||
return (HOOK_DATA(i));
|
||||
}
|
||||
|
||||
void print_str( const char *str ) {
|
||||
int i;
|
||||
for (i=1; str[i]; i++); /* find null at end of string */
|
||||
hook_call(hook_print_str, i, str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------- CPU_KICK_DOG
|
||||
void CPU_KICK_DOG(void) {
|
||||
(void) hook_call( hook_kick_dog, 0 );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------- CPU_WATCHDOG_TIMEOUT
|
||||
void CPU_WATCHDOG_TIMEOUT( unsigned t ) {
|
||||
(void) hook_call( hook_dog_timeout, 1, t );
|
||||
}
|
|
@ -2,5 +2,6 @@
|
|||
# Makefile for Etrax-specific library files..
|
||||
#
|
||||
|
||||
lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o spinlock.o
|
||||
lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o \
|
||||
csumcpfruser.o spinlock.o delay.o
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* A fast checksum routine using movem
|
||||
* Copyright (c) 1998-2001, 2003 Axis Communications AB
|
||||
* Copyright (c) 1998-2007 Axis Communications AB
|
||||
*
|
||||
* csum_partial(const unsigned char * buff, int len, unsigned int sum)
|
||||
*/
|
||||
|
@ -12,30 +12,23 @@ csum_partial:
|
|||
;; r11 - length
|
||||
;; r12 - checksum
|
||||
|
||||
;; check for breakeven length between movem and normal word looping versions
|
||||
;; we also do _NOT_ want to compute a checksum over more than the
|
||||
;; actual length when length < 40
|
||||
|
||||
cmpu.w 80,$r11
|
||||
blo _word_loop
|
||||
nop
|
||||
|
||||
;; need to save the registers we use below in the movem loop
|
||||
;; this overhead is why we have a check above for breakeven length
|
||||
;; only r0 - r8 have to be saved, the other ones are clobber-able
|
||||
;; according to the ABI
|
||||
;; Optimized for large packets
|
||||
subq 10*4, $r11
|
||||
blt _word_loop
|
||||
move.d $r11, $acr
|
||||
|
||||
subq 9*4,$sp
|
||||
subq 10*4,$r11 ; update length for the first loop
|
||||
clearf c
|
||||
movem $r8,[$sp]
|
||||
|
||||
;; do a movem checksum
|
||||
|
||||
_mloop: movem [$r10+],$r9 ; read 10 longwords
|
||||
|
||||
;; Loop count without touching the c flag.
|
||||
addoq -10*4, $acr, $acr
|
||||
;; perform dword checksumming on the 10 longwords
|
||||
|
||||
add.d $r0,$r12
|
||||
addc $r0,$r12
|
||||
addc $r1,$r12
|
||||
addc $r2,$r12
|
||||
addc $r3,$r12
|
||||
|
@ -46,60 +39,41 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords
|
|||
addc $r8,$r12
|
||||
addc $r9,$r12
|
||||
|
||||
;; fold the carry into the checksum, to avoid having to loop the carry
|
||||
;; back into the top
|
||||
|
||||
addc 0,$r12
|
||||
addc 0,$r12 ; do it again, since we might have generated a carry
|
||||
|
||||
subq 10*4,$r11
|
||||
bge _mloop
|
||||
nop
|
||||
|
||||
addq 10*4,$r11 ; compensate for last loop underflowing length
|
||||
;; test $acr without trashing carry.
|
||||
move.d $acr, $acr
|
||||
bpl _mloop
|
||||
;; r11 <= acr is not really needed in the mloop, just using the dslot
|
||||
;; to prepare for what is needed after mloop.
|
||||
move.d $acr, $r11
|
||||
|
||||
;; fold the last carry into r13
|
||||
addc 0, $r12
|
||||
movem [$sp+],$r8 ; restore regs
|
||||
|
||||
_word_loop:
|
||||
;; only fold if there is anything to fold.
|
||||
|
||||
cmpq 0,$r12
|
||||
beq _no_fold
|
||||
|
||||
;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below.
|
||||
;; r9 and r13 can be used as temporaries.
|
||||
addq 10*4,$r11 ; compensate for last loop underflowing length
|
||||
|
||||
moveq -1,$r9 ; put 0xffff in r9, faster than move.d 0xffff,r9
|
||||
lsrq 16,$r9
|
||||
|
||||
move.d $r12,$r13
|
||||
lsrq 16,$r13 ; r13 = checksum >> 16
|
||||
and.d $r9,$r12 ; checksum = checksum & 0xffff
|
||||
add.d $r13,$r12 ; checksum += r13
|
||||
move.d $r12,$r13 ; do the same again, maybe we got a carry last add
|
||||
lsrq 16,$r13
|
||||
and.d $r9,$r12
|
||||
add.d $r13,$r12
|
||||
and.d $r9,$r12 ; checksum = checksum & 0xffff
|
||||
|
||||
_no_fold:
|
||||
cmpq 2,$r11
|
||||
subq 2,$r11
|
||||
blt _no_words
|
||||
nop
|
||||
add.d $r13,$r12 ; checksum += r13
|
||||
|
||||
;; checksum the rest of the words
|
||||
|
||||
subq 2,$r11
|
||||
|
||||
_wloop: subq 2,$r11
|
||||
bge _wloop
|
||||
addu.w [$r10+],$r12
|
||||
|
||||
addq 2,$r11
|
||||
|
||||
_no_words:
|
||||
addq 2,$r11
|
||||
;; see if we have one odd byte more
|
||||
cmpq 1,$r11
|
||||
beq _do_byte
|
||||
bne _do_byte
|
||||
nop
|
||||
ret
|
||||
move.d $r12,$r10
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* A fast checksum+copy routine using movem
|
||||
* Copyright (c) 1998, 2001, 2003 Axis Communications AB
|
||||
* Copyright (c) 1998-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Bjorn Wesen
|
||||
*
|
||||
|
@ -16,32 +16,23 @@ csum_partial_copy_nocheck:
|
|||
;; r12 - length
|
||||
;; r13 - checksum
|
||||
|
||||
;; check for breakeven length between movem and normal word looping versions
|
||||
;; we also do _NOT_ want to compute a checksum over more than the
|
||||
;; actual length when length < 40
|
||||
|
||||
cmpu.w 80,$r12
|
||||
blo _word_loop
|
||||
nop
|
||||
|
||||
;; need to save the registers we use below in the movem loop
|
||||
;; this overhead is why we have a check above for breakeven length
|
||||
;; only r0 - r8 have to be saved, the other ones are clobber-able
|
||||
;; according to the ABI
|
||||
;; Optimized for large packets
|
||||
subq 10*4, $r12
|
||||
blt _word_loop
|
||||
move.d $r12, $acr
|
||||
|
||||
subq 9*4,$sp
|
||||
subq 10*4,$r12 ; update length for the first loop
|
||||
clearf c
|
||||
movem $r8,[$sp]
|
||||
|
||||
;; do a movem copy and checksum
|
||||
|
||||
1: ;; A failing userspace access (the read) will have this as PC.
|
||||
_mloop: movem [$r10+],$r9 ; read 10 longwords
|
||||
addoq -10*4, $acr, $acr ; loop counter in latency cycle
|
||||
movem $r9,[$r11+] ; write 10 longwords
|
||||
|
||||
;; perform dword checksumming on the 10 longwords
|
||||
|
||||
add.d $r0,$r13
|
||||
addc $r0,$r13
|
||||
addc $r1,$r13
|
||||
addc $r2,$r13
|
||||
addc $r3,$r13
|
||||
|
@ -52,47 +43,30 @@ _mloop: movem [$r10+],$r9 ; read 10 longwords
|
|||
addc $r8,$r13
|
||||
addc $r9,$r13
|
||||
|
||||
;; fold the carry into the checksum, to avoid having to loop the carry
|
||||
;; back into the top
|
||||
|
||||
addc 0,$r13
|
||||
addc 0,$r13 ; do it again, since we might have generated a carry
|
||||
|
||||
subq 10*4,$r12
|
||||
bge _mloop
|
||||
nop
|
||||
|
||||
addq 10*4,$r12 ; compensate for last loop underflowing length
|
||||
;; test $acr, without trashing carry.
|
||||
move.d $acr, $acr
|
||||
bpl _mloop
|
||||
;; r12 <= acr is needed after mloop and in the exception handlers.
|
||||
move.d $acr, $r12
|
||||
|
||||
;; fold the last carry into r13
|
||||
addc 0, $r13
|
||||
movem [$sp+],$r8 ; restore regs
|
||||
|
||||
_word_loop:
|
||||
;; only fold if there is anything to fold.
|
||||
|
||||
cmpq 0,$r13
|
||||
beq _no_fold
|
||||
addq 10*4,$r12 ; compensate for last loop underflowing length
|
||||
|
||||
;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
|
||||
;; r9 can be used as temporary.
|
||||
|
||||
move.d $r13,$r9
|
||||
lsrq 16,$r9 ; r0 = checksum >> 16
|
||||
and.d 0xffff,$r13 ; checksum = checksum & 0xffff
|
||||
add.d $r9,$r13 ; checksum += r0
|
||||
move.d $r13,$r9 ; do the same again, maybe we got a carry last add
|
||||
lsrq 16,$r9
|
||||
and.d 0xffff,$r13
|
||||
add.d $r9,$r13
|
||||
|
||||
_no_fold:
|
||||
cmpq 2,$r12
|
||||
subq 2, $r12
|
||||
blt _no_words
|
||||
nop
|
||||
add.d $r9,$r13 ; checksum += r0
|
||||
|
||||
;; copy and checksum the rest of the words
|
||||
|
||||
subq 2,$r12
|
||||
|
||||
2: ;; A failing userspace access for the read below will have this as PC.
|
||||
_wloop: move.w [$r10+],$r9
|
||||
addu.w $r9,$r13
|
||||
|
@ -100,12 +74,9 @@ _wloop: move.w [$r10+],$r9
|
|||
bge _wloop
|
||||
move.w $r9,[$r11+]
|
||||
|
||||
addq 2,$r12
|
||||
|
||||
_no_words:
|
||||
;; see if we have one odd byte more
|
||||
cmpq 1,$r12
|
||||
beq _do_byte
|
||||
addq 2,$r12
|
||||
bne _do_byte
|
||||
nop
|
||||
ret
|
||||
move.d $r13,$r10
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Precise Delay Loops for ETRAX FS
|
||||
*
|
||||
* Copyright (C) 2006 Axis Communications AB.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/timer_defs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* On ETRAX FS, we can check the free-running read-only 100MHz timer
|
||||
* getting 32-bit 10ns precision, theoretically good for 42.94967295
|
||||
* seconds. Unsigned arithmetic and careful expression handles
|
||||
* wrapping.
|
||||
*/
|
||||
|
||||
void cris_delay10ns(u32 n10ns)
|
||||
{
|
||||
u32 t0 = REG_RD(timer, regi_timer0, r_time);
|
||||
while (REG_RD(timer, regi_timer0, r_time) - t0 < n10ns)
|
||||
;
|
||||
}
|
||||
EXPORT_SYMBOL(cris_delay10ns);
|
|
@ -12,11 +12,11 @@
|
|||
|
||||
cris_spin_lock:
|
||||
clearf p
|
||||
1: test.d [$r10]
|
||||
1: test.b [$r10]
|
||||
beq 1b
|
||||
clearf p
|
||||
ax
|
||||
clear.d [$r10]
|
||||
clear.b [$r10]
|
||||
bcs 1b
|
||||
clearf p
|
||||
ret
|
||||
|
@ -24,10 +24,10 @@ cris_spin_lock:
|
|||
|
||||
cris_spin_trylock:
|
||||
clearf p
|
||||
1: move.d [$r10], $r11
|
||||
1: move.b [$r10], $r11
|
||||
ax
|
||||
clear.d [$r10]
|
||||
clear.b [$r10]
|
||||
bcs 1b
|
||||
clearf p
|
||||
ret
|
||||
move.d $r11,$r10
|
||||
movu.b $r11,$r10
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
if CRIS_MACH_ARTPEC3
|
||||
|
||||
menu "Artpec-3 options"
|
||||
depends on CRIS_MACH_ARTPEC3
|
||||
|
||||
config ETRAX_DRAM_VIRTUAL_BASE
|
||||
hex
|
||||
default "c0000000"
|
||||
|
||||
config ETRAX_L2CACHE
|
||||
bool
|
||||
default y
|
||||
|
||||
config ETRAX_SERIAL_PORTS
|
||||
int
|
||||
default 5
|
||||
|
||||
config ETRAX_DDR
|
||||
bool
|
||||
default y
|
||||
|
||||
config ETRAX_DDR2_MRS
|
||||
hex "DDR2 MRS"
|
||||
default "0"
|
||||
|
||||
config ETRAX_DDR2_TIMING
|
||||
hex "DDR2 SDRAM timing"
|
||||
default "0"
|
||||
help
|
||||
SDRAM timing parameters.
|
||||
|
||||
config ETRAX_DDR2_CONFIG
|
||||
hex "DDR2 config"
|
||||
default "0"
|
||||
|
||||
config ETRAX_PIO_CE0_CFG
|
||||
hex "PIO CE0 configuration"
|
||||
default "0"
|
||||
|
||||
config ETRAX_PIO_CE1_CFG
|
||||
hex "PIO CE1 configuration"
|
||||
default "0"
|
||||
|
||||
config ETRAX_PIO_CE2_CFG
|
||||
hex "PIO CE2 configuration"
|
||||
default "0"
|
||||
|
||||
config ETRAX_DEF_GIO_PA_OE
|
||||
hex "GIO_PA_OE"
|
||||
default "00000000"
|
||||
help
|
||||
Configures the direction of general port A bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PA_OUT
|
||||
hex "GIO_PA_OUT"
|
||||
default "00000000"
|
||||
help
|
||||
Configures the initial data for the general port A bits. Most
|
||||
products should use 00 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PB_OE
|
||||
hex "GIO_PB_OE"
|
||||
default "000000000"
|
||||
help
|
||||
Configures the direction of general port B bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PB_OUT
|
||||
hex "GIO_PB_OUT"
|
||||
default "000000000"
|
||||
help
|
||||
Configures the initial data for the general port B bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PC_OE
|
||||
hex "GIO_PC_OE"
|
||||
default "00000"
|
||||
help
|
||||
Configures the direction of general port C bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PC_OUT
|
||||
hex "GIO_PC_OUT"
|
||||
default "00000"
|
||||
help
|
||||
Configures the initial data for the general port C bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
|
@ -0,0 +1,11 @@
|
|||
# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-y := dma.o pinmux.o io.o arbiter.o
|
||||
obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
|
||||
clean:
|
||||
|
|
@ -0,0 +1,634 @@
|
|||
/*
|
||||
* Memory arbiter functions. Allocates bandwidth through the
|
||||
* arbiter and sets up arbiter breakpoints.
|
||||
*
|
||||
* The algorithm first assigns slots to the clients that has specified
|
||||
* bandwidth (e.g. ethernet) and then the remaining slots are divided
|
||||
* on all the active clients.
|
||||
*
|
||||
* Copyright (c) 2004-2007 Axis Communications AB.
|
||||
*
|
||||
* The artpec-3 has two arbiters. The memory hierarchy looks like this:
|
||||
*
|
||||
*
|
||||
* CPU DMAs
|
||||
* | |
|
||||
* | |
|
||||
* -------------- ------------------
|
||||
* | foo arbiter|----| Internal memory|
|
||||
* -------------- ------------------
|
||||
* |
|
||||
* --------------
|
||||
* | L2 cache |
|
||||
* --------------
|
||||
* |
|
||||
* h264 etc |
|
||||
* | |
|
||||
* | |
|
||||
* --------------
|
||||
* | bar arbiter|
|
||||
* --------------
|
||||
* |
|
||||
* ---------
|
||||
* | SDRAM |
|
||||
* ---------
|
||||
*
|
||||
*/
|
||||
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/marb_foo_defs.h>
|
||||
#include <hwregs/marb_bar_defs.h>
|
||||
#include <arbiter.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
#define D(x)
|
||||
|
||||
struct crisv32_watch_entry {
|
||||
unsigned long instance;
|
||||
watch_callback *cb;
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
int used;
|
||||
};
|
||||
|
||||
#define NUMBER_OF_BP 4
|
||||
#define SDRAM_BANDWIDTH 400000000
|
||||
#define INTMEM_BANDWIDTH 400000000
|
||||
#define NBR_OF_SLOTS 64
|
||||
#define NBR_OF_REGIONS 2
|
||||
#define NBR_OF_CLIENTS 15
|
||||
#define ARBITERS 2
|
||||
#define UNASSIGNED 100
|
||||
|
||||
struct arbiter {
|
||||
unsigned long instance;
|
||||
int nbr_regions;
|
||||
int nbr_clients;
|
||||
int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
};
|
||||
|
||||
static struct crisv32_watch_entry watches[ARBITERS][NUMBER_OF_BP] =
|
||||
{
|
||||
{
|
||||
{regi_marb_foo_bp0},
|
||||
{regi_marb_foo_bp1},
|
||||
{regi_marb_foo_bp2},
|
||||
{regi_marb_foo_bp3}
|
||||
},
|
||||
{
|
||||
{regi_marb_bar_bp0},
|
||||
{regi_marb_bar_bp1},
|
||||
{regi_marb_bar_bp2},
|
||||
{regi_marb_bar_bp3}
|
||||
}
|
||||
};
|
||||
|
||||
struct arbiter arbiters[ARBITERS] =
|
||||
{
|
||||
{ /* L2 cache arbiter */
|
||||
.instance = regi_marb_foo,
|
||||
.nbr_regions = 2,
|
||||
.nbr_clients = 15
|
||||
},
|
||||
{ /* DDR2 arbiter */
|
||||
.instance = regi_marb_bar,
|
||||
.nbr_regions = 1,
|
||||
.nbr_clients = 9
|
||||
}
|
||||
};
|
||||
|
||||
static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH};
|
||||
|
||||
DEFINE_SPINLOCK(arbiter_lock);
|
||||
|
||||
static irqreturn_t
|
||||
crisv32_foo_arbiter_irq(int irq, void *dev_id);
|
||||
static irqreturn_t
|
||||
crisv32_bar_arbiter_irq(int irq, void *dev_id);
|
||||
|
||||
/*
|
||||
* "I'm the arbiter, I know the score.
|
||||
* From square one I'll be watching all 64."
|
||||
* (memory arbiter slots, that is)
|
||||
*
|
||||
* Or in other words:
|
||||
* Program the memory arbiter slots for "region" according to what's
|
||||
* in requested_slots[] and active_clients[], while minimizing
|
||||
* latency. A caller may pass a non-zero positive amount for
|
||||
* "unused_slots", which must then be the unallocated, remaining
|
||||
* number of slots, free to hand out to any client.
|
||||
*/
|
||||
|
||||
static void crisv32_arbiter_config(int arbiter, int region, int unused_slots)
|
||||
{
|
||||
int slot;
|
||||
int client;
|
||||
int interval = 0;
|
||||
|
||||
/*
|
||||
* This vector corresponds to the hardware arbiter slots (see
|
||||
* the hardware documentation for semantics). We initialize
|
||||
* each slot with a suitable sentinel value outside the valid
|
||||
* range {0 .. NBR_OF_CLIENTS - 1} and replace them with
|
||||
* client indexes. Then it's fed to the hardware.
|
||||
*/
|
||||
s8 val[NBR_OF_SLOTS];
|
||||
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++)
|
||||
val[slot] = -1;
|
||||
|
||||
for (client = 0; client < arbiters[arbiter].nbr_clients; client++) {
|
||||
int pos;
|
||||
/* Allocate the requested non-zero number of slots, but
|
||||
* also give clients with zero-requests one slot each
|
||||
* while stocks last. We do the latter here, in client
|
||||
* order. This makes sure zero-request clients are the
|
||||
* first to get to any spare slots, else those slots
|
||||
* could, when bandwidth is allocated close to the limit,
|
||||
* all be allocated to low-index non-zero-request clients
|
||||
* in the default-fill loop below. Another positive but
|
||||
* secondary effect is a somewhat better spread of the
|
||||
* zero-bandwidth clients in the vector, avoiding some of
|
||||
* the latency that could otherwise be caused by the
|
||||
* partitioning of non-zero-bandwidth clients at low
|
||||
* indexes and zero-bandwidth clients at high
|
||||
* indexes. (Note that this spreading can only affect the
|
||||
* unallocated bandwidth.) All the above only matters for
|
||||
* memory-intensive situations, of course.
|
||||
*/
|
||||
if (!arbiters[arbiter].requested_slots[region][client]) {
|
||||
/*
|
||||
* Skip inactive clients. Also skip zero-slot
|
||||
* allocations in this pass when there are no known
|
||||
* free slots.
|
||||
*/
|
||||
if (!arbiters[arbiter].active_clients[region][client] ||
|
||||
unused_slots <= 0)
|
||||
continue;
|
||||
|
||||
unused_slots--;
|
||||
|
||||
/* Only allocate one slot for this client. */
|
||||
interval = NBR_OF_SLOTS;
|
||||
} else
|
||||
interval = NBR_OF_SLOTS /
|
||||
arbiters[arbiter].requested_slots[region][client];
|
||||
|
||||
pos = 0;
|
||||
while (pos < NBR_OF_SLOTS) {
|
||||
if (val[pos] >= 0)
|
||||
pos++;
|
||||
else {
|
||||
val[pos] = client;
|
||||
pos += interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client = 0;
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++) {
|
||||
/*
|
||||
* Allocate remaining slots in round-robin
|
||||
* client-number order for active clients. For this
|
||||
* pass, we ignore requested bandwidth and previous
|
||||
* allocations.
|
||||
*/
|
||||
if (val[slot] < 0) {
|
||||
int first = client;
|
||||
while (!arbiters[arbiter].active_clients[region][client]) {
|
||||
client = (client + 1) %
|
||||
arbiters[arbiter].nbr_clients;
|
||||
if (client == first)
|
||||
break;
|
||||
}
|
||||
val[slot] = client;
|
||||
client = (client + 1) % arbiters[arbiter].nbr_clients;
|
||||
}
|
||||
if (arbiter == 0) {
|
||||
if (region == EXT_REGION)
|
||||
REG_WR_INT_VECT(marb_foo, regi_marb_foo,
|
||||
rw_l2_slots, slot, val[slot]);
|
||||
else if (region == INT_REGION)
|
||||
REG_WR_INT_VECT(marb_foo, regi_marb_foo,
|
||||
rw_intm_slots, slot, val[slot]);
|
||||
} else {
|
||||
REG_WR_INT_VECT(marb_bar, regi_marb_bar,
|
||||
rw_ddr2_slots, slot, val[slot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern char _stext, _etext;
|
||||
|
||||
static void crisv32_arbiter_init(void)
|
||||
{
|
||||
static int initialized;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
/*
|
||||
* CPU caches are always set to active, but with zero
|
||||
* bandwidth allocated. It should be ok to allocate zero
|
||||
* bandwidth for the caches, because DMA for other channels
|
||||
* will supposedly finish, once their programmed amount is
|
||||
* done, and then the caches will get access according to the
|
||||
* "fixed scheme" for unclaimed slots. Though, if for some
|
||||
* use-case somewhere, there's a maximum CPU latency for
|
||||
* e.g. some interrupt, we have to start allocating specific
|
||||
* bandwidth for the CPU caches too.
|
||||
*/
|
||||
arbiters[0].active_clients[EXT_REGION][11] = 1;
|
||||
arbiters[0].active_clients[EXT_REGION][12] = 1;
|
||||
crisv32_arbiter_config(0, EXT_REGION, 0);
|
||||
crisv32_arbiter_config(0, INT_REGION, 0);
|
||||
crisv32_arbiter_config(1, EXT_REGION, 0);
|
||||
|
||||
if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq,
|
||||
IRQF_DISABLED, "arbiter", NULL))
|
||||
printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
|
||||
|
||||
if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq,
|
||||
IRQF_DISABLED, "arbiter", NULL))
|
||||
printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
|
||||
|
||||
#ifndef CONFIG_ETRAX_KGDB
|
||||
/* Global watch for writes to kernel text segment. */
|
||||
crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
|
||||
MARB_CLIENTS(arbiter_all_clients, arbiter_bar_all_clients),
|
||||
arbiter_all_write, NULL);
|
||||
#endif
|
||||
|
||||
/* Set up max burst sizes by default */
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_rd_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_wr_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_ccd_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_wr_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_rd_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_rd_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_vout_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_fifo_burst, 3);
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_l2cache_burst, 3);
|
||||
}
|
||||
|
||||
int crisv32_arbiter_allocate_bandwidth(int client, int region,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
int i;
|
||||
int total_assigned = 0;
|
||||
int total_clients = 0;
|
||||
int req;
|
||||
int arbiter = 0;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
if (client & 0xffff0000) {
|
||||
arbiter = 1;
|
||||
client >>= 16;
|
||||
}
|
||||
|
||||
for (i = 0; i < arbiters[arbiter].nbr_clients; i++) {
|
||||
total_assigned += arbiters[arbiter].requested_slots[region][i];
|
||||
total_clients += arbiters[arbiter].active_clients[region][i];
|
||||
}
|
||||
|
||||
/* Avoid division by 0 for 0-bandwidth requests. */
|
||||
req = bandwidth == 0
|
||||
? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
|
||||
|
||||
/*
|
||||
* We make sure that there are enough slots only for non-zero
|
||||
* requests. Requesting 0 bandwidth *may* allocate slots,
|
||||
* though if all bandwidth is allocated, such a client won't
|
||||
* get any and will have to rely on getting memory access
|
||||
* according to the fixed scheme that's the default when one
|
||||
* of the slot-allocated clients doesn't claim their slot.
|
||||
*/
|
||||
if (total_assigned + req > NBR_OF_SLOTS)
|
||||
return -ENOMEM;
|
||||
|
||||
arbiters[arbiter].active_clients[region][client] = 1;
|
||||
arbiters[arbiter].requested_slots[region][client] = req;
|
||||
crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned);
|
||||
|
||||
/* Propagate allocation from foo to bar */
|
||||
if (arbiter == 0)
|
||||
crisv32_arbiter_allocate_bandwidth(8 << 16,
|
||||
EXT_REGION, bandwidth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry for bandwidth deallocation.
|
||||
*
|
||||
* Strictly speaking, for a somewhat constant set of clients where
|
||||
* each client gets a constant bandwidth and is just enabled or
|
||||
* disabled (somewhat dynamically), no action is necessary here to
|
||||
* avoid starvation for non-zero-allocation clients, as the allocated
|
||||
* slots will just be unused. However, handing out those unused slots
|
||||
* to active clients avoids needless latency if the "fixed scheme"
|
||||
* would give unclaimed slots to an eager low-index client.
|
||||
*/
|
||||
|
||||
void crisv32_arbiter_deallocate_bandwidth(int client, int region)
|
||||
{
|
||||
int i;
|
||||
int total_assigned = 0;
|
||||
int arbiter = 0;
|
||||
|
||||
if (client & 0xffff0000)
|
||||
arbiter = 1;
|
||||
|
||||
arbiters[arbiter].requested_slots[region][client] = 0;
|
||||
arbiters[arbiter].active_clients[region][client] = 0;
|
||||
|
||||
for (i = 0; i < arbiters[arbiter].nbr_clients; i++)
|
||||
total_assigned += arbiters[arbiter].requested_slots[region][i];
|
||||
|
||||
crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned);
|
||||
}
|
||||
|
||||
int crisv32_arbiter_watch(unsigned long start, unsigned long size,
|
||||
unsigned long clients, unsigned long accesses,
|
||||
watch_callback *cb)
|
||||
{
|
||||
int i;
|
||||
int arbiter;
|
||||
int used[2];
|
||||
int ret = 0;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
if (start > 0x80000000) {
|
||||
printk(KERN_ERR "Arbiter: %lX doesn't look like a "
|
||||
"physical address", start);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
if (clients & 0xffff)
|
||||
used[0] = 1;
|
||||
if (clients & 0xffff0000)
|
||||
used[1] = 1;
|
||||
|
||||
for (arbiter = 0; arbiter < ARBITERS; arbiter++) {
|
||||
if (!used[arbiter])
|
||||
continue;
|
||||
|
||||
for (i = 0; i < NUMBER_OF_BP; i++) {
|
||||
if (!watches[arbiter][i].used) {
|
||||
unsigned intr_mask;
|
||||
if (arbiter)
|
||||
intr_mask = REG_RD_INT(marb_bar,
|
||||
regi_marb_bar, rw_intr_mask);
|
||||
else
|
||||
intr_mask = REG_RD_INT(marb_foo,
|
||||
regi_marb_foo, rw_intr_mask);
|
||||
|
||||
watches[arbiter][i].used = 1;
|
||||
watches[arbiter][i].start = start;
|
||||
watches[arbiter][i].end = start + size;
|
||||
watches[arbiter][i].cb = cb;
|
||||
|
||||
ret |= (i + 1) << (arbiter + 8);
|
||||
if (arbiter) {
|
||||
REG_WR_INT(marb_bar_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_first_addr,
|
||||
watches[arbiter][i].start);
|
||||
REG_WR_INT(marb_bar_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_last_addr,
|
||||
watches[arbiter][i].end);
|
||||
REG_WR_INT(marb_bar_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_op, accesses);
|
||||
REG_WR_INT(marb_bar_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_clients,
|
||||
clients & 0xffff);
|
||||
} else {
|
||||
REG_WR_INT(marb_foo_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_first_addr,
|
||||
watches[arbiter][i].start);
|
||||
REG_WR_INT(marb_foo_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_last_addr,
|
||||
watches[arbiter][i].end);
|
||||
REG_WR_INT(marb_foo_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_op, accesses);
|
||||
REG_WR_INT(marb_foo_bp,
|
||||
watches[arbiter][i].instance,
|
||||
rw_clients, clients >> 16);
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
intr_mask |= 1;
|
||||
else if (i == 1)
|
||||
intr_mask |= 2;
|
||||
else if (i == 2)
|
||||
intr_mask |= 4;
|
||||
else if (i == 3)
|
||||
intr_mask |= 8;
|
||||
|
||||
if (arbiter)
|
||||
REG_WR_INT(marb_bar, regi_marb_bar,
|
||||
rw_intr_mask, intr_mask);
|
||||
else
|
||||
REG_WR_INT(marb_foo, regi_marb_foo,
|
||||
rw_intr_mask, intr_mask);
|
||||
|
||||
spin_unlock(&arbiter_lock);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&arbiter_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int crisv32_arbiter_unwatch(int id)
|
||||
{
|
||||
int arbiter;
|
||||
int intr_mask;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
for (arbiter = 0; arbiter < ARBITERS; arbiter++) {
|
||||
int id2;
|
||||
|
||||
if (arbiter)
|
||||
intr_mask = REG_RD_INT(marb_bar, regi_marb_bar,
|
||||
rw_intr_mask);
|
||||
else
|
||||
intr_mask = REG_RD_INT(marb_foo, regi_marb_foo,
|
||||
rw_intr_mask);
|
||||
|
||||
id2 = (id & (0xff << (arbiter + 8))) >> (arbiter + 8);
|
||||
if (id2 == 0)
|
||||
continue;
|
||||
id2--;
|
||||
if ((id2 >= NUMBER_OF_BP) || (!watches[arbiter][id2].used)) {
|
||||
spin_unlock(&arbiter_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&watches[arbiter][id2], 0,
|
||||
sizeof(struct crisv32_watch_entry));
|
||||
|
||||
if (id2 == 0)
|
||||
intr_mask &= ~1;
|
||||
else if (id2 == 1)
|
||||
intr_mask &= ~2;
|
||||
else if (id2 == 2)
|
||||
intr_mask &= ~4;
|
||||
else if (id2 == 3)
|
||||
intr_mask &= ~8;
|
||||
|
||||
if (arbiter)
|
||||
REG_WR_INT(marb_bar, regi_marb_bar, rw_intr_mask,
|
||||
intr_mask);
|
||||
else
|
||||
REG_WR_INT(marb_foo, regi_marb_foo, rw_intr_mask,
|
||||
intr_mask);
|
||||
}
|
||||
|
||||
spin_unlock(&arbiter_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void show_registers(struct pt_regs *regs);
|
||||
|
||||
|
||||
static irqreturn_t
|
||||
crisv32_foo_arbiter_irq(int irq, void *dev_id)
|
||||
{
|
||||
reg_marb_foo_r_masked_intr masked_intr =
|
||||
REG_RD(marb_foo, regi_marb_foo, r_masked_intr);
|
||||
reg_marb_foo_bp_r_brk_clients r_clients;
|
||||
reg_marb_foo_bp_r_brk_addr r_addr;
|
||||
reg_marb_foo_bp_r_brk_op r_op;
|
||||
reg_marb_foo_bp_r_brk_first_client r_first;
|
||||
reg_marb_foo_bp_r_brk_size r_size;
|
||||
reg_marb_foo_bp_rw_ack ack = {0};
|
||||
reg_marb_foo_rw_ack_intr ack_intr = {
|
||||
.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
|
||||
};
|
||||
struct crisv32_watch_entry *watch;
|
||||
unsigned arbiter = (unsigned)dev_id;
|
||||
|
||||
masked_intr = REG_RD(marb_foo, regi_marb_foo, r_masked_intr);
|
||||
|
||||
if (masked_intr.bp0)
|
||||
watch = &watches[arbiter][0];
|
||||
else if (masked_intr.bp1)
|
||||
watch = &watches[arbiter][1];
|
||||
else if (masked_intr.bp2)
|
||||
watch = &watches[arbiter][2];
|
||||
else if (masked_intr.bp3)
|
||||
watch = &watches[arbiter][3];
|
||||
else
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Retrieve all useful information and print it. */
|
||||
r_clients = REG_RD(marb_foo_bp, watch->instance, r_brk_clients);
|
||||
r_addr = REG_RD(marb_foo_bp, watch->instance, r_brk_addr);
|
||||
r_op = REG_RD(marb_foo_bp, watch->instance, r_brk_op);
|
||||
r_first = REG_RD(marb_foo_bp, watch->instance, r_brk_first_client);
|
||||
r_size = REG_RD(marb_foo_bp, watch->instance, r_brk_size);
|
||||
|
||||
printk(KERN_DEBUG "Arbiter IRQ\n");
|
||||
printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n",
|
||||
REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_clients, r_clients),
|
||||
REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_addr, r_addr),
|
||||
REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_op, r_op),
|
||||
REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_first_client, r_first),
|
||||
REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_size, r_size));
|
||||
|
||||
REG_WR(marb_foo_bp, watch->instance, rw_ack, ack);
|
||||
REG_WR(marb_foo, regi_marb_foo, rw_ack_intr, ack_intr);
|
||||
|
||||
printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs());
|
||||
|
||||
if (watch->cb)
|
||||
watch->cb();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
crisv32_bar_arbiter_irq(int irq, void *dev_id)
|
||||
{
|
||||
reg_marb_bar_r_masked_intr masked_intr =
|
||||
REG_RD(marb_bar, regi_marb_bar, r_masked_intr);
|
||||
reg_marb_bar_bp_r_brk_clients r_clients;
|
||||
reg_marb_bar_bp_r_brk_addr r_addr;
|
||||
reg_marb_bar_bp_r_brk_op r_op;
|
||||
reg_marb_bar_bp_r_brk_first_client r_first;
|
||||
reg_marb_bar_bp_r_brk_size r_size;
|
||||
reg_marb_bar_bp_rw_ack ack = {0};
|
||||
reg_marb_bar_rw_ack_intr ack_intr = {
|
||||
.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
|
||||
};
|
||||
struct crisv32_watch_entry *watch;
|
||||
unsigned arbiter = (unsigned)dev_id;
|
||||
|
||||
masked_intr = REG_RD(marb_bar, regi_marb_bar, r_masked_intr);
|
||||
|
||||
if (masked_intr.bp0)
|
||||
watch = &watches[arbiter][0];
|
||||
else if (masked_intr.bp1)
|
||||
watch = &watches[arbiter][1];
|
||||
else if (masked_intr.bp2)
|
||||
watch = &watches[arbiter][2];
|
||||
else if (masked_intr.bp3)
|
||||
watch = &watches[arbiter][3];
|
||||
else
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Retrieve all useful information and print it. */
|
||||
r_clients = REG_RD(marb_bar_bp, watch->instance, r_brk_clients);
|
||||
r_addr = REG_RD(marb_bar_bp, watch->instance, r_brk_addr);
|
||||
r_op = REG_RD(marb_bar_bp, watch->instance, r_brk_op);
|
||||
r_first = REG_RD(marb_bar_bp, watch->instance, r_brk_first_client);
|
||||
r_size = REG_RD(marb_bar_bp, watch->instance, r_brk_size);
|
||||
|
||||
printk(KERN_DEBUG "Arbiter IRQ\n");
|
||||
printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n",
|
||||
REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_clients, r_clients),
|
||||
REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_addr, r_addr),
|
||||
REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_op, r_op),
|
||||
REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_first_client, r_first),
|
||||
REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_size, r_size));
|
||||
|
||||
REG_WR(marb_bar_bp, watch->instance, rw_ack, ack);
|
||||
REG_WR(marb_bar, regi_marb_bar, rw_ack_intr, ack_intr);
|
||||
|
||||
printk(KERN_DEBUG "IRQ occured at %X\n", (unsigned)get_irq_regs()->erp);
|
||||
|
||||
if (watch->cb)
|
||||
watch->cb();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/clkgen_defs.h>
|
||||
#include <hwregs/ddr2_defs.h>
|
||||
|
||||
static int
|
||||
cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data);
|
||||
|
||||
static struct notifier_block cris_sdram_freq_notifier_block = {
|
||||
.notifier_call = cris_sdram_freq_notifier
|
||||
};
|
||||
|
||||
static struct cpufreq_frequency_table cris_freq_table[] = {
|
||||
{0x01, 6000},
|
||||
{0x02, 200000},
|
||||
{0, CPUFREQ_TABLE_END},
|
||||
};
|
||||
|
||||
static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
|
||||
{
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
return clk_ctrl.pll ? 200000 : 6000;
|
||||
}
|
||||
|
||||
static void cris_freq_set_cpu_state(unsigned int state)
|
||||
{
|
||||
int i = 0;
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
for_each_present_cpu(i)
|
||||
#endif
|
||||
{
|
||||
freqs.old = cris_freq_get_cpu_frequency(i);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
freqs.cpu = i;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Even though we may be SMP they will share the same clock
|
||||
* so all settings are made on CPU0. */
|
||||
if (cris_freq_table[state].frequency == 200000)
|
||||
clk_ctrl.pll = 1;
|
||||
else
|
||||
clk_ctrl.pll = 0;
|
||||
REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
static int cris_freq_verify(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);
|
||||
}
|
||||
|
||||
static int cris_freq_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
unsigned int newstate = 0;
|
||||
|
||||
if (cpufreq_frequency_table_target(policy, cris_freq_table,
|
||||
target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
cris_freq_set_cpu_state(newstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cris_freq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
|
||||
policy->cur = cris_freq_get_cpu_frequency(0);
|
||||
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
|
||||
if (result)
|
||||
return (result);
|
||||
|
||||
cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int cris_freq_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct freq_attr *cris_freq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver cris_freq_driver = {
|
||||
.get = cris_freq_get_cpu_frequency,
|
||||
.verify = cris_freq_verify,
|
||||
.target = cris_freq_target,
|
||||
.init = cris_freq_cpu_init,
|
||||
.exit = cris_freq_cpu_exit,
|
||||
.name = "cris_freq",
|
||||
.owner = THIS_MODULE,
|
||||
.attr = cris_freq_attr,
|
||||
};
|
||||
|
||||
static int __init cris_freq_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = cpufreq_register_driver(&cris_freq_driver);
|
||||
cpufreq_register_notifier(&cris_sdram_freq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_freqs *freqs = data;
|
||||
if (val == CPUFREQ_PRECHANGE) {
|
||||
reg_ddr2_rw_cfg cfg =
|
||||
REG_RD(ddr2, regi_ddr2_ctrl, rw_cfg);
|
||||
cfg.ref_interval = (freqs->new == 200000 ? 1560 : 46);
|
||||
|
||||
if (freqs->new == 200000)
|
||||
for (i = 0; i < 50000; i++);
|
||||
REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
module_init(cris_freq_init);
|
|
@ -0,0 +1,185 @@
|
|||
/* Wrapper for DMA channel allocator that starts clocks etc */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/arch/mach/dma.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/marb_defs.h>
|
||||
#include <hwregs/clkgen_defs.h>
|
||||
#include <hwregs/strmux_defs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/system.h>
|
||||
#include <arbiter.h>
|
||||
|
||||
static char used_dma_channels[MAX_DMA_CHANNELS];
|
||||
static const char *used_dma_channels_users[MAX_DMA_CHANNELS];
|
||||
|
||||
static DEFINE_SPINLOCK(dma_lock);
|
||||
|
||||
int crisv32_request_dma(unsigned int dmanr, const char *device_id,
|
||||
unsigned options, unsigned int bandwidth, enum dma_owner owner)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl;
|
||||
reg_strmux_rw_cfg strmux_cfg;
|
||||
|
||||
if (crisv32_arbiter_allocate_bandwidth(dmanr,
|
||||
options & DMA_INT_MEM ? INT_REGION : EXT_REGION,
|
||||
bandwidth))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&dma_lock, flags);
|
||||
|
||||
if (used_dma_channels[dmanr]) {
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
if (options & DMA_VERBOSE_ON_ERROR)
|
||||
printk(KERN_ERR "Failed to request DMA %i for %s, "
|
||||
"already allocated by %s\n",
|
||||
dmanr,
|
||||
device_id,
|
||||
used_dma_channels_users[dmanr]);
|
||||
|
||||
if (options & DMA_PANIC_ON_ERROR)
|
||||
panic("request_dma error!");
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
|
||||
strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
|
||||
|
||||
switch (dmanr) {
|
||||
case 0:
|
||||
case 1:
|
||||
clk_ctrl.dma0_1_eth = 1;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
clk_ctrl.dma2_3_strcop = 1;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
clk_ctrl.dma4_5_iop = 1;
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
clk_ctrl.sser_ser_dma6_7 = 1;
|
||||
break;
|
||||
case 9:
|
||||
case 11:
|
||||
clk_ctrl.dma9_11 = 1;
|
||||
break;
|
||||
#if MAX_DMA_CHANNELS-1 != 11
|
||||
#error Check dma.c
|
||||
#endif
|
||||
default:
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
if (options & DMA_VERBOSE_ON_ERROR)
|
||||
printk(KERN_ERR "Failed to request DMA %i for %s, "
|
||||
"only 0-%i valid)\n",
|
||||
dmanr, device_id, MAX_DMA_CHANNELS-1);
|
||||
|
||||
if (options & DMA_PANIC_ON_ERROR)
|
||||
panic("request_dma error!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (owner) {
|
||||
case dma_eth:
|
||||
if (dmanr == 0)
|
||||
strmux_cfg.dma0 = regk_strmux_eth;
|
||||
else if (dmanr == 1)
|
||||
strmux_cfg.dma1 = regk_strmux_eth;
|
||||
else
|
||||
panic("Invalid DMA channel for eth\n");
|
||||
break;
|
||||
case dma_ser0:
|
||||
if (dmanr == 0)
|
||||
strmux_cfg.dma0 = regk_strmux_ser0;
|
||||
else if (dmanr == 1)
|
||||
strmux_cfg.dma1 = regk_strmux_ser0;
|
||||
else
|
||||
panic("Invalid DMA channel for ser0\n");
|
||||
break;
|
||||
case dma_ser3:
|
||||
if (dmanr == 2)
|
||||
strmux_cfg.dma2 = regk_strmux_ser3;
|
||||
else if (dmanr == 3)
|
||||
strmux_cfg.dma3 = regk_strmux_ser3;
|
||||
else
|
||||
panic("Invalid DMA channel for ser3\n");
|
||||
break;
|
||||
case dma_strp:
|
||||
if (dmanr == 2)
|
||||
strmux_cfg.dma2 = regk_strmux_strcop;
|
||||
else if (dmanr == 3)
|
||||
strmux_cfg.dma3 = regk_strmux_strcop;
|
||||
else
|
||||
panic("Invalid DMA channel for strp\n");
|
||||
break;
|
||||
case dma_ser1:
|
||||
if (dmanr == 4)
|
||||
strmux_cfg.dma4 = regk_strmux_ser1;
|
||||
else if (dmanr == 5)
|
||||
strmux_cfg.dma5 = regk_strmux_ser1;
|
||||
else
|
||||
panic("Invalid DMA channel for ser1\n");
|
||||
break;
|
||||
case dma_iop:
|
||||
if (dmanr == 4)
|
||||
strmux_cfg.dma4 = regk_strmux_iop;
|
||||
else if (dmanr == 5)
|
||||
strmux_cfg.dma5 = regk_strmux_iop;
|
||||
else
|
||||
panic("Invalid DMA channel for iop\n");
|
||||
break;
|
||||
case dma_ser2:
|
||||
if (dmanr == 6)
|
||||
strmux_cfg.dma6 = regk_strmux_ser2;
|
||||
else if (dmanr == 7)
|
||||
strmux_cfg.dma7 = regk_strmux_ser2;
|
||||
else
|
||||
panic("Invalid DMA channel for ser2\n");
|
||||
break;
|
||||
case dma_sser:
|
||||
if (dmanr == 6)
|
||||
strmux_cfg.dma6 = regk_strmux_sser;
|
||||
else if (dmanr == 7)
|
||||
strmux_cfg.dma7 = regk_strmux_sser;
|
||||
else
|
||||
panic("Invalid DMA channel for sser\n");
|
||||
break;
|
||||
case dma_ser4:
|
||||
if (dmanr == 9)
|
||||
strmux_cfg.dma9 = regk_strmux_ser4;
|
||||
else
|
||||
panic("Invalid DMA channel for ser4\n");
|
||||
break;
|
||||
case dma_jpeg:
|
||||
if (dmanr == 9)
|
||||
strmux_cfg.dma9 = regk_strmux_jpeg;
|
||||
else
|
||||
panic("Invalid DMA channel for JPEG\n");
|
||||
break;
|
||||
case dma_h264:
|
||||
if (dmanr == 11)
|
||||
strmux_cfg.dma11 = regk_strmux_h264;
|
||||
else
|
||||
panic("Invalid DMA channel for H264\n");
|
||||
break;
|
||||
}
|
||||
|
||||
used_dma_channels[dmanr] = 1;
|
||||
used_dma_channels_users[dmanr] = device_id;
|
||||
REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
|
||||
REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void crisv32_free_dma(unsigned int dmanr)
|
||||
{
|
||||
spin_lock(&dma_lock);
|
||||
used_dma_channels[dmanr] = 0;
|
||||
spin_unlock(&dma_lock);
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* DDR SDRAM initialization - alter with care
|
||||
* This file is intended to be included from other assembler files
|
||||
*
|
||||
* Note: This file may not modify r8 or r9 because they are used to
|
||||
* carry information from the decompresser to the kernel
|
||||
*
|
||||
* Copyright (C) 2005-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Mikael Starvik <starvik@axis.com>
|
||||
*/
|
||||
|
||||
/* Just to be certain the config file is included, we include it here
|
||||
* explicitely instead of depending on it being included in the file that
|
||||
* uses this code.
|
||||
*/
|
||||
|
||||
#include <hwregs/asm/reg_map_asm.h>
|
||||
#include <hwregs/asm/ddr2_defs_asm.h>
|
||||
|
||||
;; WARNING! The registers r8 and r9 are used as parameters carrying
|
||||
;; information from the decompressor (if the kernel was compressed).
|
||||
;; They should not be used in the code below.
|
||||
|
||||
;; Refer to ddr2 MDS for initialization sequence
|
||||
|
||||
; Start clock
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_cfg), $r0
|
||||
move.d REG_STATE(ddr2, rw_phy_cfg, en, yes), $r1
|
||||
move.d $r1, [$r0]
|
||||
|
||||
; Reset phy and start calibration
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_ctrl), $r0
|
||||
move.d REG_STATE(ddr2, rw_phy_ctrl, rst, yes) | \
|
||||
REG_STATE(ddr2, rw_phy_ctrl, cal_rst, yes), $r1
|
||||
move.d $r1, [$r0]
|
||||
move.d REG_STATE(ddr2, rw_phy_ctrl, cal_start, yes), $r1
|
||||
move.d $r1, [$r0]
|
||||
|
||||
; 2. Wait 200us
|
||||
move.d 10000, $r2
|
||||
1: bne 1b
|
||||
subq 1, $r2
|
||||
|
||||
; Issue commands
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_ctrl), $r0
|
||||
move.d sdram_commands_start, $r2
|
||||
command_loop:
|
||||
movu.b [$r2+], $r1
|
||||
movu.w [$r2+], $r3
|
||||
do_cmd:
|
||||
lslq 16, $r1
|
||||
or.d $r3, $r1
|
||||
move.d $r1, [$r0]
|
||||
cmp.d sdram_commands_end, $r2
|
||||
blo command_loop
|
||||
nop
|
||||
|
||||
; Set timing
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing), $r0
|
||||
move.d CONFIG_ETRAX_DDR2_TIMING, $r1
|
||||
move.d $r1, [$r0]
|
||||
|
||||
; Set latency
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_latency), $r0
|
||||
move.d 0x13, $r1
|
||||
move.d $r1, [$r0]
|
||||
|
||||
; Set configuration
|
||||
move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg), $r0
|
||||
move.d CONFIG_ETRAX_DDR2_CONFIG, $r1
|
||||
move.d $r1, [$r0]
|
||||
|
||||
ba after_sdram_commands
|
||||
nop
|
||||
|
||||
sdram_commands_start:
|
||||
.byte regk_ddr2_deselect
|
||||
.word 0
|
||||
.byte regk_ddr2_pre
|
||||
.word regk_ddr2_pre_all
|
||||
.byte regk_ddr2_emrs2
|
||||
.word 0
|
||||
.byte regk_ddr2_emrs3
|
||||
.word 0
|
||||
.byte regk_ddr2_emrs
|
||||
.word regk_ddr2_dll_en
|
||||
.byte regk_ddr2_mrs
|
||||
.word regk_ddr2_dll_rst
|
||||
.byte regk_ddr2_pre
|
||||
.word regk_ddr2_pre_all
|
||||
.byte regk_ddr2_ref
|
||||
.word 0
|
||||
.byte regk_ddr2_ref
|
||||
.word 0
|
||||
.byte regk_ddr2_mrs
|
||||
.word CONFIG_ETRAX_DDR2_MRS & 0xffff
|
||||
.byte regk_ddr2_emrs
|
||||
.word regk_ddr2_ocd_default | regk_ddr2_dll_en
|
||||
.byte regk_ddr2_emrs
|
||||
.word regk_ddr2_ocd_exit | regk_ddr2_dll_en | (CONFIG_ETRAX_DDR2_MRS >> 16)
|
||||
sdram_commands_end:
|
||||
.align 1
|
||||
after_sdram_commands:
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This table is used by some tools to extract hardware parameters.
|
||||
* The table should be included in the kernel and the decompressor.
|
||||
* Don't forget to update the tools if you change this table.
|
||||
*
|
||||
* Copyright (C) 2001-2007 Axis Communications AB
|
||||
*
|
||||
* Authors: Mikael Starvik <starvik@axis.com>
|
||||
*/
|
||||
|
||||
#include <hwregs/asm/reg_map_asm.h>
|
||||
#include <hwregs/asm/ddr2_defs_asm.h>
|
||||
#include <hwregs/asm/gio_defs_asm.h>
|
||||
|
||||
.ascii "HW_PARAM_MAGIC" ; Magic number
|
||||
.dword 0xc0004000 ; Kernel start address
|
||||
|
||||
; Debug port
|
||||
#ifdef CONFIG_ETRAX_DEBUG_PORT0
|
||||
.dword 0
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
|
||||
.dword 1
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
|
||||
.dword 2
|
||||
#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
|
||||
.dword 3
|
||||
#else
|
||||
.dword 4 ; No debug
|
||||
#endif
|
||||
|
||||
; Register values
|
||||
.dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg)
|
||||
.dword CONFIG_ETRAX_DDR2_CONFIG
|
||||
.dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing)
|
||||
.dword CONFIG_ETRAX_DDR2_TIMING
|
||||
.dword CONFIG_ETRAX_DDR2_MRS
|
||||
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pa_dout)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PA_OUT
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pa_oe)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PA_OE
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pb_dout)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PB_OUT
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pb_oe)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PB_OE
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pc_dout)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PC_OUT
|
||||
.dword REG_ADDR(gio, regi_gio, rw_pc_oe)
|
||||
.dword CONFIG_ETRAX_DEF_GIO_PC_OE
|
||||
|
||||
.dword 0 ; No more register values
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Helper functions for I/O pins.
|
||||
*
|
||||
* Copyright (c) 2005-2007 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/mach/pinmux.h>
|
||||
#include <hwregs/gio_defs.h>
|
||||
|
||||
struct crisv32_ioport crisv32_ioports[] = {
|
||||
{
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din),
|
||||
32
|
||||
},
|
||||
{
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din),
|
||||
32
|
||||
},
|
||||
{
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout),
|
||||
(unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din),
|
||||
16
|
||||
},
|
||||
};
|
||||
|
||||
#define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport)
|
||||
|
||||
struct crisv32_iopin crisv32_led_net0_green;
|
||||
struct crisv32_iopin crisv32_led_net0_red;
|
||||
struct crisv32_iopin crisv32_led2_green;
|
||||
struct crisv32_iopin crisv32_led2_red;
|
||||
struct crisv32_iopin crisv32_led3_green;
|
||||
struct crisv32_iopin crisv32_led3_red;
|
||||
|
||||
/* Dummy port used when green LED and red LED is on the same bit */
|
||||
static unsigned long io_dummy;
|
||||
static struct crisv32_ioport dummy_port = {
|
||||
&io_dummy,
|
||||
&io_dummy,
|
||||
&io_dummy,
|
||||
32
|
||||
};
|
||||
static struct crisv32_iopin dummy_led = {
|
||||
&dummy_port,
|
||||
0
|
||||
};
|
||||
|
||||
static int __init crisv32_io_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
u32 i;
|
||||
|
||||
/* Locks *should* be dynamically initialized. */
|
||||
for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++)
|
||||
spin_lock_init(&crisv32_ioports[i].lock);
|
||||
spin_lock_init(&dummy_port.lock);
|
||||
|
||||
/* Initialize LEDs */
|
||||
#if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO))
|
||||
ret += crisv32_io_get_name(&crisv32_led_net0_green,
|
||||
CONFIG_ETRAX_LED_G_NET0);
|
||||
crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out);
|
||||
if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) {
|
||||
ret += crisv32_io_get_name(&crisv32_led_net0_red,
|
||||
CONFIG_ETRAX_LED_R_NET0);
|
||||
crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out);
|
||||
} else
|
||||
crisv32_led_net0_red = dummy_led;
|
||||
#endif
|
||||
|
||||
ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G);
|
||||
ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R);
|
||||
ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G);
|
||||
ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R);
|
||||
|
||||
crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out);
|
||||
crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
__initcall(crisv32_io_init);
|
||||
|
||||
int crisv32_io_get(struct crisv32_iopin *iopin,
|
||||
unsigned int port, unsigned int pin)
|
||||
{
|
||||
if (port > NBR_OF_PORTS)
|
||||
return -EINVAL;
|
||||
if (port > crisv32_ioports[port].pin_count)
|
||||
return -EINVAL;
|
||||
|
||||
iopin->bit = 1 << pin;
|
||||
iopin->port = &crisv32_ioports[port];
|
||||
|
||||
if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name)
|
||||
{
|
||||
int port;
|
||||
int pin;
|
||||
|
||||
if (toupper(*name) == 'P')
|
||||
name++;
|
||||
|
||||
if (toupper(*name) < 'A' || toupper(*name) > 'E')
|
||||
return -EINVAL;
|
||||
|
||||
port = toupper(*name) - 'A';
|
||||
name++;
|
||||
pin = simple_strtoul(name, NULL, 10);
|
||||
|
||||
if (pin < 0 || pin > crisv32_ioports[port].pin_count)
|
||||
return -EINVAL;
|
||||
|
||||
iopin->bit = 1 << pin;
|
||||
iopin->port = &crisv32_ioports[port];
|
||||
|
||||
if (crisv32_pinmux_alloc(port, pin, pin, pinmux_gpio))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
/* PCI I/O access stuff */
|
||||
struct cris_io_operations *cris_iops = NULL;
|
||||
EXPORT_SYMBOL(cris_iops);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Allocator for I/O pins. All pins are allocated to GPIO at bootup.
|
||||
* Unassigned pins and GPIO pins can be allocated to a fixed interface
|
||||
* or the I/O processor instead.
|
||||
*
|
||||
* Copyright (c) 2005-2007 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <pinmux.h>
|
||||
#include <hwregs/pinmux_defs.h>
|
||||
#include <hwregs/clkgen_defs.h>
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#define PINS 80
|
||||
#define PORT_PINS 32
|
||||
#define PORTS 3
|
||||
|
||||
static char pins[PINS];
|
||||
static DEFINE_SPINLOCK(pinmux_lock);
|
||||
|
||||
static void crisv32_pinmux_set(int port);
|
||||
|
||||
int
|
||||
crisv32_pinmux_init(void)
|
||||
{
|
||||
static int initialized;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);
|
||||
crisv32_pinmux_alloc(PORT_A, 0, 31, pinmux_gpio);
|
||||
crisv32_pinmux_alloc(PORT_B, 0, 31, pinmux_gpio);
|
||||
crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
crisv32_pinmux_init();
|
||||
|
||||
if (port >= PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pinmux_lock, flags);
|
||||
|
||||
for (i = first_pin; i <= last_pin; i++) {
|
||||
if ((pins[port * PORT_PINS + i] != pinmux_none) &&
|
||||
(pins[port * PORT_PINS + i] != pinmux_gpio) &&
|
||||
(pins[port * PORT_PINS + i] != mode)) {
|
||||
spin_unlock_irqrestore(&pinmux_lock, flags);
|
||||
#ifdef DEBUG
|
||||
panic("Pinmux alloc failed!\n");
|
||||
#endif
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = first_pin; i <= last_pin; i++)
|
||||
pins[port * PORT_PINS + i] = mode;
|
||||
|
||||
crisv32_pinmux_set(port);
|
||||
|
||||
spin_unlock_irqrestore(&pinmux_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
crisv32_pinmux_alloc_fixed(enum fixed_function function)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
char saved[sizeof pins];
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pinmux_lock, flags);
|
||||
|
||||
/* Save internal data for recovery */
|
||||
memcpy(saved, pins, sizeof pins);
|
||||
|
||||
crisv32_pinmux_init(); /* must be done before we read rw_hwprot */
|
||||
|
||||
reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
|
||||
reg_clkgen_rw_clk_ctrl clk_ctrl = REG_RD(clkgen, regi_clkgen,
|
||||
rw_clk_ctrl);
|
||||
|
||||
switch (function) {
|
||||
case pinmux_eth:
|
||||
clk_ctrl.eth = regk_clkgen_yes;
|
||||
clk_ctrl.dma0_1_eth = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_B, 8, 23, pinmux_fixed);
|
||||
ret |= crisv32_pinmux_alloc(PORT_B, 24, 25, pinmux_fixed);
|
||||
hwprot.eth = hwprot.eth_mdio = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_geth:
|
||||
ret = crisv32_pinmux_alloc(PORT_B, 0, 7, pinmux_fixed);
|
||||
hwprot.geth = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_tg_cmos:
|
||||
clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_B, 27, 29, pinmux_fixed);
|
||||
hwprot.tg_clk = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_tg_ccd:
|
||||
clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_B, 27, 31, pinmux_fixed);
|
||||
ret |= crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_fixed);
|
||||
hwprot.tg = hwprot.tg_clk = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_vout:
|
||||
clk_ctrl.strdma0_2_video = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 8, 18, pinmux_fixed);
|
||||
hwprot.vout = hwprot.vout_sync = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_ser1:
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 24, 25, pinmux_fixed);
|
||||
hwprot.ser1 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_ser2:
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 26, 27, pinmux_fixed);
|
||||
hwprot.ser2 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_ser3:
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 28, 29, pinmux_fixed);
|
||||
hwprot.ser3 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_ser4:
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 30, 31, pinmux_fixed);
|
||||
hwprot.ser4 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_sser:
|
||||
clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes;
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 19, 23, pinmux_fixed);
|
||||
hwprot.sser = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_pio:
|
||||
hwprot.pio = regk_pinmux_yes;
|
||||
ret = 0;
|
||||
break;
|
||||
case pinmux_pwm0:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 30, 30, pinmux_fixed);
|
||||
hwprot.pwm0 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_pwm1:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 31, 31, pinmux_fixed);
|
||||
hwprot.pwm1 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_pwm2:
|
||||
ret = crisv32_pinmux_alloc(PORT_B, 26, 26, pinmux_fixed);
|
||||
hwprot.pwm2 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c0:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 0, 1, pinmux_fixed);
|
||||
hwprot.i2c0 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c1:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
|
||||
hwprot.i2c1 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c1_3wire:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
|
||||
ret |= crisv32_pinmux_alloc(PORT_A, 7, 7, pinmux_fixed);
|
||||
hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c1_sda1:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 2, 4, pinmux_fixed);
|
||||
hwprot.i2c1 = hwprot.i2c1_sda1 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c1_sda2:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
|
||||
ret |= crisv32_pinmux_alloc(PORT_A, 5, 5, pinmux_fixed);
|
||||
hwprot.i2c1 = hwprot.i2c1_sda2 = regk_pinmux_yes;
|
||||
break;
|
||||
case pinmux_i2c1_sda3:
|
||||
ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed);
|
||||
ret |= crisv32_pinmux_alloc(PORT_A, 6, 6, pinmux_fixed);
|
||||
hwprot.i2c1 = hwprot.i2c1_sda3 = regk_pinmux_yes;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
|
||||
REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
|
||||
} else
|
||||
memcpy(pins, saved, sizeof pins);
|
||||
|
||||
spin_unlock_irqrestore(&pinmux_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
crisv32_pinmux_set(int port)
|
||||
{
|
||||
int i;
|
||||
int gpio_val = 0;
|
||||
int iop_val = 0;
|
||||
int pin = port * PORT_PINS;
|
||||
|
||||
for (i = 0; (i < PORT_PINS) && (pin < PINS); i++, pin++) {
|
||||
if (pins[pin] == pinmux_gpio)
|
||||
gpio_val |= (1 << i);
|
||||
else if (pins[pin] == pinmux_iop)
|
||||
iop_val |= (1 << i);
|
||||
}
|
||||
|
||||
REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_gio_pa + 4 * port,
|
||||
gpio_val);
|
||||
REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_iop_pa + 4 * port,
|
||||
iop_val);
|
||||
|
||||
#ifdef DEBUG
|
||||
crisv32_pinmux_dump();
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
crisv32_pinmux_init();
|
||||
|
||||
if (port > PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pinmux_lock, flags);
|
||||
|
||||
for (i = first_pin; i <= last_pin; i++)
|
||||
pins[port * PORT_PINS + i] = pinmux_none;
|
||||
|
||||
crisv32_pinmux_set(port);
|
||||
spin_unlock_irqrestore(&pinmux_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
crisv32_pinmux_dealloc_fixed(enum fixed_function function)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
char saved[sizeof pins];
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&pinmux_lock, flags);
|
||||
|
||||
/* Save internal data for recovery */
|
||||
memcpy(saved, pins, sizeof pins);
|
||||
|
||||
crisv32_pinmux_init(); /* must be done before we read rw_hwprot */
|
||||
|
||||
reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
|
||||
|
||||
switch (function) {
|
||||
case pinmux_eth:
|
||||
ret = crisv32_pinmux_dealloc(PORT_B, 8, 23);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_B, 24, 25);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_B, 0, 7);
|
||||
hwprot.eth = hwprot.eth_mdio = hwprot.geth = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_tg_cmos:
|
||||
ret = crisv32_pinmux_dealloc(PORT_B, 27, 29);
|
||||
hwprot.tg_clk = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_tg_ccd:
|
||||
ret = crisv32_pinmux_dealloc(PORT_B, 27, 31);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_C, 0, 15);
|
||||
hwprot.tg = hwprot.tg_clk = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_vout:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 8, 18);
|
||||
hwprot.vout = hwprot.vout_sync = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_ser1:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 24, 25);
|
||||
hwprot.ser1 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_ser2:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 26, 27);
|
||||
hwprot.ser2 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_ser3:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 28, 29);
|
||||
hwprot.ser3 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_ser4:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 30, 31);
|
||||
hwprot.ser4 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_sser:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 19, 23);
|
||||
hwprot.sser = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_pwm0:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 30, 30);
|
||||
hwprot.pwm0 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_pwm1:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 31, 31);
|
||||
hwprot.pwm1 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_pwm2:
|
||||
ret = crisv32_pinmux_dealloc(PORT_B, 26, 26);
|
||||
hwprot.pwm2 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c0:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 0, 1);
|
||||
hwprot.i2c0 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c1:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
|
||||
hwprot.i2c1 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c1_3wire:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_A, 7, 7);
|
||||
hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c1_sda1:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 2, 4);
|
||||
hwprot.i2c1_sda1 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c1_sda2:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_A, 5, 5);
|
||||
hwprot.i2c1_sda2 = regk_pinmux_no;
|
||||
break;
|
||||
case pinmux_i2c1_sda3:
|
||||
ret = crisv32_pinmux_dealloc(PORT_A, 2, 3);
|
||||
ret |= crisv32_pinmux_dealloc(PORT_A, 6, 6);
|
||||
hwprot.i2c1_sda3 = regk_pinmux_no;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
|
||||
else
|
||||
memcpy(pins, saved, sizeof pins);
|
||||
|
||||
spin_unlock_irqrestore(&pinmux_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
crisv32_pinmux_dump(void)
|
||||
{
|
||||
int i, j;
|
||||
int pin = 0;
|
||||
|
||||
crisv32_pinmux_init();
|
||||
|
||||
for (i = 0; i < PORTS; i++) {
|
||||
pin++;
|
||||
printk(KERN_DEBUG "Port %c\n", 'A'+i);
|
||||
for (j = 0; (j < PORT_PINS) && (pin < PINS); j++, pin++)
|
||||
printk(KERN_DEBUG
|
||||
" Pin %d = %d\n", j, pins[i * PORT_PINS + j]);
|
||||
}
|
||||
}
|
||||
|
||||
__initcall(crisv32_pinmux_init);
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Simulator hook mechanism
|
||||
*/
|
||||
|
||||
#include "vcs_hook.h"
|
||||
#include <asm/io.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define HOOK_TRIG_ADDR 0xb7000000
|
||||
#define HOOK_MEM_BASE_ADDR 0xce000000
|
||||
|
||||
static volatile unsigned *hook_base;
|
||||
|
||||
#define HOOK_DATA(offset) hook_base[offset]
|
||||
#define VHOOK_DATA(offset) hook_base[offset]
|
||||
#define HOOK_TRIG(funcid) \
|
||||
do { \
|
||||
*((unsigned *) HOOK_TRIG_ADDR) = funcid; \
|
||||
} while (0)
|
||||
#define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset]
|
||||
|
||||
static void hook_init(void)
|
||||
{
|
||||
static int first = 1;
|
||||
if (first) {
|
||||
first = 0;
|
||||
hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned hook_trig(unsigned id)
|
||||
{
|
||||
unsigned ret;
|
||||
|
||||
/* preempt_disable(); */
|
||||
|
||||
/* Dummy read from mem to make sure data has propagated to memory
|
||||
* before trigging */
|
||||
ret = *hook_base;
|
||||
|
||||
/* trigger hook */
|
||||
HOOK_TRIG(id);
|
||||
|
||||
/* wait for call to finish */
|
||||
while (VHOOK_DATA(0) > 0) ;
|
||||
|
||||
/* extract return value */
|
||||
|
||||
ret = VHOOK_DATA(1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hook_call(unsigned id, unsigned pcnt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i;
|
||||
unsigned ret;
|
||||
|
||||
hook_init();
|
||||
|
||||
HOOK_DATA(0) = id;
|
||||
|
||||
va_start(ap, pcnt);
|
||||
for (i = 1; i <= pcnt; i++)
|
||||
HOOK_DATA(i) = va_arg(ap, unsigned);
|
||||
va_end(ap);
|
||||
|
||||
ret = hook_trig(id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hook_call_str(unsigned id, unsigned size, const char *str)
|
||||
{
|
||||
int i;
|
||||
unsigned ret;
|
||||
|
||||
hook_init();
|
||||
|
||||
HOOK_DATA(0) = id;
|
||||
HOOK_DATA(1) = size;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
HOOK_DATA_BYTE(8 + i) = str[i];
|
||||
HOOK_DATA_BYTE(8 + i) = 0;
|
||||
|
||||
ret = hook_trig(id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void print_str(const char *str)
|
||||
{
|
||||
int i;
|
||||
/* find null at end of string */
|
||||
for (i = 1; str[i]; i++) ;
|
||||
hook_call(hook_print_str, i, str);
|
||||
}
|
||||
|
||||
void CPU_WATCHDOG_TIMEOUT(unsigned t)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Simulator hook call mechanism
|
||||
*/
|
||||
|
||||
#ifndef __hook_h__
|
||||
#define __hook_h__
|
||||
|
||||
int hook_call(unsigned id, unsigned pcnt, ...);
|
||||
int hook_call_str(unsigned id, unsigned size, const char *str);
|
||||
|
||||
enum hook_ids {
|
||||
hook_debug_on = 1,
|
||||
hook_debug_off,
|
||||
hook_stop_sim_ok,
|
||||
hook_stop_sim_fail,
|
||||
hook_alloc_shared,
|
||||
hook_ptr_shared,
|
||||
hook_free_shared,
|
||||
hook_file2shared,
|
||||
hook_cmp_shared,
|
||||
hook_print_params,
|
||||
hook_sim_time,
|
||||
hook_stop_sim,
|
||||
hook_kick_dog,
|
||||
hook_dog_timeout,
|
||||
hook_rand,
|
||||
hook_srand,
|
||||
hook_rand_range,
|
||||
hook_print_str,
|
||||
hook_print_hex,
|
||||
hook_cmp_offset_shared,
|
||||
hook_fill_random_shared,
|
||||
hook_alloc_random_data,
|
||||
hook_calloc_random_data,
|
||||
hook_print_int,
|
||||
hook_print_uint,
|
||||
hook_fputc,
|
||||
hook_init_fd,
|
||||
hook_sbrk,
|
||||
hook_print_context_descr,
|
||||
hook_print_data_descr,
|
||||
hook_print_group_descr,
|
||||
hook_fill_shared,
|
||||
hook_sl_srand,
|
||||
hook_sl_rand_irange,
|
||||
hook_sl_rand_urange,
|
||||
hook_sl_sh_malloc_aligned,
|
||||
hook_sl_sh_calloc_aligned,
|
||||
hook_sl_sh_alloc_random_data,
|
||||
hook_sl_sh_file2mem,
|
||||
hook_sl_vera_mbox_handle,
|
||||
hook_sl_vera_mbox_put,
|
||||
hook_sl_vera_mbox_get,
|
||||
hook_sl_system,
|
||||
hook_sl_sh_hexdump
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
if ETRAXFS
|
||||
|
||||
menu "ETRAX FS options"
|
||||
depends on ETRAXFS
|
||||
|
||||
config ETRAX_DRAM_VIRTUAL_BASE
|
||||
hex
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "c0000000"
|
||||
|
||||
config ETRAX_SERIAL_PORTS
|
||||
int
|
||||
default 4
|
||||
|
||||
config ETRAX_MEM_GRP1_CONFIG
|
||||
hex "MEM_GRP1_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "4044a"
|
||||
help
|
||||
Waitstates for flash. The default value is suitable for the
|
||||
standard flashes used in axis products (120 ns).
|
||||
|
||||
config ETRAX_MEM_GRP2_CONFIG
|
||||
hex "MEM_GRP2_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "0"
|
||||
help
|
||||
Waitstates for SRAM. 0 is a good choice for most Axis products.
|
||||
|
||||
config ETRAX_MEM_GRP3_CONFIG
|
||||
hex "MEM_GRP3_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "0"
|
||||
help
|
||||
Waitstates for CSP0-3. 0 is a good choice for most Axis products.
|
||||
It may need to be changed if external devices such as extra
|
||||
register-mapped LEDs are used.
|
||||
|
||||
config ETRAX_MEM_GRP4_CONFIG
|
||||
hex "MEM_GRP4_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "0"
|
||||
help
|
||||
Waitstates for CSP4-6. 0 is a good choice for most Axis products.
|
||||
|
||||
config ETRAX_SDRAM_GRP0_CONFIG
|
||||
hex "SDRAM_GRP0_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "336"
|
||||
help
|
||||
SDRAM configuration for group 0. The value depends on the
|
||||
hardware configuration. The default value is suitable
|
||||
for 32 MB organized as two 16 bits chips (e.g. Axis
|
||||
part number 18550) connected as one 32 bit device (i.e. in
|
||||
the same group).
|
||||
|
||||
config ETRAX_SDRAM_GRP1_CONFIG
|
||||
hex "SDRAM_GRP1_CONFIG"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "0"
|
||||
help
|
||||
SDRAM configuration for group 1. The defult value is 0
|
||||
because group 1 is not used in the default configuration,
|
||||
described in the help for SDRAM_GRP0_CONFIG.
|
||||
|
||||
config ETRAX_SDRAM_TIMING
|
||||
hex "SDRAM_TIMING"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "104a"
|
||||
help
|
||||
SDRAM timing parameters. The default value is ok for
|
||||
most hardwares but large SDRAMs may require a faster
|
||||
refresh (a.k.a 8K refresh). The default value implies
|
||||
100MHz clock and SDR mode.
|
||||
|
||||
config ETRAX_SDRAM_COMMAND
|
||||
hex "SDRAM_COMMAND"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "0"
|
||||
help
|
||||
SDRAM command. Should be 0 unless you really know what
|
||||
you are doing (may be != 0 for unusual address line
|
||||
mappings such as in a MCM)..
|
||||
|
||||
config ETRAX_DEF_GIO_PA_OE
|
||||
hex "GIO_PA_OE"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "1c"
|
||||
help
|
||||
Configures the direction of general port A bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PA_OUT
|
||||
hex "GIO_PA_OUT"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00"
|
||||
help
|
||||
Configures the initial data for the general port A bits. Most
|
||||
products should use 00 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PB_OE
|
||||
hex "GIO_PB_OE"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the direction of general port B bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PB_OUT
|
||||
hex "GIO_PB_OUT"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the initial data for the general port B bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PC_OE
|
||||
hex "GIO_PC_OE"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the direction of general port C bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PC_OUT
|
||||
hex "GIO_PC_OUT"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the initial data for the general port C bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PD_OE
|
||||
hex "GIO_PD_OE"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the direction of general port D bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PD_OUT
|
||||
hex "GIO_PD_OUT"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the initial data for the general port D bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PE_OE
|
||||
hex "GIO_PE_OE"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the direction of general port E bits. 1 is out, 0 is in.
|
||||
This is often totally different depending on the product used.
|
||||
There are some guidelines though - if you know that only LED's are
|
||||
connected to port PA, then they are usually connected to bits 2-4
|
||||
and you can therefore use 1c. On other boards which don't have the
|
||||
LED's at the general ports, these bits are used for all kinds of
|
||||
stuff. If you don't know what to use, it is always safe to put all
|
||||
as inputs, although floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PE_OUT
|
||||
hex "GIO_PE_OUT"
|
||||
depends on ETRAX_ARCH_V32
|
||||
default "00000"
|
||||
help
|
||||
Configures the initial data for the general port E bits. Most
|
||||
products should use 00000 here.
|
||||
|
||||
config ETRAX_DEF_GIO_PV_OE
|
||||
hex "GIO_PV_OE"
|
||||
depends on ETRAX_VIRTUAL_GPIO
|
||||
default "0000"
|
||||
help
|
||||
Configures the direction of virtual general port V bits. 1 is out,
|
||||
0 is in. This is often totally different depending on the product
|
||||
used. These bits are used for all kinds of stuff. If you don't know
|
||||
what to use, it is always safe to put all as inputs, although
|
||||
floating inputs isn't good.
|
||||
|
||||
config ETRAX_DEF_GIO_PV_OUT
|
||||
hex "GIO_PV_OUT"
|
||||
depends on ETRAX_VIRTUAL_GPIO
|
||||
default "0000"
|
||||
help
|
||||
Configures the initial data for the virtual general port V bits.
|
||||
Most products should use 0000 here.
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
|
@ -0,0 +1,11 @@
|
|||
# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
obj-y := dma.o pinmux.o io.o arbiter.o
|
||||
bj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
|
||||
clean:
|
||||
|
|
@ -0,0 +1,404 @@
|
|||
/*
|
||||
* Memory arbiter functions. Allocates bandwidth through the
|
||||
* arbiter and sets up arbiter breakpoints.
|
||||
*
|
||||
* The algorithm first assigns slots to the clients that has specified
|
||||
* bandwidth (e.g. ethernet) and then the remaining slots are divided
|
||||
* on all the active clients.
|
||||
*
|
||||
* Copyright (c) 2004-2007 Axis Communications AB.
|
||||
*/
|
||||
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/marb_defs.h>
|
||||
#include <arbiter.h>
|
||||
#include <hwregs/intr_vect.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq_regs.h>
|
||||
|
||||
struct crisv32_watch_entry {
|
||||
unsigned long instance;
|
||||
watch_callback *cb;
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
int used;
|
||||
};
|
||||
|
||||
#define NUMBER_OF_BP 4
|
||||
#define NBR_OF_CLIENTS 14
|
||||
#define NBR_OF_SLOTS 64
|
||||
#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */
|
||||
#define INTMEM_BANDWIDTH 400000000
|
||||
#define NBR_OF_REGIONS 2
|
||||
|
||||
static struct crisv32_watch_entry watches[NUMBER_OF_BP] = {
|
||||
{regi_marb_bp0},
|
||||
{regi_marb_bp1},
|
||||
{regi_marb_bp2},
|
||||
{regi_marb_bp3}
|
||||
};
|
||||
|
||||
static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS];
|
||||
static int max_bandwidth[NBR_OF_REGIONS] =
|
||||
{ SDRAM_BANDWIDTH, INTMEM_BANDWIDTH };
|
||||
|
||||
DEFINE_SPINLOCK(arbiter_lock);
|
||||
|
||||
static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id);
|
||||
|
||||
/*
|
||||
* "I'm the arbiter, I know the score.
|
||||
* From square one I'll be watching all 64."
|
||||
* (memory arbiter slots, that is)
|
||||
*
|
||||
* Or in other words:
|
||||
* Program the memory arbiter slots for "region" according to what's
|
||||
* in requested_slots[] and active_clients[], while minimizing
|
||||
* latency. A caller may pass a non-zero positive amount for
|
||||
* "unused_slots", which must then be the unallocated, remaining
|
||||
* number of slots, free to hand out to any client.
|
||||
*/
|
||||
|
||||
static void crisv32_arbiter_config(int region, int unused_slots)
|
||||
{
|
||||
int slot;
|
||||
int client;
|
||||
int interval = 0;
|
||||
|
||||
/*
|
||||
* This vector corresponds to the hardware arbiter slots (see
|
||||
* the hardware documentation for semantics). We initialize
|
||||
* each slot with a suitable sentinel value outside the valid
|
||||
* range {0 .. NBR_OF_CLIENTS - 1} and replace them with
|
||||
* client indexes. Then it's fed to the hardware.
|
||||
*/
|
||||
s8 val[NBR_OF_SLOTS];
|
||||
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++)
|
||||
val[slot] = -1;
|
||||
|
||||
for (client = 0; client < NBR_OF_CLIENTS; client++) {
|
||||
int pos;
|
||||
/* Allocate the requested non-zero number of slots, but
|
||||
* also give clients with zero-requests one slot each
|
||||
* while stocks last. We do the latter here, in client
|
||||
* order. This makes sure zero-request clients are the
|
||||
* first to get to any spare slots, else those slots
|
||||
* could, when bandwidth is allocated close to the limit,
|
||||
* all be allocated to low-index non-zero-request clients
|
||||
* in the default-fill loop below. Another positive but
|
||||
* secondary effect is a somewhat better spread of the
|
||||
* zero-bandwidth clients in the vector, avoiding some of
|
||||
* the latency that could otherwise be caused by the
|
||||
* partitioning of non-zero-bandwidth clients at low
|
||||
* indexes and zero-bandwidth clients at high
|
||||
* indexes. (Note that this spreading can only affect the
|
||||
* unallocated bandwidth.) All the above only matters for
|
||||
* memory-intensive situations, of course.
|
||||
*/
|
||||
if (!requested_slots[region][client]) {
|
||||
/*
|
||||
* Skip inactive clients. Also skip zero-slot
|
||||
* allocations in this pass when there are no known
|
||||
* free slots.
|
||||
*/
|
||||
if (!active_clients[region][client]
|
||||
|| unused_slots <= 0)
|
||||
continue;
|
||||
|
||||
unused_slots--;
|
||||
|
||||
/* Only allocate one slot for this client. */
|
||||
interval = NBR_OF_SLOTS;
|
||||
} else
|
||||
interval =
|
||||
NBR_OF_SLOTS / requested_slots[region][client];
|
||||
|
||||
pos = 0;
|
||||
while (pos < NBR_OF_SLOTS) {
|
||||
if (val[pos] >= 0)
|
||||
pos++;
|
||||
else {
|
||||
val[pos] = client;
|
||||
pos += interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client = 0;
|
||||
for (slot = 0; slot < NBR_OF_SLOTS; slot++) {
|
||||
/*
|
||||
* Allocate remaining slots in round-robin
|
||||
* client-number order for active clients. For this
|
||||
* pass, we ignore requested bandwidth and previous
|
||||
* allocations.
|
||||
*/
|
||||
if (val[slot] < 0) {
|
||||
int first = client;
|
||||
while (!active_clients[region][client]) {
|
||||
client = (client + 1) % NBR_OF_CLIENTS;
|
||||
if (client == first)
|
||||
break;
|
||||
}
|
||||
val[slot] = client;
|
||||
client = (client + 1) % NBR_OF_CLIENTS;
|
||||
}
|
||||
if (region == EXT_REGION)
|
||||
REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot,
|
||||
val[slot]);
|
||||
else if (region == INT_REGION)
|
||||
REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot,
|
||||
val[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
extern char _stext, _etext;
|
||||
|
||||
static void crisv32_arbiter_init(void)
|
||||
{
|
||||
static int initialized;
|
||||
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
initialized = 1;
|
||||
|
||||
/*
|
||||
* CPU caches are always set to active, but with zero
|
||||
* bandwidth allocated. It should be ok to allocate zero
|
||||
* bandwidth for the caches, because DMA for other channels
|
||||
* will supposedly finish, once their programmed amount is
|
||||
* done, and then the caches will get access according to the
|
||||
* "fixed scheme" for unclaimed slots. Though, if for some
|
||||
* use-case somewhere, there's a maximum CPU latency for
|
||||
* e.g. some interrupt, we have to start allocating specific
|
||||
* bandwidth for the CPU caches too.
|
||||
*/
|
||||
active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1;
|
||||
crisv32_arbiter_config(EXT_REGION, 0);
|
||||
crisv32_arbiter_config(INT_REGION, 0);
|
||||
|
||||
if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
|
||||
"arbiter", NULL))
|
||||
printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
|
||||
|
||||
#ifndef CONFIG_ETRAX_KGDB
|
||||
/* Global watch for writes to kernel text segment. */
|
||||
crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext,
|
||||
arbiter_all_clients, arbiter_all_write, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Main entry for bandwidth allocation. */
|
||||
|
||||
int crisv32_arbiter_allocate_bandwidth(int client, int region,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
int i;
|
||||
int total_assigned = 0;
|
||||
int total_clients = 0;
|
||||
int req;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
for (i = 0; i < NBR_OF_CLIENTS; i++) {
|
||||
total_assigned += requested_slots[region][i];
|
||||
total_clients += active_clients[region][i];
|
||||
}
|
||||
|
||||
/* Avoid division by 0 for 0-bandwidth requests. */
|
||||
req = bandwidth == 0
|
||||
? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth);
|
||||
|
||||
/*
|
||||
* We make sure that there are enough slots only for non-zero
|
||||
* requests. Requesting 0 bandwidth *may* allocate slots,
|
||||
* though if all bandwidth is allocated, such a client won't
|
||||
* get any and will have to rely on getting memory access
|
||||
* according to the fixed scheme that's the default when one
|
||||
* of the slot-allocated clients doesn't claim their slot.
|
||||
*/
|
||||
if (total_assigned + req > NBR_OF_SLOTS)
|
||||
return -ENOMEM;
|
||||
|
||||
active_clients[region][client] = 1;
|
||||
requested_slots[region][client] = req;
|
||||
crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry for bandwidth deallocation.
|
||||
*
|
||||
* Strictly speaking, for a somewhat constant set of clients where
|
||||
* each client gets a constant bandwidth and is just enabled or
|
||||
* disabled (somewhat dynamically), no action is necessary here to
|
||||
* avoid starvation for non-zero-allocation clients, as the allocated
|
||||
* slots will just be unused. However, handing out those unused slots
|
||||
* to active clients avoids needless latency if the "fixed scheme"
|
||||
* would give unclaimed slots to an eager low-index client.
|
||||
*/
|
||||
|
||||
void crisv32_arbiter_deallocate_bandwidth(int client, int region)
|
||||
{
|
||||
int i;
|
||||
int total_assigned = 0;
|
||||
|
||||
requested_slots[region][client] = 0;
|
||||
active_clients[region][client] = 0;
|
||||
|
||||
for (i = 0; i < NBR_OF_CLIENTS; i++)
|
||||
total_assigned += requested_slots[region][i];
|
||||
|
||||
crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned);
|
||||
}
|
||||
|
||||
int crisv32_arbiter_watch(unsigned long start, unsigned long size,
|
||||
unsigned long clients, unsigned long accesses,
|
||||
watch_callback *cb)
|
||||
{
|
||||
int i;
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
if (start > 0x80000000) {
|
||||
printk(KERN_ERR "Arbiter: %lX doesn't look like a "
|
||||
"physical address", start);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
for (i = 0; i < NUMBER_OF_BP; i++) {
|
||||
if (!watches[i].used) {
|
||||
reg_marb_rw_intr_mask intr_mask =
|
||||
REG_RD(marb, regi_marb, rw_intr_mask);
|
||||
|
||||
watches[i].used = 1;
|
||||
watches[i].start = start;
|
||||
watches[i].end = start + size;
|
||||
watches[i].cb = cb;
|
||||
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr,
|
||||
watches[i].start);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr,
|
||||
watches[i].end);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_op,
|
||||
accesses);
|
||||
REG_WR_INT(marb_bp, watches[i].instance, rw_clients,
|
||||
clients);
|
||||
|
||||
if (i == 0)
|
||||
intr_mask.bp0 = regk_marb_yes;
|
||||
else if (i == 1)
|
||||
intr_mask.bp1 = regk_marb_yes;
|
||||
else if (i == 2)
|
||||
intr_mask.bp2 = regk_marb_yes;
|
||||
else if (i == 3)
|
||||
intr_mask.bp3 = regk_marb_yes;
|
||||
|
||||
REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
|
||||
spin_unlock(&arbiter_lock);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
spin_unlock(&arbiter_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int crisv32_arbiter_unwatch(int id)
|
||||
{
|
||||
reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask);
|
||||
|
||||
crisv32_arbiter_init();
|
||||
|
||||
spin_lock(&arbiter_lock);
|
||||
|
||||
if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) {
|
||||
spin_unlock(&arbiter_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&watches[id], 0, sizeof(struct crisv32_watch_entry));
|
||||
|
||||
if (id == 0)
|
||||
intr_mask.bp0 = regk_marb_no;
|
||||
else if (id == 1)
|
||||
intr_mask.bp2 = regk_marb_no;
|
||||
else if (id == 2)
|
||||
intr_mask.bp2 = regk_marb_no;
|
||||
else if (id == 3)
|
||||
intr_mask.bp3 = regk_marb_no;
|
||||
|
||||
REG_WR(marb, regi_marb, rw_intr_mask, intr_mask);
|
||||
|
||||
spin_unlock(&arbiter_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void show_registers(struct pt_regs *regs);
|
||||
|
||||
static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id)
|
||||
{
|
||||
reg_marb_r_masked_intr masked_intr =
|
||||
REG_RD(marb, regi_marb, r_masked_intr);
|
||||
reg_marb_bp_r_brk_clients r_clients;
|
||||
reg_marb_bp_r_brk_addr r_addr;
|
||||
reg_marb_bp_r_brk_op r_op;
|
||||
reg_marb_bp_r_brk_first_client r_first;
|
||||
reg_marb_bp_r_brk_size r_size;
|
||||
reg_marb_bp_rw_ack ack = { 0 };
|
||||
reg_marb_rw_ack_intr ack_intr = {
|
||||
.bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1
|
||||
};
|
||||
struct crisv32_watch_entry *watch;
|
||||
|
||||
if (masked_intr.bp0) {
|
||||
watch = &watches[0];
|
||||
ack_intr.bp0 = regk_marb_yes;
|
||||
} else if (masked_intr.bp1) {
|
||||
watch = &watches[1];
|
||||
ack_intr.bp1 = regk_marb_yes;
|
||||
} else if (masked_intr.bp2) {
|
||||
watch = &watches[2];
|
||||
ack_intr.bp2 = regk_marb_yes;
|
||||
} else if (masked_intr.bp3) {
|
||||
watch = &watches[3];
|
||||
ack_intr.bp3 = regk_marb_yes;
|
||||
} else {
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* Retrieve all useful information and print it. */
|
||||
r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients);
|
||||
r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr);
|
||||
r_op = REG_RD(marb_bp, watch->instance, r_brk_op);
|
||||
r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client);
|
||||
r_size = REG_RD(marb_bp, watch->instance, r_brk_size);
|
||||
|
||||
printk(KERN_INFO "Arbiter IRQ\n");
|
||||
printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n",
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first),
|
||||
REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size));
|
||||
|
||||
REG_WR(marb_bp, watch->instance, rw_ack, ack);
|
||||
REG_WR(marb, regi_marb, rw_ack_intr, ack_intr);
|
||||
|
||||
printk(KERN_INFO "IRQ occured at %lX\n", get_irq_regs()->erp);
|
||||
|
||||
if (watch->cb)
|
||||
watch->cb();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/config_defs.h>
|
||||
#include <asm/arch/hwregs/bif_core_defs.h>
|
||||
|
||||
static int
|
||||
cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data);
|
||||
|
||||
static struct notifier_block cris_sdram_freq_notifier_block = {
|
||||
.notifier_call = cris_sdram_freq_notifier
|
||||
};
|
||||
|
||||
static struct cpufreq_frequency_table cris_freq_table[] = {
|
||||
{0x01, 6000},
|
||||
{0x02, 200000},
|
||||
{0, CPUFREQ_TABLE_END},
|
||||
};
|
||||
|
||||
static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
|
||||
{
|
||||
reg_config_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
|
||||
return clk_ctrl.pll ? 200000 : 6000;
|
||||
}
|
||||
|
||||
static void cris_freq_set_cpu_state(unsigned int state)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_config_rw_clk_ctrl clk_ctrl;
|
||||
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
freqs.old = cris_freq_get_cpu_frequency(i);
|
||||
freqs.new = cris_freq_table[state].frequency;
|
||||
freqs.cpu = i;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
/* Even though we may be SMP they will share the same clock
|
||||
* so all settings are made on CPU0. */
|
||||
if (cris_freq_table[state].frequency == 200000)
|
||||
clk_ctrl.pll = 1;
|
||||
else
|
||||
clk_ctrl.pll = 0;
|
||||
REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
};
|
||||
|
||||
static int cris_freq_verify(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);
|
||||
}
|
||||
|
||||
static int cris_freq_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq, unsigned int relation)
|
||||
{
|
||||
unsigned int newstate = 0;
|
||||
|
||||
if (cpufreq_frequency_table_target
|
||||
(policy, cris_freq_table, target_freq, relation, &newstate))
|
||||
return -EINVAL;
|
||||
|
||||
cris_freq_set_cpu_state(newstate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cris_freq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
|
||||
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
|
||||
policy->cur = cris_freq_get_cpu_frequency(0);
|
||||
|
||||
result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
|
||||
if (result)
|
||||
return (result);
|
||||
|
||||
cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cris_freq_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_put_attr(policy->cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr *cris_freq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver cris_freq_driver = {
|
||||
.get = cris_freq_get_cpu_frequency,
|
||||
.verify = cris_freq_verify,
|
||||
.target = cris_freq_target,
|
||||
.init = cris_freq_cpu_init,
|
||||
.exit = cris_freq_cpu_exit,
|
||||
.name = "cris_freq",
|
||||
.owner = THIS_MODULE,
|
||||
.attr = cris_freq_attr,
|
||||
};
|
||||
|
||||
static int __init cris_freq_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = cpufreq_register_driver(&cris_freq_driver);
|
||||
cpufreq_register_notifier(&cris_sdram_freq_notifier_block,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
int i;
|
||||
struct cpufreq_freqs *freqs = data;
|
||||
if (val == CPUFREQ_PRECHANGE) {
|
||||
reg_bif_core_rw_sdram_timing timing =
|
||||
REG_RD(bif_core, regi_bif_core, rw_sdram_timing);
|
||||
timing.cpd = (freqs->new == 200000 ? 0 : 1);
|
||||
|
||||
if (freqs->new == 200000)
|
||||
for (i = 0; i < 50000; i++) ;
|
||||
REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(cris_freq_init);
|
|
@ -3,49 +3,54 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/arch/hwregs/reg_map.h>
|
||||
#include <asm/arch/hwregs/reg_rdwr.h>
|
||||
#include <asm/arch/hwregs/marb_defs.h>
|
||||
#include <asm/arch/hwregs/config_defs.h>
|
||||
#include <asm/arch/hwregs/strmux_defs.h>
|
||||
#include <hwregs/reg_map.h>
|
||||
#include <hwregs/reg_rdwr.h>
|
||||
#include <hwregs/marb_defs.h>
|
||||
#include <hwregs/config_defs.h>
|
||||
#include <hwregs/strmux_defs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/arch/arbiter.h>
|
||||
#include <asm/arch/mach/arbiter.h>
|
||||
|
||||
static char used_dma_channels[MAX_DMA_CHANNELS];
|
||||
static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
|
||||
static const char *used_dma_channels_users[MAX_DMA_CHANNELS];
|
||||
|
||||
static DEFINE_SPINLOCK(dma_lock);
|
||||
|
||||
int crisv32_request_dma(unsigned int dmanr, const char * device_id,
|
||||
unsigned options, unsigned int bandwidth,
|
||||
int crisv32_request_dma(unsigned int dmanr, const char *device_id,
|
||||
unsigned options, unsigned int bandwidth,
|
||||
enum dma_owner owner)
|
||||
{
|
||||
unsigned long flags;
|
||||
reg_config_rw_clk_ctrl clk_ctrl;
|
||||
reg_strmux_rw_cfg strmux_cfg;
|
||||
|
||||
if (crisv32_arbiter_allocate_bandwidth(dmanr,
|
||||
options & DMA_INT_MEM ? INT_REGION : EXT_REGION,
|
||||
bandwidth))
|
||||
return -ENOMEM;
|
||||
if (crisv32_arbiter_allocate_bandwidth(dmanr,
|
||||
options & DMA_INT_MEM ?
|
||||
INT_REGION : EXT_REGION,
|
||||
bandwidth))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&dma_lock, flags);
|
||||
|
||||
if (used_dma_channels[dmanr]) {
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
if (options & DMA_VERBOSE_ON_ERROR) {
|
||||
printk("Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
|
||||
printk(KERN_ERR "Failed to request DMA %i for %s, "
|
||||
"already allocated by %s\n",
|
||||
dmanr,
|
||||
device_id,
|
||||
used_dma_channels_users[dmanr]);
|
||||
}
|
||||
if (options & DMA_PANIC_ON_ERROR)
|
||||
panic("request_dma error!");
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
|
||||
strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg);
|
||||
|
||||
switch(dmanr)
|
||||
{
|
||||
switch (dmanr) {
|
||||
case 0:
|
||||
case 1:
|
||||
clk_ctrl.dma01_eth0 = 1;
|
||||
|
@ -72,7 +77,9 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
|
|||
default:
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
if (options & DMA_VERBOSE_ON_ERROR) {
|
||||
printk("Failed to request DMA %i for %s, only 0-%i valid)\n", dmanr, device_id, MAX_DMA_CHANNELS-1);
|
||||
printk(KERN_ERR "Failed to request DMA %i for %s, "
|
||||
"only 0-%i valid)\n",
|
||||
dmanr, device_id, MAX_DMA_CHANNELS - 1);
|
||||
}
|
||||
|
||||
if (options & DMA_PANIC_ON_ERROR)
|
||||
|
@ -80,8 +87,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch(owner)
|
||||
{
|
||||
switch (owner) {
|
||||
case dma_eth0:
|
||||
if (dmanr == 0)
|
||||
strmux_cfg.dma0 = regk_strmux_eth0;
|
||||
|
@ -212,7 +218,7 @@ int crisv32_request_dma(unsigned int dmanr, const char * device_id,
|
|||
used_dma_channels_users[dmanr] = device_id;
|
||||
REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl);
|
||||
REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg);
|
||||
spin_unlock_irqrestore(&dma_lock,flags);
|
||||
spin_unlock_irqrestore(&dma_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue