提交 b98adfcc 编写于 作者: L Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/lethal/sh-2.6: (108 commits)
  sh: Fix occasional flush_cache_4096() stack corruption.
  sh: Calculate shm alignment at runtime.
  sh: dma-mapping compile fixes.
  sh: Initial vsyscall page support.
  sh: Clean up PAGE_SIZE definition for assembly use.
  sh: Selective flush_cache_mm() flushing.
  sh: More intelligent entry_mask/way_size calculation.
  sh: Support for L2 cache on newer SH-4A CPUs.
  sh: Update kexec support for API changes.
  sh: Optimized readsl()/writesl() support.
  sh: Report movli.l/movco.l capabilities.
  sh: CPU flags in AT_HWCAP in ELF auxvt.
  sh: Add support for 4K stacks.
  sh: Enable /proc/kcore support.
  sh: stack debugging support.
  sh: select CONFIG_EMBEDDED.
  sh: machvec rework.
  sh: Solution Engine SH7343 board support.
  sh: SH7710VoIPGW board support.
  sh: Enable verbose BUG() support.
  ...
......@@ -41,11 +41,6 @@ Board-specific code:
|
.. more boards here ...
It should also be noted that each board is required to have some certain
headers. At the time of this writing, io.h is the only thing that needs
to be provided for each board, and can generally just reference generic
functions (with the exception of isa_port2addr).
Next, for companion chips:
.
`-- arch
......@@ -104,12 +99,13 @@ and then populate that with sub-directories for each member of the family.
Both the Solution Engine and the hp6xx boards are an example of this.
After you have setup your new arch/sh/boards/ directory, remember that you
also must add a directory in include/asm-sh for headers localized to this
board. In order to interoperate seamlessly with the build system, it's best
to have this directory the same as the arch/sh/boards/ directory name,
though if your board is again part of a family, the build system has ways
of dealing with this, and you can feel free to name the directory after
the family member itself.
should also add a directory in include/asm-sh for headers localized to this
board (if there are going to be more than one). In order to interoperate
seamlessly with the build system, it's best to have this directory the same
as the arch/sh/boards/ directory name, though if your board is again part of
a family, the build system has ways of dealing with this (via incdir-y
overloading), and you can feel free to name the directory after the family
member itself.
There are a few things that each board is required to have, both in the
arch/sh/boards and the include/asm-sh/ heirarchy. In order to better
......@@ -122,6 +118,7 @@ might look something like:
* arch/sh/boards/vapor/setup.c - Setup code for imaginary board
*/
#include <linux/init.h>
#include <asm/rtc.h> /* for board_time_init() */
const char *get_system_type(void)
{
......@@ -152,79 +149,57 @@ int __init platform_setup(void)
}
Our new imaginary board will also have to tie into the machvec in order for it
to be of any use. Currently the machvec is slowly on its way out, but is still
required for the time being. As such, let us take a look at what needs to be
done for the machvec assignment.
to be of any use.
machvec functions fall into a number of categories:
- I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
- I/O remapping functions (ioremap etc)
- some initialisation functions
- a 'heartbeat' function
- some miscellaneous flags
The tree can be built in two ways:
- as a fully generic build. All drivers are linked in, and all functions
go through the machvec
- as a machine specific build. In this case only the required drivers
will be linked in, and some macros may be redefined to not go through
the machvec where performance is important (in particular IO functions).
There are three ways in which IO can be performed:
- none at all. This is really only useful for the 'unknown' machine type,
which us designed to run on a machine about which we know nothing, and
so all all IO instructions do nothing.
- fully custom. In this case all IO functions go to a machine specific
set of functions which can do what they like
- a generic set of functions. These will cope with most situations,
and rely on a single function, mv_port2addr, which is called through the
machine vector, and converts an IO address into a memory address, which
can be read from/written to directly.
Thus adding a new machine involves the following steps (I will assume I am
adding a machine called vapor):
- add a new file include/asm-sh/vapor/io.h which contains prototypes for
- I/O mapping functions (ioport_map, ioport_unmap, etc).
- a 'heartbeat' function.
- PCI and IRQ initialization routines.
- Consistent allocators (for boards that need special allocators,
particularly for allocating out of some board-specific SRAM for DMA
handles).
There are machvec functions added and removed over time, so always be sure to
consult include/asm-sh/machvec.h for the current state of the machvec.
The kernel will automatically wrap in generic routines for undefined function
pointers in the machvec at boot time, as machvec functions are referenced
unconditionally throughout most of the tree. Some boards have incredibly
sparse machvecs (such as the dreamcast and sh03), whereas others must define
virtually everything (rts7751r2d).
Adding a new machine is relatively trivial (using vapor as an example):
If the board-specific definitions are quite minimalistic, as is the case for
the vast majority of boards, simply having a single board-specific header is
sufficient.
- add a new file include/asm-sh/vapor.h which contains prototypes for
any machine specific IO functions prefixed with the machine name, for
example vapor_inb. These will be needed when filling out the machine
vector.
This is the minimum that is required, however there are ample
opportunities to optimise this. In particular, by making the prototypes
inline function definitions, it is possible to inline the function when
building machine specific versions. Note that the machine vector
functions will still be needed, so that a module built for a generic
setup can be loaded.
- add a new file arch/sh/boards/vapor/mach.c. This contains the definition
of the machine vector. When building the machine specific version, this
will be the real machine vector (via an alias), while in the generic
version is used to initialise the machine vector, and then freed, by
making it initdata. This should be defined as:
struct sh_machine_vector mv_vapor __initmv = {
.mv_name = "vapor",
}
ALIAS_MV(vapor)
- finally add a file arch/sh/boards/vapor/io.c, which contains
definitions of the machine specific io functions.
A note about initialisation functions. Three initialisation functions are
provided in the machine vector:
- mv_arch_init - called very early on from setup_arch
- mv_init_irq - called from init_IRQ, after the generic SH interrupt
initialisation
- mv_init_pci - currently not used
Any other remaining functions which need to be called at start up can be
added to the list using the __initcalls macro (or module_init if the code
can be built as a module). Many generic drivers probe to see if the device
they are targeting is present, however this may not always be appropriate,
so a flag can be added to the machine vector which will be set on those
machines which have the hardware in question, reducing the probe to a
single conditional.
Note that these prototypes are generated automatically by setting
__IO_PREFIX to something sensible. A typical example would be:
#define __IO_PREFIX vapor
#include <asm/io_generic.h>
somewhere in the board-specific header. Any boards being ported that still
have a legacy io.h should remove it entirely and switch to the new model.
- Add machine vector definitions to the board's setup.c. At a bare minimum,
this must be defined as something like:
struct sh_machine_vector mv_vapor __initmv = {
.mv_name = "vapor",
};
ALIAS_MV(vapor)
- finally add a file arch/sh/boards/vapor/io.c, which contains definitions of
the machine specific io functions (if there are enough to warrant it).
3. Hooking into the Build System
================================
......@@ -303,4 +278,3 @@ which will in turn copy the defconfig for this board, run it through
oldconfig (prompting you for any new options since the time of creation),
and start you on your way to having a functional kernel for your new
board.
Notes on register bank usage in the kernel
==========================================
Introduction
------------
The SH-3 and SH-4 CPU families traditionally include a single partial register
bank (selected by SR.RB, only r0 ... r7 are banked), whereas other families
may have more full-featured banking or simply no such capabilities at all.
SR.RB banking
-------------
In the case of this type of banking, banked registers are mapped directly to
r0 ... r7 if SR.RB is set to the bank we are interested in, otherwise ldc/stc
can still be used to reference the banked registers (as r0_bank ... r7_bank)
when in the context of another bank. The developer must keep the SR.RB value
in mind when writing code that utilizes these banked registers, for obvious
reasons. Userspace is also not able to poke at the bank1 values, so these can
be used rather effectively as scratch registers by the kernel.
Presently the kernel uses several of these registers.
- r0_bank, r1_bank (referenced as k0 and k1, used for scratch
registers when doing exception handling).
- r2_bank (used to track the EXPEVT/INTEVT code)
- Used by do_IRQ() and friends for doing irq mapping based off
of the interrupt exception vector jump table offset
- r6_bank (global interrupt mask)
- The SR.IMASK interrupt handler makes use of this to set the
interrupt priority level (used by local_irq_enable())
- r7_bank (current)
......@@ -8,6 +8,7 @@ mainmenu "Linux/SuperH Kernel Configuration"
config SUPERH
bool
default y
select EMBEDDED
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
......@@ -51,18 +52,23 @@ source "init/Kconfig"
menu "System type"
config SOLUTION_ENGINE
bool
choice
prompt "SuperH system type"
default SH_UNKNOWN
config SH_SOLUTION_ENGINE
bool "SolutionEngine"
select SOLUTION_ENGINE
help
Select SolutionEngine if configuring for a Hitachi SH7709
or SH7750 evaluation board.
config SH_7751_SOLUTION_ENGINE
bool "SolutionEngine7751"
select SOLUTION_ENGINE
select CPU_SUBTYPE_SH7751
help
Select 7751 SolutionEngine if configuring for a Hitachi SH7751
......@@ -70,17 +76,27 @@ config SH_7751_SOLUTION_ENGINE
config SH_7300_SOLUTION_ENGINE
bool "SolutionEngine7300"
select SOLUTION_ENGINE
select CPU_SUBTYPE_SH7300
help
Select 7300 SolutionEngine if configuring for a Hitachi SH7300(SH-Mobile V)
evaluation board.
Select 7300 SolutionEngine if configuring for a Hitachi
SH7300(SH-Mobile V) evaluation board.
config SH_7343_SOLUTION_ENGINE
bool "SolutionEngine7343"
select SOLUTION_ENGINE
select CPU_SUBTYPE_SH7343
help
Select 7343 SolutionEngine if configuring for a Hitachi
SH7343 (SH-Mobile 3AS) evaluation board.
config SH_73180_SOLUTION_ENGINE
bool "SolutionEngine73180"
select CPU_SUBTYPE_SH73180
help
Select 73180 SolutionEngine if configuring for a Hitachi SH73180(SH-Mobile 3)
evaluation board.
select SOLUTION_ENGINE
select CPU_SUBTYPE_SH73180
help
Select 73180 SolutionEngine if configuring for a Hitachi
SH73180(SH-Mobile 3) evaluation board.
config SH_7751_SYSTEMH
bool "SystemH7751R"
......@@ -89,12 +105,6 @@ config SH_7751_SYSTEMH
Select SystemH if you are configuring for a Renesas SystemH
7751R evaluation board.
config SH_STB1_HARP
bool "STB1_Harp"
config SH_STB1_OVERDRIVE
bool "STB1_Overdrive"
config SH_HP6XX
bool "HP6XX"
help
......@@ -102,19 +112,6 @@ config SH_HP6XX
More information (hardware only) at
<http://www.hp.com/jornada/>.
config SH_CQREEK
bool "CqREEK"
help
Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
More information at
<http://sources.redhat.com/ecos/hardware.html#SuperH>.
config SH_DMIDA
bool "DMIDA"
help
Select DMIDA if configuring for a DataMyte 4000 Industrial
Digital Assistant. More information at <http://www.dmida.com/>.
config SH_EC3104
bool "EC3104"
help
......@@ -136,25 +133,9 @@ config SH_DREAMCAST
<http://www.m17n.org/linux-sh/dreamcast/>. There is a
Dreamcast project is at <http://linuxdc.sourceforge.net/>.
config SH_CAT68701
bool "CAT68701"
config SH_BIGSUR
bool "BigSur"
config SH_SH2000
bool "SH2000"
select CPU_SUBTYPE_SH7709
help
SH-2000 is a single-board computer based around SH7709A chip
intended for embedded applications.
It has an Ethernet interface (CS8900A), direct connected
Compact Flash socket, three serial ports and PC-104 bus.
More information at <http://sh2000.sh-linux.org>.
config SH_ADX
bool "ADX"
config SH_MPC1211
bool "Interface MPC1211"
help
......@@ -184,6 +165,13 @@ config SH_HS7751RVOIP
Select HS7751RVOIP if configuring for a Renesas Technology
Sales VoIP board.
config SH_7710VOIPGW
bool "SH7710-VOIP-GW"
select CPU_SUBTYPE_SH7710
help
Select this option to build a kernel for the SH7710 based
VOIP GW.
config SH_RTS7751R2D
bool "RTS7751R2D"
select CPU_SUBTYPE_SH7751R
......@@ -222,6 +210,12 @@ config SH_TITAN
Select Titan if you are configuring for a Nimble Microsystems
NetEngine NP51R.
config SH_SHMIN
bool "SHMIN"
select CPU_SUBTYPE_SH7706
help
Select SHMIN if configureing for the SHMIN board
config SH_UNKNOWN
bool "BareCPU"
help
......@@ -238,35 +232,9 @@ endchoice
source "arch/sh/mm/Kconfig"
config MEMORY_START
hex "Physical memory start address"
default "0x08000000"
---help---
Computers built with Hitachi SuperH processors always
map the ROM starting at address zero. But the processor
does not specify the range that RAM takes.
The physical memory (RAM) start address will be automatically
set to 08000000. Other platforms, such as the Solution Engine
boards typically map RAM at 0C000000.
Tweak this only when porting to a new machine which does not
already have a defconfig. Changing it from the known correct
value on any of the known systems will only lead to disaster.
config MEMORY_SIZE
hex "Physical memory size"
default "0x00400000"
help
This sets the default memory size assumed by your SH kernel. It can
be overridden as normal by the 'mem=' argument on the kernel command
line. If unsure, consult your board specifications or just leave it
as 0x00400000 which was the default value before this became
configurable.
config CF_ENABLER
bool "Compact Flash Enabler support"
depends on SH_ADX || SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_CAT68701 || SH_SH03
depends on SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_SH03
---help---
Compact Flash is a small, removable mass storage device introduced
in 1994 originally as a PCMCIA device. If you say `Y' here, you
......@@ -294,7 +262,7 @@ config CF_AREA5
- "Area5" if CompactFlash is connected to Area 5 (0x14000000)
- "Area6" if it is connected to Area 6 (0x18000000)
"Area6" will work for most boards. For ADX, select "Area5".
"Area6" will work for most boards.
config CF_AREA6
bool "Area6"
......@@ -316,19 +284,6 @@ config CPU_LITTLE_ENDIAN
endian byte order. These modes require different kernels. Say Y if
your machine is little endian, N if it's a big endian machine.
# The SH7750 RTC module is disabled in the Dreamcast
config SH_RTC
bool
depends on !SH_DREAMCAST && !SH_SATURN && !SH_7300_SOLUTION_ENGINE && \
!SH_73180_SOLUTION_ENGINE && !SH_LANDISK && \
!SH_R7780RP
default y
help
Selecting this option will allow the Linux kernel to emulate
PC's RTC.
If unsure, say N.
config SH_FPU
bool "FPU support"
depends on !CPU_SH3
......@@ -339,14 +294,22 @@ config SH_FPU
This option must be set in order to enable the FPU.
config SH_FPU_EMU
bool "FPU emulation support"
depends on !SH_FPU && EXPERIMENTAL
default n
help
Selecting this option will enable support for software FPU emulation.
Most SH-3 users will want to say Y here, whereas most SH-4 users will
want to say N.
config SH_DSP
bool "DSP support"
depends on !CPU_SH4
default y
default y if SH4AL_DSP || !CPU_SH4
default n
help
Selecting this option will enable support for SH processors that
have DSP units (ie, SH2-DSP and SH3-DSP). It is safe to say Y here
by default, as the existance of the DSP will be probed at runtime.
have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
This option must be set in order to enable the DSP.
......@@ -373,6 +336,9 @@ config CPU_HAS_INTEVT
config CPU_HAS_PINT_IRQ
bool
config CPU_HAS_MASKREG_IRQ
bool
config CPU_HAS_INTC2_IRQ
bool
......@@ -400,16 +366,19 @@ config SH_TMU
endmenu
#source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
#source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
source "arch/sh/boards/renesas/r7780rp/Kconfig"
config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
default "60000000" if CPU_SUBTYPE_SH7751
default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || CPU_SUBTYPE_SH7760
default "27000000" if CPU_SUBTYPE_SH73180
default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
CPU_SUBTYPE_SH7760
default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
default "66000000" if CPU_SUBTYPE_SH4_202
help
This option is used to specify the peripheral clock frequency.
......@@ -440,10 +409,8 @@ source "arch/sh/cchips/Kconfig"
config HEARTBEAT
bool "Heartbeat LED"
depends on SH_MPC1211 || SH_SH03 || SH_CAT68701 || \
SH_STB1_HARP || SH_STB1_OVERDRIVE || SH_BIGSUR || \
SH_7751_SOLUTION_ENGINE || SH_7300_SOLUTION_ENGINE || \
SH_73180_SOLUTION_ENGINE || SH_SOLUTION_ENGINE || \
depends on SH_MPC1211 || SH_SH03 || \
SH_BIGSUR || SOLUTION_ENGINE || \
SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK
help
Use the power-on LED on your machine as a load meter. The exact
......@@ -459,6 +426,8 @@ config ISA_DMA_API
menu "Kernel features"
source kernel/Kconfig.hz
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
depends on EXPERIMENTAL
......@@ -476,10 +445,6 @@ config KEXEC
support. As of this writing the exact hardware interface is
strongly in flux, so no good recommendation can be made.
config PREEMPT
bool "Preemptible Kernel (EXPERIMENTAL)"
depends on EXPERIMENTAL
config SMP
bool "Symmetric multi-processing support"
---help---
......@@ -515,6 +480,8 @@ config NR_CPUS
This is purely to save memory - each supported CPU adds
approximately eight kilobytes to the kernel image.
source "kernel/Kconfig.preempt"
config CPU_HAS_SR_RB
bool "CPU has SR.RB"
depends on CPU_SH3 || CPU_SH4
......@@ -636,6 +603,16 @@ source "fs/Kconfig.binfmt"
endmenu
menu "Power management options (EXPERIMENTAL)"
depends on EXPERIMENTAL
source kernel/power/Kconfig
config APM
bool "Advanced Power Management Emulation"
depends on PM
endmenu
source "net/Kconfig"
source "drivers/Kconfig"
......
......@@ -30,8 +30,35 @@ config EARLY_PRINTK
when the kernel may crash or hang before the serial console is
initialised. If unsure, say N.
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
depends on DEBUG_KERNEL
help
This option will cause messages to be printed if free stack space
drops below a certain limit.
config DEBUG_STACK_USAGE
bool "Stack utilization instrumentation"
depends on DEBUG_KERNEL
help
Enables the display of the minimum amount of free stack which each
task has ever had available in the sysrq-T and sysrq-P debug output.
This option will slow down process creation somewhat.
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
depends on DEBUG_KERNEL
help
If you say Y here the kernel will use a 4Kb stacksize for the
kernel stack attached to each process/thread. This facilitates
running more threads on a system and also reduces the pressure
on the VM subsystem for higher order allocations. This option
will also use IRQ stacks to compensate for the reduced stackspace.
config KGDB
bool "Include KGDB kernel debugger"
select FRAME_POINTER
help
Include in-kernel hooks for kgdb, the Linux kernel source level
debugger. See <http://kgdb.sourceforge.net/> for more information.
......@@ -112,13 +139,4 @@ endchoice
endmenu
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
default y if KGDB
help
If you say Y here the resulting kernel image will be slightly larger
and slower, but it will give very useful debugging information.
If you don't debug the kernel, you can say N, but we may not be able
to solve problems without frame pointers.
endmenu
......@@ -18,11 +18,13 @@ cflags-y := -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml
isa-y := any
isa-$(CONFIG_SH_DSP) := sh
isa-$(CONFIG_CPU_SH2) := sh2
isa-$(CONFIG_CPU_SH2A) := sh2a
isa-$(CONFIG_CPU_SH3) := sh3
isa-$(CONFIG_CPU_SH4) := sh4
isa-$(CONFIG_CPU_SH4A) := sh4a
isa-$(CONFIG_CPU_SH2A) := sh2a
isa-$(CONFIG_CPU_SH4AL_DSP) := sh4al
isa-$(CONFIG_SH_DSP) := $(isa-y)-dsp
......@@ -30,9 +32,11 @@ ifndef CONFIG_MMU
isa-y := $(isa-y)-nommu
endif
ifndef CONFIG_SH_DSP
ifndef CONFIG_SH_FPU
isa-y := $(isa-y)-nofpu
endif
endif
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
......@@ -79,24 +83,19 @@ head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
core-y += arch/sh/kernel/ arch/sh/mm/
core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
# Boards
machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300
machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343
machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180
machdir-$(CONFIG_SH_STB1_HARP) := harp
machdir-$(CONFIG_SH_STB1_OVERDRIVE) := overdrive
machdir-$(CONFIG_SH_HP6XX) := hp6xx
machdir-$(CONFIG_SH_CQREEK) := cqreek
machdir-$(CONFIG_SH_DMIDA) := dmida
machdir-$(CONFIG_SH_EC3104) := ec3104
machdir-$(CONFIG_SH_SATURN) := saturn
machdir-$(CONFIG_SH_DREAMCAST) := dreamcast
machdir-$(CONFIG_SH_CAT68701) := cat68701
machdir-$(CONFIG_SH_BIGSUR) := bigsur
machdir-$(CONFIG_SH_SH2000) := sh2000
machdir-$(CONFIG_SH_ADX) := adx
machdir-$(CONFIG_SH_MPC1211) := mpc1211
machdir-$(CONFIG_SH_SH03) := sh03
machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear
......@@ -104,16 +103,16 @@ machdir-$(CONFIG_SH_HS7751RVOIP) := renesas/hs7751rvoip
machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d
machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh
machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705
machdir-$(CONFIG_SH_R7780RP) := renesas/r7780rp
machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw
machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
machdir-$(CONFIG_SH_LANDISK) := landisk
machdir-$(CONFIG_SH_TITAN) := titan
machdir-$(CONFIG_SH_SHMIN) := shmin
machdir-$(CONFIG_SH_UNKNOWN) := unknown
incdir-y := $(notdir $(machdir-y))
incdir-$(CONFIG_SH_SOLUTION_ENGINE) := se
incdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se7751
incdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se7300
incdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se73180
incdir-$(CONFIG_SH_HP600) := hp6xx
incdir-$(CONFIG_SH_HP6XX) := hp6xx
ifneq ($(machdir-y),)
core-y += arch/sh/boards/$(machdir-y)/
......@@ -137,17 +136,14 @@ boot := arch/sh/boot
CPPFLAGS_vmlinux.lds := -traditional
ifneq ($(KBUILD_SRC),)
incdir-prefix := $(srctree)/include/asm-sh/
else
incdir-prefix :=
endif
# Update machine arch and proc symlinks if something which affects
# them changed. We use .arch and .mach to indicate when they were
# updated last, otherwise make uses the target directory mtime.
include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) \
include/config/auto.conf FORCE
@echo ' SYMLINK include/asm-sh/cpu -> include/asm-sh/$(cpuincdir-y)'
$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
$(Q)ln -fsn $(incdir-prefix)$(cpuincdir-y) include/asm-sh/cpu
......@@ -157,7 +153,8 @@ include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
# don't, just reference the parent directory so the semantics are
# kept roughly the same.
include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
include/config/auto.conf FORCE
@echo -n ' SYMLINK include/asm-sh/mach -> '
$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
$(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \
......@@ -170,7 +167,7 @@ include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
fi
@touch $@
archprepare: maketools include/asm-sh/.cpu include/asm-sh/.mach
archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
PHONY += maketools FORCE
maketools: include/linux/version.h FORCE
......@@ -191,4 +188,3 @@ CLEAN_FILES += include/asm-sh/machtypes.h
define archhelp
@echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)'
endef
#
# Makefile for ADX boards
#
obj-y := setup.o irq.o irq_maskreq.o
/*
* linux/arch/sh/boards/adx/irq.c
*
* Copyright (C) 2001 A&D Co., Ltd.
*
* I/O routine and setup routines for A&D ADX Board
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <asm/irq.h>
void init_adx_IRQ(void)
{
int i;
/* printk("init_adx_IRQ()\n");*/
/* setup irq_mask_register */
irq_mask_register = (unsigned short *)0xa6000008;
/* cover all external interrupt area by maskreg_irq_type
* (Actually, irq15 doesn't exist)
*/
for (i = 0; i < 16; i++) {
make_maskreg_irq(i);
disable_irq(i);
}
}
/*
* linux/arch/sh/board/adx/setup.c
*
* Copyright (C) 2001 A&D Co., Ltd.
*
* I/O routine and setup routines for A&D ADX Board
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <asm/machvec.h>
#include <linux/module.h>
extern void init_adx_IRQ(void);
extern void *cf_io_base;
const char *get_system_type(void)
{
return "A&D ADX";
}
unsigned long adx_isa_port2addr(unsigned long offset)
{
/* CompactFlash (IDE) */
if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset == 0x3f6)) {
return (unsigned long)cf_io_base + offset;
}
/* eth0 */
if ((offset >= 0x300) && (offset <= 0x30f)) {
return 0xa5000000 + offset; /* COMM BOARD (AREA1) */
}
return offset + 0xb0000000; /* IOBUS (AREA 4)*/
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_adx __initmv = {
.mv_nr_irqs = 48,
.mv_isa_port2addr = adx_isa_port2addr,
.mv_init_irq = init_adx_IRQ,
};
ALIAS_MV(adx)
int __init platform_setup(void)
{
/* Nothing to see here .. */
return 0;
}
......@@ -19,6 +19,7 @@
* IRQ functions for a Hitachi Big Sur Evaluation Board.
*
*/
#undef DEBUG
#include <linux/sched.h>
#include <linux/module.h>
......@@ -41,10 +42,8 @@
#undef BIGSUR_DEBUG
#ifdef BIGSUR_DEBUG
#define DPRINTK(args...) printk(args)
#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
#else
#define DPRINTK(args...)
#define DIPRINTK(n, args...)
#endif /* BIGSUR_DEBUG */
......@@ -60,45 +59,39 @@ extern int hd64465_irq_demux(int irq);
/* Level 1 IRQ routines */
static void disable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Disable L1 IRQ %d\n", irq);
pr_debug("Disable L1 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Disable IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
pr_debug("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l1irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
DPRINTK("Enable L1 IRQ %d\n", irq);
pr_debug("Enable L1 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Enable L1 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
pr_debug("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
......@@ -126,51 +119,45 @@ static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
/* Level 2 IRQ routines */
static void disable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Disable L2 IRQ %d\n", irq);
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
pr_debug("Disable L2 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Disable L2 IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
pr_debug("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l2irq(unsigned int irq)
{
unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
DPRINTK("Enable L2 IRQ %d\n", irq);
if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
pr_debug("Enable L2 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
local_irq_save(flags);
/* Enable L2 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
local_irq_restore(flags);
return;
}
DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
pr_debug("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void mask_and_ack_bigsur(unsigned int irq)
{
DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
pr_debug("mask_and_ack_bigsur IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
......@@ -179,7 +166,7 @@ static void mask_and_ack_bigsur(unsigned int irq)
static void end_bigsur_irq(unsigned int irq)
{
DPRINTK("end_bigsur_irq IRQ %d\n", irq);
pr_debug("end_bigsur_irq IRQ %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
enable_bigsur_l1irq(irq);
......@@ -193,7 +180,7 @@ static unsigned int startup_bigsur_irq(unsigned int irq)
u8 mask;
u32 reg;
DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
pr_debug("startup_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Enable the L1 IRQ */
......@@ -218,7 +205,7 @@ static unsigned int startup_bigsur_irq(unsigned int irq)
static void shutdown_bigsur_irq(unsigned int irq)
{
DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
pr_debug("shutdown_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
......@@ -260,7 +247,7 @@ static void make_bigsur_l1isr(unsigned int irq) {
disable_bigsur_l1irq(irq);
return;
}
DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
pr_debug("make_bigsur_l1isr: bad irq, %d\n", irq);
return;
}
......@@ -277,7 +264,7 @@ static void make_bigsur_l2isr(unsigned int irq) {
disable_bigsur_l2irq(irq);
return;
}
DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
pr_debug("make_bigsur_l2isr: bad irq, %d\n", irq);
return;
}
......
......@@ -41,31 +41,7 @@
// Big Sur Init Routines
/*===========================================================*/
const char *get_system_type(void)
{
return "Big Sur";
}
/*
* The Machine Vector
*/
extern void heartbeat_bigsur(void);
extern void init_bigsur_IRQ(void);
struct sh_machine_vector mv_bigsur __initmv = {
.mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h>
.mv_isa_port2addr = bigsur_isa_port2addr,
.mv_irq_demux = bigsur_irq_demux,
.mv_init_irq = init_bigsur_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_bigsur,
#endif
};
ALIAS_MV(bigsur)
int __init platform_setup(void)
static void __init bigsur_setup(char **cmdline_p)
{
/* Mask all 2nd level IRQ's */
outb(-1,BIGSUR_IMR0);
......@@ -89,7 +65,24 @@ int __init platform_setup(void)
outw(1, BIGSUR_ETHR+0xe);
/* set the IO port to BIGSUR_ETHER_IOPORT */
outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
return 0;
}
/*
* The Machine Vector
*/
extern void heartbeat_bigsur(void);
extern void init_bigsur_IRQ(void);
struct sh_machine_vector mv_bigsur __initmv = {
.mv_name = "Big Sur",
.mv_setup = bigsur_setup,
.mv_isa_port2addr = bigsur_isa_port2addr,
.mv_irq_demux = bigsur_irq_demux,
.mv_init_irq = init_bigsur_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_bigsur,
#endif
};
ALIAS_MV(bigsur)
#
# Makefile for the CAT-68701 specific parts of the kernel
#
obj-y := setup.o irq.o
/*
* linux/arch/sh/boards/cat68701/irq.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* Setup routines for A-ONE Corp CAT-68701 SH7708 Board
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <asm/irq.h>
int cat68701_irq_demux(int irq)
{
if(irq==13) return 14;
if(irq==7) return 10;
return irq;
}
void init_cat68701_IRQ()
{
make_imask_irq(10);
make_imask_irq(14);
}
/*
* linux/arch/sh/boards/cat68701/setup.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* Setup routines for A-ONE Corp CAT-68701 SH7708 Board
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mach/io.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
const char *get_system_type(void)
{
return "CAT-68701";
}
#ifdef CONFIG_HEARTBEAT
void heartbeat_cat68701()
{
static unsigned int cnt = 0, period = 0 , bit = 0;
cnt += 1;
if (cnt < period) {
return;
}
cnt = 0;
/* Go through the points (roughly!):
* f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
*/
period = 110 - ( (300<<FSHIFT)/
((avenrun[0]/5) + (3<<FSHIFT)) );
if(bit){ bit=0; }else{ bit=1; }
outw(bit<<15,0x3fe);
}
#endif /* CONFIG_HEARTBEAT */
unsigned long cat68701_isa_port2addr(unsigned long offset)
{
/* CompactFlash (IDE) */
if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6))
return 0xba000000 + offset;
/* INPUT PORT */
if ((offset >= 0x3fc) && (offset <= 0x3fd))
return 0xb4007000 + offset;
/* OUTPUT PORT */
if ((offset >= 0x3fe) && (offset <= 0x3ff))
return 0xb4007400 + offset;
return offset + 0xb4000000; /* other I/O (EREA 5)*/
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cat68701 __initmv = {
.mv_nr_irqs = 32,
.mv_isa_port2addr = cat68701_isa_port2addr,
.mv_irq_demux = cat68701_irq_demux,
.mv_init_irq = init_cat68701_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_cat68701,
#endif
};
ALIAS_MV(cat68701)
int __init platform_setup(void)
{
/* dummy read erea5 (CS8900A) */
}
#
# Makefile for the CqREEK specific parts of the kernel
#
obj-y := setup.o irq.o
/* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $
*
* arch/sh/boards/cqreek/irq.c
*
* Copyright (C) 2000 Niibe Yutaka
*
* CqREEK IDE/ISA Bridge Support.
*
*/
#include <linux/irq.h>
#include <linux/init.h>
#include <asm/cqreek/cqreek.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/irq.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
struct cqreek_irq_data {
unsigned short mask_port; /* Port of Interrupt Mask Register */
unsigned short stat_port; /* Port of Interrupt Status Register */
unsigned short bit; /* Value of the bit */
};
static struct cqreek_irq_data cqreek_irq_data[NR_IRQS];
static void disable_cqreek_irq(unsigned int irq)
{
unsigned long flags;
unsigned short mask;
unsigned short mask_port = cqreek_irq_data[irq].mask_port;
unsigned short bit = cqreek_irq_data[irq].bit;
local_irq_save(flags);
/* Disable IRQ */
mask = inw(mask_port) & ~bit;
outw_p(mask, mask_port);
local_irq_restore(flags);
}
static void enable_cqreek_irq(unsigned int irq)
{
unsigned long flags;
unsigned short mask;
unsigned short mask_port = cqreek_irq_data[irq].mask_port;
unsigned short bit = cqreek_irq_data[irq].bit;
local_irq_save(flags);
/* Enable IRQ */
mask = inw(mask_port) | bit;
outw_p(mask, mask_port);
local_irq_restore(flags);
}
static void mask_and_ack_cqreek(unsigned int irq)
{
unsigned short stat_port = cqreek_irq_data[irq].stat_port;
unsigned short bit = cqreek_irq_data[irq].bit;
disable_cqreek_irq(irq);
/* Clear IRQ (it might be edge IRQ) */
inw(stat_port);
outw_p(bit, stat_port);
}
static void end_cqreek_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_cqreek_irq(irq);
}
static unsigned int startup_cqreek_irq(unsigned int irq)
{
enable_cqreek_irq(irq);
return 0;
}
static void shutdown_cqreek_irq(unsigned int irq)
{
disable_cqreek_irq(irq);
}
static struct hw_interrupt_type cqreek_irq_type = {
.typename = "CqREEK-IRQ",
.startup = startup_cqreek_irq,
.shutdown = shutdown_cqreek_irq,
.enable = enable_cqreek_irq,
.disable = disable_cqreek_irq,
.ack = mask_and_ack_cqreek,
.end = end_cqreek_irq
};
int cqreek_has_ide, cqreek_has_isa;
/* XXX: This is just for test for my NE2000 ISA board
What we really need is virtualized IRQ and demultiplexer like HP600 port */
void __init init_cqreek_IRQ(void)
{
if (cqreek_has_ide) {
cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
cqreek_irq_data[14].bit = 1;
irq_desc[14].chip = &cqreek_irq_type;
irq_desc[14].status = IRQ_DISABLED;
irq_desc[14].action = 0;
irq_desc[14].depth = 1;
disable_cqreek_irq(14);
}
if (cqreek_has_isa) {
cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
cqreek_irq_data[10].bit = (1 << 10);
/* XXX: Err... we may need demultiplexer for ISA irq... */
irq_desc[10].chip = &cqreek_irq_type;
irq_desc[10].status = IRQ_DISABLED;
irq_desc[10].action = 0;
irq_desc[10].depth = 1;
disable_cqreek_irq(10);
}
}
/* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
*
* Copyright (C) 2000 Niibe Yutaka
*
* CqREEK IDE/ISA Bridge Support.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/mach/cqreek.h>
#include <asm/machvec.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/irq.h>
#include <asm/rtc.h>
#define IDE_OFFSET 0xA4000000UL
#define ISA_OFFSET 0xA4A00000UL
const char *get_system_type(void)
{
return "CqREEK";
}
static unsigned long cqreek_port2addr(unsigned long port)
{
if (0x0000<=port && port<=0x0040)
return IDE_OFFSET + port;
if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
return IDE_OFFSET + port;
return ISA_OFFSET + port;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cqreek __initmv = {
#if defined(CONFIG_CPU_SH4)
.mv_nr_irqs = 48,
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
.mv_nr_irqs = 32,
#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
.mv_nr_irqs = 61,
#endif
.mv_init_irq = init_cqreek_IRQ,
.mv_isa_port2addr = cqreek_port2addr,
};
ALIAS_MV(cqreek)
/*
* Initialize the board
*/
void __init platform_setup(void)
{
int i;
/* udelay is not available at setup time yet... */
#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
outw_p(0, BRIDGE_IDE_INTR_LVL);
outw_p(0, BRIDGE_IDE_INTR_MASK);
outw_p(0, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_IDE_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
cqreek_has_ide=1;
}
if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
outw_p(0, BRIDGE_ISA_INTR_LVL);
outw_p(0, BRIDGE_ISA_INTR_MASK);
outw_p(0, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0x8000, BRIDGE_ISA_CTRL);
DELAY();
outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
cqreek_has_isa=1;
}
printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa);
}
#
# Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts
# of the kernel
#
obj-y := mach.o
/*
* linux/arch/sh/boards/dmida/mach.c
*
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
* Derived from mach_hp600.c, which bore the message:
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the DataMyte Industrial Digital Assistant(tm).
* See http://www.dmida.com
*
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/hd64465/hd64465.h>
#include <asm/irq.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_dmida __initmv = {
.mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
.mv_inb = hd64465_inb,
.mv_inw = hd64465_inw,
.mv_inl = hd64465_inl,
.mv_outb = hd64465_outb,
.mv_outw = hd64465_outw,
.mv_outl = hd64465_outl,
.mv_inb_p = hd64465_inb_p,
.mv_inw_p = hd64465_inw,
.mv_inl_p = hd64465_inl,
.mv_outb_p = hd64465_outb_p,
.mv_outw_p = hd64465_outw,
.mv_outl_p = hd64465_outl,
.mv_insb = hd64465_insb,
.mv_insw = hd64465_insw,
.mv_insl = hd64465_insl,
.mv_outsb = hd64465_outsb,
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
.mv_irq_demux = hd64465_irq_demux,
};
ALIAS_MV(dmida)
......@@ -10,7 +10,6 @@
*/
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dreamcast/sysasic.h>
......@@ -26,10 +25,10 @@
event.
There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
types can be found in include/asm-sh/dc_sysasic.h. There are three groups
of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so
0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
types can be found in include/asm-sh/dreamcast/sysasic.h. There are three
groups of EMRs that parallel the ESRs. Each EMR group corresponds to an
IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928
triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
In the kernel, these events are mapped to virtual IRQs so that drivers can
respond to them as they would a normal interrupt. In order to keep this
......@@ -57,29 +56,23 @@
/* Disable the hardware event by masking its bit in its EMR */
static inline void disable_systemasic_irq(unsigned int irq)
{
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
local_irq_save(flags);
mask = inl(emr);
mask &= ~(1 << EVENT_BIT(irq));
outl(mask, emr);
local_irq_restore(flags);
}
/* Enable the hardware event by setting its bit in its EMR */
static inline void enable_systemasic_irq(unsigned int irq)
{
unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
local_irq_save(flags);
mask = inl(emr);
mask |= (1 << EVENT_BIT(irq));
outl(mask, emr);
local_irq_restore(flags);
}
/* Acknowledge a hardware event by writing its bit back to its ESR */
......
/* arch/sh/kernel/rtc-aica.c
/*
* arch/sh/boards/dreamcast/rtc.c
*
* Dreamcast AICA RTC routines.
*
......@@ -10,15 +11,12 @@
*/
#include <linux/time.h>
#include <asm/rtc.h>
#include <asm/io.h>
extern void (*rtc_get_time)(struct timespec *);
extern int (*rtc_set_time)(const time_t);
/* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
seconds to get the standard Unix Epoch when getting the time, and add 20
years when setting the time. */
seconds) to get the standard Unix Epoch when getting the time, and add
20 years when setting the time. */
#define TWENTY_YEARS ((20 * 365LU + 5) * 86400)
/* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit
......@@ -32,7 +30,8 @@ extern int (*rtc_set_time)(const time_t);
*
* Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
*/
void aica_rtc_gettimeofday(struct timespec *ts) {
void aica_rtc_gettimeofday(struct timespec *ts)
{
unsigned long val1, val2;
do {
......@@ -55,7 +54,8 @@ void aica_rtc_gettimeofday(struct timespec *ts) {
*
* Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
*/
int aica_rtc_settimeofday(const time_t secs) {
int aica_rtc_settimeofday(const time_t secs)
{
unsigned long val1, val2;
unsigned long adj = secs + TWENTY_YEARS;
......@@ -75,7 +75,7 @@ int aica_rtc_settimeofday(const time_t secs) {
void aica_time_init(void)
{
rtc_get_time = aica_rtc_gettimeofday;
rtc_set_time = aica_rtc_settimeofday;
rtc_sh_get_time = aica_rtc_gettimeofday;
rtc_sh_set_time = aica_rtc_settimeofday;
}
......@@ -22,41 +22,21 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/rtc.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/mach/sysasic.h>
extern struct hw_interrupt_type systemasic_int;
/* XXX: Move this into it's proper header. */
extern void (*board_time_init)(void);
extern void aica_time_init(void);
extern int gapspci_init(void);
extern int systemasic_irq_demux(int);
void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
const char *get_system_type(void)
{
return "Sega Dreamcast";
}
struct sh_machine_vector mv_dreamcast __initmv = {
.mv_nr_irqs = NR_IRQS,
.mv_irq_demux = systemasic_irq_demux,
#ifdef CONFIG_PCI
.mv_consistent_alloc = dreamcast_consistent_alloc,
.mv_consistent_free = dreamcast_consistent_free,
#endif
};
ALIAS_MV(dreamcast)
int __init platform_setup(void)
static void __init dreamcast_setup(char **cmdline_p)
{
int i;
......@@ -78,6 +58,16 @@ int __init platform_setup(void)
if (gapspci_init() < 0)
printk(KERN_WARNING "GAPSPCI was not detected.\n");
#endif
return 0;
}
struct sh_machine_vector mv_dreamcast __initmv = {
.mv_name = "Sega Dreamcast",
.mv_setup = dreamcast_setup,
.mv_irq_demux = systemasic_irq_demux,
#ifdef CONFIG_PCI
.mv_consistent_alloc = dreamcast_consistent_alloc,
.mv_consistent_free = dreamcast_consistent_free,
#endif
};
ALIAS_MV(dreamcast)
......@@ -21,22 +21,36 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/machvec.h>
#include <asm/mach/ec3104.h>
const char *get_system_type(void)
static void __init ec3104_setup(char **cmdline_p)
{
return "EC3104";
char str[8];
int i;
for (i=0; i<8; i++)
str[i] = ctrl_readb(EC3104_BASE + i);
for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
irq_desc[i].handler = &ec3104_int;
printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
/* mask all interrupts. this should have been done by the boot
* loader for us but we want to be sure ... */
ctrl_writel(0xffffffff, EC3104_IMR);
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_ec3104 __initmv = {
.mv_name = "EC3104",
.mv_setup = ec3104_setup,
.mv_nr_irqs = 96,
.mv_inb = ec3104_inb,
......@@ -48,31 +62,4 @@ struct sh_machine_vector mv_ec3104 __initmv = {
.mv_irq_demux = ec3104_irq_demux,
};
ALIAS_MV(ec3104)
int __init platform_setup(void)
{
char str[8];
int i;
if (0)
return 0;
for (i=0; i<8; i++)
str[i] = ctrl_readb(EC3104_BASE + i);
for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
irq_desc[i].chip = &ec3104_int;
printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
/* mask all interrupts. this should have been done by the boot
* loader for us but we want to be sure ... */
ctrl_writel(0xffffffff, EC3104_IMR);
return 0;
}
#
# Makefile for STMicroelectronics board specific parts of the kernel
#
obj-y := irq.o setup.o mach.o led.o
obj-$(CONFIG_PCI) += pcidma.o
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Looks after interrupts on the HARP board.
*
* Bases on the IPR irq system
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/harp/harp.h>
#define NUM_EXTERNAL_IRQS 16
// Early versions of the STB1 Overdrive required this nasty frig
//#define INVERT_INTMASK_WRITES
static void enable_harp_irq(unsigned int irq);
static void disable_harp_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_harp_irq disable_harp_irq
static void mask_and_ack_harp(unsigned int);
static void end_harp_irq(unsigned int irq);
static unsigned int startup_harp_irq(unsigned int irq)
{
enable_harp_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type harp_irq_type = {
.typename = "Harp-IRQ",
.startup = startup_harp_irq,
.shutdown = shutdown_harp_irq,
.enable = enable_harp_irq,
.disable = disable_harp_irq,
.ack = mask_and_ack_harp,
.end = end_harp_irq
};
static void disable_harp_irq(unsigned int irq)
{
unsigned val, flags;
unsigned maskReg;
unsigned mask;
int pri;
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
pri = 15 - irq;
if (pri < 8) {
maskReg = EPLD_INTMASK0;
} else {
maskReg = EPLD_INTMASK1;
pri -= 8;
}
local_irq_save(flags);
mask = ctrl_inl(maskReg);
mask &= (~(1 << pri));
#if defined(INVERT_INTMASK_WRITES)
mask ^= 0xff;
#endif
ctrl_outl(mask, maskReg);
local_irq_restore(flags);
}
static void enable_harp_irq(unsigned int irq)
{
unsigned flags;
unsigned maskReg;
unsigned mask;
int pri;
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
pri = 15 - irq;
if (pri < 8) {
maskReg = EPLD_INTMASK0;
} else {
maskReg = EPLD_INTMASK1;
pri -= 8;
}
local_irq_save(flags);
mask = ctrl_inl(maskReg);
mask |= (1 << pri);
#if defined(INVERT_INTMASK_WRITES)
mask ^= 0xff;
#endif
ctrl_outl(mask, maskReg);
local_irq_restore(flags);
}
/* This functions sets the desired irq handler to be an overdrive type */
static void __init make_harp_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].chip = &harp_irq_type;
disable_harp_irq(irq);
}
static void mask_and_ack_harp(unsigned int irq)
{
disable_harp_irq(irq);
}
static void end_harp_irq(unsigned int irq)
{
enable_harp_irq(irq);
}
void __init init_harp_irq(void)
{
int i;
#if !defined(INVERT_INTMASK_WRITES)
// On the harp these are set to enable an interrupt
ctrl_outl(0x00, EPLD_INTMASK0);
ctrl_outl(0x00, EPLD_INTMASK1);
#else
// On the Overdrive the data is inverted before being stored in the reg
ctrl_outl(0xff, EPLD_INTMASK0);
ctrl_outl(0xff, EPLD_INTMASK1);
#endif
for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
make_harp_irq(i);
}
}
/*
* linux/arch/sh/stboards/led.c
*
* Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains ST40STB1 HARP and compatible code.
*/
#include <asm/io.h>
#include <asm/harp/harp.h>
/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
/* Works for HARP and overdrive */
static void mach_led(int position, int value)
{
if (value) {
ctrl_outl(EPLD_LED_ON, EPLD_LED);
} else {
ctrl_outl(EPLD_LED_OFF, EPLD_LED);
}
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
/* acts like an actual heart beat -- ie thump-thump-pause... */
void heartbeat_harp(void)
{
static unsigned cnt = 0, period = 0, dist = 0;
if (cnt == 0 || cnt == dist)
mach_led( -1, 1);
else if (cnt == 7 || cnt == dist+7)
mach_led( -1, 0);
if (++cnt > period) {
cnt = 0;
/* The hyperbolic function below modifies the heartbeat period
* length in dependency of the current (5min) load. It goes
* through the points f(0)=126, f(1)=86, f(5)=51,
* f(inf)->30. */
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
dist = period / 4;
}
}
#endif
/*
* linux/arch/sh/boards/harp/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the STMicroelectronics STB1 HARP and compatible boards
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/hd64465/io.h>
#include <asm/hd64465/hd64465.h>
void setup_harp(void);
void init_harp_irq(void);
void heartbeat_harp(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_harp __initmv = {
.mv_nr_irqs = 89 + HD64465_IRQ_NUM,
.mv_inb = hd64465_inb,
.mv_inw = hd64465_inw,
.mv_inl = hd64465_inl,
.mv_outb = hd64465_outb,
.mv_outw = hd64465_outw,
.mv_outl = hd64465_outl,
.mv_inb_p = hd64465_inb_p,
.mv_inw_p = hd64465_inw,
.mv_inl_p = hd64465_inl,
.mv_outb_p = hd64465_outb_p,
.mv_outw_p = hd64465_outw,
.mv_outl_p = hd64465_outl,
.mv_insb = hd64465_insb,
.mv_insw = hd64465_insw,
.mv_insl = hd64465_insl,
.mv_outsb = hd64465_outsb,
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
.mv_isa_port2addr = hd64465_isa_port2addr,
#ifdef CONFIG_PCI
.mv_init_irq = init_harp_irq,
#endif
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_harp,
#endif
};
ALIAS_MV(harp)
/*
* Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Dynamic DMA mapping support.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/addrspace.h>
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t * dma_handle)
{
void *ret;
int gfp = GFP_ATOMIC;
ret = (void *) __get_free_pages(gfp, get_order(size));
if (ret != NULL) {
/* Is it neccessary to do the memset? */
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
}
/* We must flush the cache before we pass it on to the device */
flush_cache_all();
return P2SEGADDR(ret);
}
void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
free_pages(p1addr, get_order(size));
}
/*
* arch/sh/stboard/setup.c
*
* Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* STMicroelectronics ST40STB1 HARP and compatible support.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/harp/harp.h>
const char *get_system_type(void)
{
return "STB1 Harp";
}
/*
* Initialize the board
*/
int __init platform_setup(void)
{
#ifdef CONFIG_SH_STB1_HARP
unsigned long ic8_version, ic36_version;
ic8_version = ctrl_inl(EPLD_REVID2);
ic36_version = ctrl_inl(EPLD_REVID1);
printk("STMicroelectronics STB1 HARP initialisaton\n");
printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
(ic8_version >> 4) & 0xf, ic8_version & 0xf,
(ic36_version >> 4) & 0xf, ic36_version & 0xf);
#elif defined(CONFIG_SH_STB1_OVERDRIVE)
unsigned long version;
version = ctrl_inl(EPLD_REVID);
printk("STMicroelectronics STB1 Overdrive initialisaton\n");
printk("EPLD version: %d.%02d\n",
(version >> 4) & 0xf, version & 0xf);
#else
#error Undefined machine
#endif
/* Currently all STB1 chips have problems with the sleep instruction,
* so disable it here.
*/
disable_hlt();
return 0;
}
/*
* pcibios_map_platform_irq
*
* This is board specific and returns the IRQ for a given PCI device.
* It is used by the PCI code (arch/sh/kernel/st40_pci*)
*
*/
#define HARP_PCI_IRQ 1
#define HARP_BRIDGE_IRQ 2
#define OVERDRIVE_SLOT0_IRQ 0
int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
switch (slot) {
#ifdef CONFIG_SH_STB1_HARP
case 2: /*This is the PCI slot on the */
return HARP_PCI_IRQ;
case 1: /* this is the bridge */
return HARP_BRIDGE_IRQ;
#elif defined(CONFIG_SH_STB1_OVERDRIVE)
case 1:
case 2:
case 3:
return slot - 1;
#else
#error Unknown board
#endif
default:
return -1;
}
}
......@@ -2,5 +2,6 @@
# Makefile for the HP6xx specific parts of the kernel
#
obj-y := mach.o setup.o
obj-y := setup.o
obj-$(CONFIG_PM) += pm.o pm_wakeup.o
obj-$(CONFIG_APM) += hp6xx_apm.o
/*
* bios-less APM driver for hp680
*
* Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/apm_bios.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/apm.h>
#include <asm/adc.h>
#include <asm/hp6xx/hp6xx.h>
#define SH7709_PGDR 0xa400012c
#define APM_CRITICAL 10
#define APM_LOW 30
#define HP680_BATTERY_MAX 875
#define HP680_BATTERY_MIN 600
#define HP680_BATTERY_AC_ON 900
#define MODNAME "hp6x0_apm"
static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
{
u8 pgdr;
char *p;
int battery_status;
int battery_flag;
int ac_line_status;
int time_units = APM_BATTERY_LIFE_UNKNOWN;
int battery = adc_single(ADC_CHANNEL_BATTERY);
int backup = adc_single(ADC_CHANNEL_BACKUP);
int charging = adc_single(ADC_CHANNEL_CHARGE);
int percentage;
percentage = 100 * (battery - HP680_BATTERY_MIN) /
(HP680_BATTERY_MAX - HP680_BATTERY_MIN);
ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
APM_AC_ONLINE : APM_AC_OFFLINE;
p = buf;
pgdr = ctrl_inb(SH7709_PGDR);
if (pgdr & PGDR_MAIN_BATTERY_OUT) {
battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
battery_flag = 0x80;
percentage = -1;
} else if (charging < 8 ) {
battery_status = APM_BATTERY_STATUS_CHARGING;
battery_flag = 0x08;
ac_line_status = 0xff;
} else if (percentage <= APM_CRITICAL) {
battery_status = APM_BATTERY_STATUS_CRITICAL;
battery_flag = 0x04;
} else if (percentage <= APM_LOW) {
battery_status = APM_BATTERY_STATUS_LOW;
battery_flag = 0x02;
} else {
battery_status = APM_BATTERY_STATUS_HIGH;
battery_flag = 0x01;
}
p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
APM_32_BIT_SUPPORT,
ac_line_status,
battery_status,
battery_flag,
percentage,
time_units,
"min");
p += sprintf(p, "bat=%d backup=%d charge=%d\n",
battery, backup, charging);
return p - buf;
}
static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev, struct pt_regs *regs)
{
if (!apm_suspended)
apm_queue_event(APM_USER_SUSPEND);
return IRQ_HANDLED;
}
static int __init hp6x0_apm_init(void)
{
int ret;
ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
SA_INTERRUPT, MODNAME, 0);
if (unlikely(ret < 0)) {
printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
HP680_BTN_IRQ);
return ret;
}
apm_get_info = hp6x0_apm_get_info;
return ret;
}
static void __exit hp6x0_apm_exit(void)
{
free_irq(HP680_BTN_IRQ, 0);
apm_get_info = 0;
}
module_init(hp6x0_apm_init);
module_exit(hp6x0_apm_exit);
MODULE_AUTHOR("Adriy Skulysh");
MODULE_DESCRIPTION("hp6xx Advanced Power Management");
MODULE_LICENSE("GPL");
/*
* hp6x0 Power Management Routines
*
* Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <asm/io.h>
#include <asm/hd64461.h>
#include <asm/hp6xx/hp6xx.h>
#include <asm/cpu/dac.h>
#include <asm/pm.h>
#define STBCR 0xffffff82
#define STBCR2 0xffffff88
static int hp6x0_pm_enter(suspend_state_t state)
{
u8 stbcr, stbcr2;
#ifdef CONFIG_HD64461_ENABLER
u8 scr;
u16 hd64461_stbcr;
#endif
if (state != PM_SUSPEND_MEM)
return -EINVAL;
#ifdef CONFIG_HD64461_ENABLER
outb(0, HD64461_PCC1CSCIER);
scr = inb(HD64461_PCC1SCR);
scr |= HD64461_PCCSCR_VCC1;
outb(scr, HD64461_PCC1SCR);
hd64461_stbcr = inw(HD64461_STBCR);
hd64461_stbcr |= HD64461_STBCR_SPC1ST;
outw(hd64461_stbcr, HD64461_STBCR);
#endif
ctrl_outb(0x1f, DACR);
stbcr = ctrl_inb(STBCR);
ctrl_outb(0x01, STBCR);
stbcr2 = ctrl_inb(STBCR2);
ctrl_outb(0x7f , STBCR2);
outw(0xf07f, HD64461_SCPUCR);
pm_enter();
outw(0, HD64461_SCPUCR);
ctrl_outb(stbcr, STBCR);
ctrl_outb(stbcr2, STBCR2);
#ifdef CONFIG_HD64461_ENABLER
hd64461_stbcr = inw(HD64461_STBCR);
hd64461_stbcr &= ~HD64461_STBCR_SPC1ST;
outw(hd64461_stbcr, HD64461_STBCR);
outb(0x4c, HD64461_PCC1CSCIER);
outb(0x00, HD64461_PCC1CSCR);
#endif
return 0;
}
/*
* Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
*/
static struct pm_ops hp6x0_pm_ops = {
.pm_disk_mode = PM_DISK_FIRMWARE,
.enter = hp6x0_pm_enter,
};
static int __init hp6x0_pm_init(void)
{
pm_set_ops(&hp6x0_pm_ops);
return 0;
}
late_initcall(hp6x0_pm_init);
/*
* Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
*/
#include <linux/linkage.h>
#include <asm/cpu/mmu_context.h>
#define k0 r0
#define k1 r1
#define k2 r2
#define k3 r3
#define k4 r4
/*
* Kernel mode register usage:
* k0 scratch
* k1 scratch
* k2 scratch (Exception code)
* k3 scratch (Return address)
* k4 scratch
* k5 reserved
* k6 Global Interrupt Mask (0--15 << 4)
* k7 CURRENT_THREAD_INFO (pointer to current thread info)
*/
ENTRY(wakeup_start)
! clear STBY bit
mov #-126, k2
and #127, k0
mov.b k0, @k2
! enable refresh
mov.l 5f, k1
mov.w 6f, k0
mov.w k0, @k1
! jump to handler
mov.l 2f, k2
mov.l 3f, k3
mov.l @k2, k2
mov.l 4f, k1
jmp @k1
nop
.align 2
1: .long EXPEVT
2: .long INTEVT
3: .long ret_from_irq
4: .long handle_exception
5: .long 0xffffff68
6: .word 0x0524
ENTRY(wakeup_end)
nop
......@@ -8,22 +8,22 @@
*
* Setup code for an HP680 (internal peripherials only)
*/
#include <linux/types.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/hd64461.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hp6xx/hp6xx.h>
#include <asm/cpu/dac.h>
const char *get_system_type(void)
{
return "HP6xx";
}
#define SCPCR 0xa4000116
#define SCPDR 0xa4000136
int __init platform_setup(void)
static void __init hp6xx_setup(char **cmdline_p)
{
u8 v8;
u16 v;
v = inw(HD64461_STBCR);
v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
......@@ -50,5 +50,51 @@ int __init platform_setup(void)
v8 &= ~DACR_DAE;
ctrl_outb(v8,DACR);
return 0;
v8 = ctrl_inb(SCPDR);
v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
v8 &= ~SCPDR_TS_SCAN_ENABLE;
ctrl_outb(v8, SCPDR);
v = ctrl_inw(SCPCR);
v &= ~SCPCR_TS_MASK;
v |= SCPCR_TS_ENABLE;
ctrl_outw(v, SCPCR);
}
/*
* XXX: This is stupid, we should have a generic machine vector for the cchips
* and just wrap the platform setup code in to this, as it's the only thing
* that ends up being different.
*/
struct sh_machine_vector mv_hp6xx __initmv = {
.mv_name = "hp6xx",
.mv_setup = hp6xx_setup,
.mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
.mv_inw = hd64461_inw,
.mv_inl = hd64461_inl,
.mv_outb = hd64461_outb,
.mv_outw = hd64461_outw,
.mv_outl = hd64461_outl,
.mv_inb_p = hd64461_inb_p,
.mv_inw_p = hd64461_inw,
.mv_inl_p = hd64461_inl,
.mv_outb_p = hd64461_outb_p,
.mv_outw_p = hd64461_outw,
.mv_outl_p = hd64461_outl,
.mv_insb = hd64461_insb,
.mv_insw = hd64461_insw,
.mv_insl = hd64461_insl,
.mv_outsb = hd64461_outsb,
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readw = hd64461_readw,
.mv_writew = hd64461_writew,
.mv_irq_demux = hd64461_irq_demux,
};
ALIAS_MV(hp6xx)
#
# Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
#
obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o
/*
* arch/sh/boards/landisk/io.c
*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
* I/O routine for I-O Data Device, Inc. LANDISK.
*
* Initial version only to support LAN access; some
* placeholder code from io_landisk.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
/*
* modifed by kogiidena
* 2005.03.03
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/landisk/iodata_landisk.h>
#include <asm/addrspace.h>
#include <asm/io.h>
extern void *area5_io_base; /* Area 5 I/O Base address */
extern void *area6_io_base; /* Area 6 I/O Base address */
static inline unsigned long port2adr(unsigned int port)
{
if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
if (port == 0x3f6)
return ((unsigned long)area5_io_base + 0x2c);
else
return ((unsigned long)area5_io_base + PA_PIDE_OFFSET +
((port - 0x1f0) << 1));
else if ((0x170 <= port && port < 0x178) || port == 0x376)
if (port == 0x376)
return ((unsigned long)area6_io_base + 0x2c);
else
return ((unsigned long)area6_io_base + PA_SIDE_OFFSET +
((port - 0x170) << 1));
else
maybebadio((unsigned long)port);
return port;
}
/*
* General outline: remap really low stuff [eventually] to SuperIO,
* stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
* is mapped through the PCI IO window. Stuff with high bits (PXSEG)
* should be way beyond the window, and is used w/o translation for
* compatibility.
*/
u8 landisk_inb(unsigned long port)
{
if (PXSEG(port))
return ctrl_inb(port);
else if (is_pci_ioaddr(port))
return ctrl_inb(pci_ioaddr(port));
return ctrl_inw(port2adr(port)) & 0xff;
}
u8 landisk_inb_p(unsigned long port)
{
u8 v;
if (PXSEG(port))
v = ctrl_inb(port);
else if (is_pci_ioaddr(port))
v = ctrl_inb(pci_ioaddr(port));
else
v = ctrl_inw(port2adr(port)) & 0xff;
ctrl_delay();
return v;
}
u16 landisk_inw(unsigned long port)
{
if (PXSEG(port))
return ctrl_inw(port);
else if (is_pci_ioaddr(port))
return ctrl_inw(pci_ioaddr(port));
else
maybebadio(port);
return 0;
}
u32 landisk_inl(unsigned long port)
{
if (PXSEG(port))
return ctrl_inl(port);
else if (is_pci_ioaddr(port))
return ctrl_inl(pci_ioaddr(port));
else
maybebadio(port);
return 0;
}
void landisk_outb(u8 value, unsigned long port)
{
if (PXSEG(port))
ctrl_outb(value, port);
else if (is_pci_ioaddr(port))
ctrl_outb(value, pci_ioaddr(port));
else
ctrl_outw(value, port2adr(port));
}
void landisk_outb_p(u8 value, unsigned long port)
{
if (PXSEG(port))
ctrl_outb(value, port);
else if (is_pci_ioaddr(port))
ctrl_outb(value, pci_ioaddr(port));
else
ctrl_outw(value, port2adr(port));
ctrl_delay();
}
void landisk_outw(u16 value, unsigned long port)
{
if (PXSEG(port))
ctrl_outw(value, port);
else if (is_pci_ioaddr(port))
ctrl_outw(value, pci_ioaddr(port));
else
maybebadio(port);
}
void landisk_outl(u32 value, unsigned long port)
{
if (PXSEG(port))
ctrl_outl(value, port);
else if (is_pci_ioaddr(port))
ctrl_outl(value, pci_ioaddr(port));
else
maybebadio(port);
}
void landisk_insb(unsigned long port, void *dst, unsigned long count)
{
volatile u16 *p;
u8 *buf = dst;
if (PXSEG(port)) {
while (count--)
*buf++ = *(volatile u8 *)port;
} else if (is_pci_ioaddr(port)) {
volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
while (count--)
*buf++ = *bp;
} else {
p = (volatile u16 *)port2adr(port);
while (count--)
*buf++ = *p & 0xff;
}
}
void landisk_insw(unsigned long port, void *dst, unsigned long count)
{
volatile u16 *p;
u16 *buf = dst;
if (PXSEG(port))
p = (volatile u16 *)port;
else if (is_pci_ioaddr(port))
p = (volatile u16 *)pci_ioaddr(port);
else
p = (volatile u16 *)port2adr(port);
while (count--)
*buf++ = *p;
}
void landisk_insl(unsigned long port, void *dst, unsigned long count)
{
u32 *buf = dst;
if (is_pci_ioaddr(port)) {
volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
while (count--)
*buf++ = *p;
} else
maybebadio(port);
}
void landisk_outsb(unsigned long port, const void *src, unsigned long count)
{
volatile u16 *p;
const u8 *buf = src;
if (PXSEG(port))
while (count--)
ctrl_outb(*buf++, port);
else if (is_pci_ioaddr(port)) {
volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
while (count--)
*bp = *buf++;
} else {
p = (volatile u16 *)port2adr(port);
while (count--)
*p = *buf++;
}
}
void landisk_outsw(unsigned long port, const void *src, unsigned long count)
{
volatile u16 *p;
const u16 *buf = src;
if (PXSEG(port))
p = (volatile u16 *)port;
else if (is_pci_ioaddr(port))
p = (volatile u16 *)pci_ioaddr(port);
else
p = (volatile u16 *)port2adr(port);
while (count--)
*p = *buf++;
}
void landisk_outsl(unsigned long port, const void *src, unsigned long count)
{
const u32 *buf = src;
if (is_pci_ioaddr(port)) {
volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
while (count--)
*p = *buf++;
} else
maybebadio(port);
}
void __iomem *landisk_ioport_map(unsigned long port, unsigned int size)
{
if (PXSEG(port))
return (void __iomem *)port;
else if (is_pci_ioaddr(port))
return (void __iomem *)pci_ioaddr(port);
return (void __iomem *)port2adr(port);
}
/*
* arch/sh/boards/landisk/irq.c
*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
* I/O routine for I-O Data Device, Inc. LANDISK.
*
* Initial version only to support LAN access; some
* placeholder code from io_landisk.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
/*
* modified by kogiidena
* 2005.03.03
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/landisk/iodata_landisk.h>
static void enable_landisk_irq(unsigned int irq);
static void disable_landisk_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_landisk_irq disable_landisk_irq
static void ack_landisk_irq(unsigned int irq);
static void end_landisk_irq(unsigned int irq);
static unsigned int startup_landisk_irq(unsigned int irq)
{
enable_landisk_irq(irq);
return 0; /* never anything pending */
}
static void disable_landisk_irq(unsigned int irq)
{
unsigned char val;
unsigned char mask = 0xff ^ (0x01 << (irq - 5));
/* Set the priority in IPR to 0 */
val = ctrl_inb(PA_IMASK);
val &= mask;
ctrl_outb(val, PA_IMASK);
}
static void enable_landisk_irq(unsigned int irq)
{
unsigned char val;
unsigned char value = (0x01 << (irq - 5));
/* Set priority in IPR back to original value */
val = ctrl_inb(PA_IMASK);
val |= value;
ctrl_outb(val, PA_IMASK);
}
static void ack_landisk_irq(unsigned int irq)
{
disable_landisk_irq(irq);
}
static void end_landisk_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_landisk_irq(irq);
}
static struct hw_interrupt_type landisk_irq_type = {
.typename = "LANDISK IRQ",
.startup = startup_landisk_irq,
.shutdown = shutdown_landisk_irq,
.enable = enable_landisk_irq,
.disable = disable_landisk_irq,
.ack = ack_landisk_irq,
.end = end_landisk_irq
};
static void make_landisk_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].handler = &landisk_irq_type;
disable_landisk_irq(irq);
}
/*
* Initialize IRQ setting
*/
void __init init_landisk_IRQ(void)
{
int i;
for (i = 5; i < 14; i++)
make_landisk_irq(i);
}
/*
* arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
*
* This driver will also support the I-O DATA Device, Inc. LANDISK Board.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copylight (C) 2002 Atom Create Engineering Co., Ltd.
*
* LED control drive function added by kogiidena
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/major.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/landisk/iodata_landisk.h>
#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */
#define LED_MINOR 21 /* LED minor no. */
#define BTN_MINOR 22 /* BUTTON minor no. */
#define GIO_MINOR 40 /* GIO minor no. */
static int openCnt;
static int openCntLED;
static int openCntGio;
static int openCntBtn;
static int landisk_btn;
static int landisk_btnctrlpid;
/*
* Functions prototypes
*/
static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
static int swdrv_open(struct inode *inode, struct file *filp)
{
int minor;
minor = MINOR(inode->i_rdev);
filp->private_data = (void *)minor;
if (minor == SHUTDOWN_BTN_MINOR) {
if (openCnt > 0) {
return -EALREADY;
} else {
openCnt++;
return 0;
}
} else if (minor == LED_MINOR) {
if (openCntLED > 0) {
return -EALREADY;
} else {
openCntLED++;
return 0;
}
} else if (minor == BTN_MINOR) {
if (openCntBtn > 0) {
return -EALREADY;
} else {
openCntBtn++;
return 0;
}
} else if (minor == GIO_MINOR) {
if (openCntGio > 0) {
return -EALREADY;
} else {
openCntGio++;
return 0;
}
}
return -ENOENT;
}
static int swdrv_close(struct inode *inode, struct file *filp)
{
int minor;
minor = MINOR(inode->i_rdev);
if (minor == SHUTDOWN_BTN_MINOR) {
openCnt--;
} else if (minor == LED_MINOR) {
openCntLED--;
} else if (minor == BTN_MINOR) {
openCntBtn--;
} else if (minor == GIO_MINOR) {
openCntGio--;
}
return 0;
}
static int swdrv_read(struct file *filp, char *buff, size_t count,
loff_t * ppos)
{
int minor;
minor = (int)(filp->private_data);
if (!access_ok(VERIFY_WRITE, (void *)buff, count))
return -EFAULT;
if (minor == SHUTDOWN_BTN_MINOR) {
if (landisk_btn & 0x10) {
put_user(1, buff);
return 1;
} else {
return 0;
}
}
return 0;
}
static int swdrv_write(struct file *filp, const char *buff, size_t count,
loff_t * ppos)
{
int minor;
minor = (int)(filp->private_data);
if (minor == SHUTDOWN_BTN_MINOR) {
return count;
}
return count;
}
static irqreturn_t sw_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
disable_irq(IRQ_BUTTON);
disable_irq(IRQ_POWER);
ctrl_outb(0x00, PA_PWRINT_CLR);
if (landisk_btnctrlpid != 0) {
kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
landisk_btnctrlpid = 0;
}
return IRQ_HANDLED;
}
static struct file_operations swdrv_fops = {
.read = swdrv_read, /* read */
.write = swdrv_write, /* write */
.open = swdrv_open, /* open */
.release = swdrv_close, /* release */
.ioctl = gio_ioctl, /* ioctl */
};
static char banner[] __initdata =
KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";
int __init swdrv_init(void)
{
int error;
printk("%s", banner);
openCnt = 0;
openCntLED = 0;
openCntBtn = 0;
openCntGio = 0;
landisk_btn = 0;
landisk_btnctrlpid = 0;
if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
printk(KERN_ERR
"Button, LED and GIO driver:Couldn't register driver, error=%d\n",
error);
return 1;
}
if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
printk(KERN_ERR "Unable to get IRQ 11.\n");
return 1;
}
if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
printk(KERN_ERR "Unable to get IRQ 12.\n");
return 1;
}
ctrl_outb(0x00, PA_PWRINT_CLR);
return 0;
}
module_init(swdrv_init);
/*
* gio driver
*
*/
#include <asm/landisk/gio.h>
static int gio_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int minor;
unsigned int data, mask;
static unsigned int addr = 0;
minor = (int)(filp->private_data);
/* access control */
if (minor == GIO_MINOR) {
;
} else if (minor == LED_MINOR) {
if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
;
} else {
return -EINVAL;
}
} else if (minor == BTN_MINOR) {
if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
;
} else {
return -EINVAL;
}
} else {
return -EINVAL;
}
if (cmd & 0x01) { /* write */
if (copy_from_user(&data, (int *)arg, sizeof(int))) {
return -EFAULT;
}
}
switch (cmd) {
case GIODRV_IOCSGIOSETADDR: /* addres set */
addr = data;
break;
case GIODRV_IOCSGIODATA1: /* write byte */
ctrl_outb((unsigned char)(0x0ff & data), addr);
break;
case GIODRV_IOCSGIODATA2: /* write word */
if (addr & 0x01) {
return -EFAULT;
}
ctrl_outw((unsigned short int)(0x0ffff & data), addr);
break;
case GIODRV_IOCSGIODATA4: /* write long */
if (addr & 0x03) {
return -EFAULT;
}
ctrl_outl(data, addr);
break;
case GIODRV_IOCGGIODATA1: /* read byte */
data = ctrl_inb(addr);
break;
case GIODRV_IOCGGIODATA2: /* read word */
if (addr & 0x01) {
return -EFAULT;
}
data = ctrl_inw(addr);
break;
case GIODRV_IOCGGIODATA4: /* read long */
if (addr & 0x03) {
return -EFAULT;
}
data = ctrl_inl(addr);
break;
case GIODRV_IOCSGIO_LED: /* write */
mask = ((data & 0x00ffffff) << 8)
| ((data & 0x0000ffff) << 16)
| ((data & 0x000000ff) << 24);
landisk_ledparam = data & (~mask);
if (landisk_arch == 0) { /* arch == landisk */
landisk_ledparam &= 0x03030303;
mask = (~(landisk_ledparam >> 22)) & 0x000c;
landisk_ledparam |= mask;
} else { /* arch == usl-5p */
mask = (landisk_ledparam >> 24) & 0x0001;
landisk_ledparam |= mask;
landisk_ledparam &= 0x007f7f7f;
}
landisk_ledparam |= 0x80;
break;
case GIODRV_IOCGGIO_LED: /* read */
data = landisk_ledparam;
if (landisk_arch == 0) { /* arch == landisk */
data &= 0x03030303;
} else { /* arch == usl-5p */
;
}
data &= (~0x080);
break;
case GIODRV_IOCSGIO_BUZZER: /* write */
landisk_buzzerparam = data;
landisk_ledparam |= 0x80;
break;
case GIODRV_IOCGGIO_LANDISK: /* read */
data = landisk_arch & 0x01;
break;
case GIODRV_IOCGGIO_BTN: /* read */
data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
data <<= 8;
data |= (0x0ff & ctrl_inb(PA_IMASK));
data <<= 8;
data |= (0x0ff & landisk_btn);
data <<= 8;
data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
break;
case GIODRV_IOCSGIO_BTNPID: /* write */
landisk_btnctrlpid = data;
landisk_btn = 0;
if (irq_desc[IRQ_BUTTON].depth) {
enable_irq(IRQ_BUTTON);
}
if (irq_desc[IRQ_POWER].depth) {
enable_irq(IRQ_POWER);
}
break;
case GIODRV_IOCGGIO_BTNPID: /* read */
data = landisk_btnctrlpid;
break;
default:
return -EFAULT;
break;
}
if ((cmd & 0x01) == 0) { /* read */
if (copy_to_user((int *)arg, &data, sizeof(int))) {
return -EFAULT;
}
}
return 0;
}
/*
* arch/sh/boards/landisk/rtc.c -- RTC support
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
*/
/*
* modifed by kogiidena
* 2005.09.16
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <asm/rtc.h>
extern spinlock_t rtc_lock;
extern void
rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon,
unsigned int BCD_day, unsigned int BCD_hr,
unsigned int BCD_min, unsigned int BCD_sec);
extern unsigned long
rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon,
unsigned int *BCD_day, unsigned int *BCD_hr,
unsigned int *BCD_min, unsigned int *BCD_sec);
void landisk_rtc_gettimeofday(struct timespec *tv)
{
unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
unsigned long flags;
spin_lock_irqsave(&rtc_lock, flags);
tv->tv_sec = rs5c313_get_cmos_time
(&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
tv->tv_nsec = 0;
spin_unlock_irqrestore(&rtc_lock, flags);
}
int landisk_rtc_settimeofday(const time_t secs)
{
int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
unsigned long flags;
unsigned long nowtime = secs;
unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
spin_lock_irqsave(&rtc_lock, flags);
rs5c313_get_cmos_time
(&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
cmos_minutes = BCD_min;
BCD_TO_BIN(cmos_minutes);
/*
* since we're only adjusting minutes and seconds,
* don't interfere with hour overflow. This avoids
* messing with unknown time zones but requires your
* RTC not to be off by more than 15 minutes
*/
real_seconds = nowtime % 60;
real_minutes = nowtime / 60;
if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
real_minutes += 30; /* correct for half hour time zone */
real_minutes %= 60;
if (abs(real_minutes - cmos_minutes) < 30) {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr,
real_minutes, real_seconds);
} else {
printk(KERN_WARNING
"set_rtc_time: can't update from %d to %d\n",
cmos_minutes, real_minutes);
retval = -1;
}
spin_unlock_irqrestore(&rtc_lock, flags);
return retval;
}
void landisk_time_init(void)
{
rtc_sh_get_time = landisk_rtc_gettimeofday;
rtc_sh_set_time = landisk_rtc_settimeofday;
}
/*
* arch/sh/boards/landisk/setup.c
*
* Copyright (C) 2000 Kazumoto Kojima
* Copyright (C) 2002 Paul Mundt
*
* I-O DATA Device, Inc. LANDISK Support.
*
* Modified for LANDISK by
* Atom Create Engineering Co., Ltd. 2002.
*
* modifed by kogiidena
* 2005.09.16
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/mm.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/landisk/iodata_landisk.h>
#include <asm/io.h>
void landisk_time_init(void);
void init_landisk_IRQ(void);
int landisk_ledparam;
int landisk_buzzerparam;
int landisk_arch;
/* cycle the led's in the clasic knightrider/sun pattern */
static void heartbeat_landisk(void)
{
static unsigned int cnt = 0, blink = 0x00, period = 25;
volatile u8 *p = (volatile u8 *)PA_LED;
char data;
if ((landisk_ledparam & 0x080) == 0)
return;
cnt += 1;
if (cnt < period)
return;
cnt = 0;
blink++;
data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0;
data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0;
data |= landisk_ledparam;
/* buzzer */
if (landisk_buzzerparam & 0x1) {
data |= 0x80;
} else {
data &= 0x7f;
}
*p = data;
if (((landisk_ledparam & 0x007f7f00) == 0) &&
(landisk_buzzerparam == 0))
landisk_ledparam &= (~0x0080);
landisk_buzzerparam >>= 1;
}
static void landisk_power_off(void)
{
ctrl_outb(0x01, PA_SHUTDOWN);
}
static void check_usl5p(void)
{
volatile u8 *p = (volatile u8 *)PA_LED;
u8 tmp1, tmp2;
tmp1 = *p;
*p = 0x40;
tmp2 = *p;
*p = tmp1;
landisk_arch = (tmp2 == 0x40);
if (landisk_arch == 1) {
/* arch == usl-5p */
landisk_ledparam = 0x00000380;
landisk_ledparam |= (tmp1 & 0x07c);
} else {
/* arch == landisk */
landisk_ledparam = 0x02000180;
landisk_ledparam |= 0x04;
}
}
void *area5_io_base;
void *area6_io_base;
static int __init landisk_cf_init(void)
{
pgprot_t prot;
unsigned long paddrbase, psize;
/* open I/O area window */
paddrbase = virt_to_phys((void *)PA_AREA5_IO);
psize = PAGE_SIZE;
prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16);
area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
if (!area5_io_base) {
printk("allocate_cf_area : can't open CF I/O window!\n");
return -ENOMEM;
}
paddrbase = virt_to_phys((void *)PA_AREA6_IO);
psize = PAGE_SIZE;
prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
if (!area6_io_base) {
printk("allocate_cf_area : can't open HDD I/O window!\n");
return -ENOMEM;
}
printk(KERN_INFO "Allocate Area5/6 success.\n");
/* XXX : do we need attribute and common-memory area also? */
return 0;
}
static void __init landisk_setup(char **cmdline_p)
{
device_initcall(landisk_cf_init);
landisk_buzzerparam = 0;
check_usl5p();
printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n");
board_time_init = landisk_time_init;
pm_power_off = landisk_power_off;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_landisk __initmv = {
.mv_name = "LANDISK",
.mv_setup = landisk_setup,
.mv_nr_irqs = 72,
.mv_inb = landisk_inb,
.mv_inw = landisk_inw,
.mv_inl = landisk_inl,
.mv_outb = landisk_outb,
.mv_outw = landisk_outw,
.mv_outl = landisk_outl,
.mv_inb_p = landisk_inb_p,
.mv_inw_p = landisk_inw,
.mv_inl_p = landisk_inl,
.mv_outb_p = landisk_outb_p,
.mv_outw_p = landisk_outw,
.mv_outl_p = landisk_outl,
.mv_insb = landisk_insb,
.mv_insw = landisk_insw,
.mv_insl = landisk_insl,
.mv_outsb = landisk_outsb,
.mv_outsw = landisk_outsw,
.mv_outsl = landisk_outsl,
.mv_ioport_map = landisk_ioport_map,
.mv_init_irq = init_landisk_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_landisk,
#endif
};
ALIAS_MV(landisk)
......@@ -130,7 +130,7 @@ int mpc1211_rtc_settimeofday(const struct timeval *tv)
void mpc1211_time_init(void)
{
rtc_get_time = mpc1211_rtc_gettimeofday;
rtc_set_time = mpc1211_rtc_settimeofday;
rtc_sh_get_time = mpc1211_rtc_gettimeofday;
rtc_sh_set_time = mpc1211_rtc_settimeofday;
}
......@@ -10,14 +10,12 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mpc1211/mpc1211.h>
#include <asm/mpc1211/pci.h>
#include <asm/mpc1211/m1543c.h>
/* ALI15X3 SMBus address offsets */
#define SMBHSTSTS (0 + 0x3100)
#define SMBHSTCNT (1 + 0x3100)
......@@ -50,11 +48,6 @@
#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
const char *get_system_type(void)
{
return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
}
static void __init pci_write_config(unsigned long busNo,
unsigned long devNo,
unsigned long fncNo,
......@@ -80,9 +73,6 @@ volatile unsigned long irq_err_count;
static void disable_mpc1211_irq(unsigned int irq)
{
unsigned long flags;
save_and_cli(flags);
if( irq < 8) {
m_irq_mask |= (1 << irq);
outb(m_irq_mask,I8259_M_MR);
......@@ -90,16 +80,11 @@ static void disable_mpc1211_irq(unsigned int irq)
s_irq_mask |= (1 << (irq - 8));
outb(s_irq_mask,I8259_S_MR);
}
restore_flags(flags);
}
static void enable_mpc1211_irq(unsigned int irq)
{
unsigned long flags;
save_and_cli(flags);
if( irq < 8) {
m_irq_mask &= ~(1 << irq);
outb(m_irq_mask,I8259_M_MR);
......@@ -107,7 +92,6 @@ static void enable_mpc1211_irq(unsigned int irq)
s_irq_mask &= ~(1 << (irq - 8));
outb(s_irq_mask,I8259_S_MR);
}
restore_flags(flags);
}
static inline int mpc1211_irq_real(unsigned int irq)
......@@ -131,10 +115,6 @@ static inline int mpc1211_irq_real(unsigned int irq)
static void mask_and_ack_mpc1211(unsigned int irq)
{
unsigned long flags;
save_and_cli(flags);
if(irq < 8) {
if(m_irq_mask & (1<<irq)){
if(!mpc1211_irq_real(irq)){
......@@ -162,7 +142,6 @@ static void mask_and_ack_mpc1211(unsigned int irq)
outb(0x60+(irq-8),I8259_S_CR); /* EOI */
outb(0x60+2,I8259_M_CR);
}
restore_flags(flags);
}
static void end_mpc1211_irq(unsigned int irq)
......@@ -219,7 +198,7 @@ int mpc1211_irq_demux(int irq)
return irq;
}
void __init init_mpc1211_IRQ(void)
static void __init init_mpc1211_IRQ(void)
{
int i;
/*
......@@ -255,23 +234,12 @@ void __init init_mpc1211_IRQ(void)
}
}
/*
Initialize the board
*/
static void delay (void)
{
volatile unsigned short tmp;
tmp = *(volatile unsigned short *) 0xa0000000;
}
static void delay1000 (void)
static void delay1000(void)
{
int i;
for (i=0; i<1000; i++)
delay ();
ctrl_delay();
}
static int put_smb_blk(unsigned char *p, int address, int command, int no)
......@@ -314,26 +282,10 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no)
return 0;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_mpc1211 __initmv = {
.mv_nr_irqs = 48,
.mv_irq_demux = mpc1211_irq_demux,
.mv_init_irq = init_mpc1211_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_mpc1211,
#endif
};
ALIAS_MV(mpc1211)
/* arch/sh/boards/mpc1211/rtc.c */
void mpc1211_time_init(void);
int __init platform_setup(void)
static void __init mpc1211_setup(char **cmdline_p)
{
unsigned char spd_buf[128];
......@@ -357,3 +309,18 @@ int __init platform_setup(void)
return 0;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_mpc1211 __initmv = {
.mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)",
.mv_setup = mpc1211_setup,
.mv_nr_irqs = 48,
.mv_irq_demux = mpc1211_irq_demux,
.mv_init_irq = init_mpc1211_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_mpc1211,
#endif
};
ALIAS_MV(mpc1211)
#
# Makefile for the STMicroelectronics Overdrive specific parts of the kernel
#
obj-y := mach.o setup.o io.o irq.o led.o
obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file handles programming up the Altera Flex10K that interfaces to
* the Galileo, and does the PS/2 keyboard and mouse
*
*/
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/overdriver/gt64111.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/fpga.h>
#define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
#define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK
/* I need to find out what (if any) the real delay factor here is */
/* The delay is definately not critical */
#define long_delay() {int i;for(i=0;i<10000;i++);}
#define short_delay() {int i;for(i=0;i<100;i++);}
static void __init program_overdrive_fpga(const unsigned char *fpgacode,
int size)
{
int timeout = 0;
int i, j;
unsigned char b;
static volatile unsigned char *FPGA_ControlReg =
(volatile unsigned char *) (OVERDRIVE_CTRL);
static volatile unsigned char *FPGA_ProgramReg =
(volatile unsigned char *) (FPGA_DCLK_ADDRESS);
printk("FPGA: Commencing FPGA Programming\n");
/* The PCI reset but MUST be low when programming the FPGA !!! */
b = (*FPGA_ControlReg) & RESET_PCI_MASK;
(*FPGA_ControlReg) = b;
/* Prepare FPGA to program */
FPGA_NotConfigHigh();
long_delay();
FPGA_NotConfigLow();
short_delay();
while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
printk("FPGA: Waiting for NotStatus to go Low ... \n");
}
FPGA_NotConfigHigh();
/* Wait for FPGA "ready to be programmed" signal */
printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n");
for (timeout = 0;
(((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
&& (timeout < FPGA_TIMEOUT)); timeout++);
/* Check if timeout condition occured - i.e. an error */
if (timeout == FPGA_TIMEOUT) {
printk
("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n");
return;
}
printk("FPGA: Copying data to FPGA ... %d bytes\n", size);
/* Copy array to FPGA - bit at a time */
for (i = 0; i < size; i++) {
volatile unsigned w = 0;
for (j = 0; j < 8; j++) {
*FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
short_delay();
}
if ((i & 0x3ff) == 0) {
printk(".");
}
}
/* Waiting for CONFDONE to go high - means the program is complete */
for (timeout = 0;
(((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
&& (timeout < FPGA_TIMEOUT)); timeout++) {
*FPGA_ProgramReg = 0x0;
long_delay();
}
if (timeout == FPGA_TIMEOUT) {
printk
("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n");
return;
} else { /* Clock another 10 times - gets the device into a working state */
for (i = 0; i < 10; i++) {
*FPGA_ProgramReg = 0x0;
short_delay();
}
}
printk("FPGA: Programming complete\n");
}
static const unsigned char __init fpgacode[] = {
#include "./overdrive.ttf" /* Code from maxplus2 compiler */
, 0, 0
};
int __init init_overdrive_fpga(void)
{
program_overdrive_fpga(fpgacode, sizeof(fpgacode));
return 0;
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains the PCI routines required for the Galileo GT6411
* PCI bridge as used on the Orion and Overdrive boards.
*
*/
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/gt64111.h>
/* After boot, we shift the Galileo registers so that they appear
* in BANK6, along with IO space. This means we can have one contingous
* lump of PCI address space without these registers appearing in the
* middle of them
*/
#define GT64111_BASE_ADDRESS 0xbb000000
#define GT64111_IO_BASE_ADDRESS 0x1000
/* The GT64111 registers appear at this address to the SH4 after reset */
#define RESET_GT64111_BASE_ADDRESS 0xb4000000
/* Macros used to access the Galileo registers */
#define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x)
#define GT64111_REG(x) (GT64111_BASE_ADDRESS+x)
#define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x))
#define RESET_GT_READ(x) readl(RESET_GT64111_REG(x))
#define GT_WRITE(x,v) writel((v),GT64111_REG(x))
#define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x))
#define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x))
#define GT_READ(x) readl(GT64111_REG(x))
#define GT_READ_BYTE(x) readb(GT64111_REG(x))
#define GT_READ_SHORT(x) readw(GT64111_REG(x))
/* Where the various SH banks start at */
#define SH_BANK4_ADR 0xb0000000
#define SH_BANK5_ADR 0xb4000000
#define SH_BANK6_ADR 0xb8000000
/* Masks out everything but lines 28,27,26 */
#define BANK_SELECT_MASK 0x1c000000
#define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK)
/*
* Masks used for address conversaion. Bank 6 is used for IO and
* has all the address bits zeroed by the FPGA. Special case this
*/
#define MEMORY_BANK_MASK 0x1fffffff
#define IO_BANK_MASK 0x03ffffff
/* Mark bank 6 as the bank used for IO. You can change this in the FPGA code
* if you want
*/
#define IO_BANK_ADR PCI_GTIO_BASE
/* Will select the correct mask to apply depending on the SH$ address */
#define SELECT_BANK_MASK(x) \
( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK)
/* Converts between PCI space and P2 region */
#define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x))
/* Various macros for figuring out what to stick in the Galileo registers.
* You *really* don't want to figure this stuff out by hand, you always get
* it wrong
*/
#define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff)
#define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f)
#define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff)
#define PROGRAM_HI_LO(block,a,s) \
GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\
GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1))
#define PROGRAM_SUB_HI_LO(block,a,s) \
GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\
GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1))
/* We need to set the size, and the offset register */
#define GT_BAR_MASK(x) ((x)&~0xfff)
/* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */
#define PROGRAM_GT_BAR(block,a,s) \
GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\
write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\
GT_BAR_MASK(a))
#define DISABLE_GT_BAR(block) \
GT_WRITE(PCI_##block##_BANK_SIZE,0),\
GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\
0x80000000)
/* Macros to disable things we are not going to use */
#define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\
GT_WRITE(x##_HI_DEC_ADR,0x00)
#define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\
GT_WRITE(x##_HI_DEC_ADR,0x00)
static void __init reset_pci(void)
{
/* Set RESET_PCI bit high */
writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
udelay(250);
/* Set RESET_PCI bit low */
writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL);
udelay(250);
writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
udelay(250);
}
static int write_config_to_galileo(int where, u32 val);
#define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val)
#define ENABLE_PCI_DRAM
#ifdef TEST_DRAM
/* Test function to check out if the PCI DRAM is working OK */
static int /* __init */ test_dram(unsigned *base, unsigned size)
{
unsigned *p = base;
unsigned *end = (unsigned *) (((unsigned) base) + size);
unsigned w;
for (p = base; p < end; p++) {
*p = 0xffffffff;
if (*p != 0xffffffff) {
printk("AAARGH -write failed!!! at %p is %x\n", p,
*p);
return 0;
}
*p = 0x0;
if (*p != 0x0) {
printk("AAARGH -write failed!!!\n");
return 0;
}
}
for (p = base; p < end; p++) {
*p = (unsigned) p;
if (*p != (unsigned) p) {
printk("Failed at 0x%p, actually is 0x%x\n", p,
*p);
return 0;
}
}
for (p = base; p < end; p++) {
w = ((unsigned) p & 0xffff0000);
*p = w | (w >> 16);
}
for (p = base; p < end; p++) {
w = ((unsigned) p & 0xffff0000);
w |= (w >> 16);
if (*p != w) {
printk
("Failed at 0x%p, should be 0x%x actually is 0x%x\n",
p, w, *p);
return 0;
}
}
return 1;
}
#endif
/* Function to set up and initialise the galileo. This sets up the BARS,
* maps the DRAM into the address space etc,etc
*/
int __init galileo_init(void)
{
reset_pci();
/* Now shift the galileo regs into this block */
RESET_GT_WRITE(INTERNAL_SPACE_DEC,
GT_MEM_LO_ADR(GT64111_BASE_ADDRESS));
/* Should have a sanity check here, that you can read back at the new
* address what you just wrote
*/
/* Disable decode for all regions */
DISABLE_DECODE(RAS10);
DISABLE_DECODE(RAS32);
DISABLE_DECODE(CS20);
DISABLE_DECODE(CS3);
DISABLE_DECODE(PCI_IO);
DISABLE_DECODE(PCI_MEM0);
DISABLE_DECODE(PCI_MEM1);
/* Disable all BARS */
GT_WRITE(BAR_ENABLE_ADR, 0x1ff);
DISABLE_GT_BAR(RAS10);
DISABLE_GT_BAR(RAS32);
DISABLE_GT_BAR(CS20);
DISABLE_GT_BAR(CS3);
/* Tell the BAR where the IO registers now are */
GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK(
(GT64111_IO_BASE_ADDRESS &
IO_BANK_MASK)));
/* set up a 112 Mb decode */
PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024);
/* Set up a 32 MB io space decode */
PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024);
#ifdef ENABLE_PCI_DRAM
/* Program up the DRAM configuration - there is DRAM only in bank 0 */
/* Now set up the DRAM decode */
PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE);
/* And the sub decode */
PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE);
DISABLE_SUB_DECODE(RAS1);
/* Set refresh rate */
GT_WRITE(DRAM_BANK0_PARMS, 0x3f);
GT_WRITE(DRAM_CFG, 0x100);
/* we have to lob off the top bits rememeber!! */
PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE);
#endif
/* We are only interested in decoding RAS10 and the Galileo's internal
* registers (as IO) on the PCI bus
*/
#ifdef ENABLE_PCI_DRAM
GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff);
#else
GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff);
#endif
/* Change the class code to host bridge, it actually powers up
* as a memory controller
*/
GT_CONFIG_WRITE(8, 0x06000011);
/* Allow the galileo to master the PCI bus */
GT_CONFIG_WRITE(PCI_COMMAND,
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_IO);
#if 0
printk("Testing PCI DRAM - ");
if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
printk("Passed\n");
}else {
printk("FAILED\n");
}
#endif
return 0;
}
#define SET_CONFIG_BITS(bus,devfn,where)\
((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3))
#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
/* This write to the galileo config registers, unlike the functions below, can
* be used before the PCI subsystem has started up
*/
static int __init write_config_to_galileo(int where, u32 val)
{
GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where));
GT_WRITE(PCI_CFG_DATA, val);
return 0;
}
/* We exclude the galileo and slot 31, the galileo because I don't know how to stop
* the setup code shagging up the setup I have done on it, and 31 because the whole
* thing locks up if you try to access that slot (which doesn't exist of course anyway
*/
#define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31)))
static int galileo_read_config_byte(struct pci_dev *dev, int where,
u8 * val)
{
/* I suspect this doesn't work because this drives a special cycle ? */
if (EXCLUDED_DEV(dev)) {
*val = 0xff;
return PCIBIOS_SUCCESSFUL;
}
/* Start the config cycle */
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
/* Read back the result */
*val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3));
return PCIBIOS_SUCCESSFUL;
}
static int galileo_read_config_word(struct pci_dev *dev, int where,
u16 * val)
{
if (EXCLUDED_DEV(dev)) {
*val = 0xffff;
return PCIBIOS_SUCCESSFUL;
}
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
*val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2));
return PCIBIOS_SUCCESSFUL;
}
static int galileo_read_config_dword(struct pci_dev *dev, int where,
u32 * val)
{
if (EXCLUDED_DEV(dev)) {
*val = 0xffffffff;
return PCIBIOS_SUCCESSFUL;
}
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
*val = GT_READ(PCI_CFG_DATA);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_byte(struct pci_dev *dev, int where,
u8 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_word(struct pci_dev *dev, int where,
u16 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val);
return PCIBIOS_SUCCESSFUL;
}
static int galileo_write_config_dword(struct pci_dev *dev, int where,
u32 val)
{
GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
GT_WRITE(PCI_CFG_DATA, val);
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_config_ops = {
galileo_read_config_byte,
galileo_read_config_word,
galileo_read_config_dword,
galileo_write_config_byte,
galileo_write_config_word,
galileo_write_config_dword
};
/* Everything hangs off this */
static struct pci_bus *pci_root_bus;
static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
{
return PCI_SLOT(dev->devfn);
}
static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
/* Slot 1: Galileo
* Slot 2: PCI Slot 1
* Slot 3: PCI Slot 2
* Slot 4: ESS
*/
switch (slot) {
case 2:
return OVERDRIVE_PCI_IRQ1;
case 3:
/* Note this assumes you have a hacked card in slot 2 */
return OVERDRIVE_PCI_IRQ2;
case 4:
return OVERDRIVE_ESS_IRQ;
default:
/* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */
return -1;
}
}
void __init
pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
ranges->io_start -= bus->resource[0]->start;
ranges->io_end -= bus->resource[0]->start;
ranges->mem_start -= bus->resource[1]->start;
ranges->mem_end -= bus->resource[1]->start;
}
static void __init pci_fixup_ide_bases(struct pci_dev *d)
{
int i;
/*
* PCI IDE controllers use non-standard I/O port decoding, respect it.
*/
if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
return;
printk("PCI: IDE base address fixup for %s\n", pci_name(d));
for(i=0; i<4; i++) {
struct resource *r = &d->resource[i];
if ((r->start & ~0x80) == 0x374) {
r->start |= 2;
r->end = r->start;
}
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
void __init pcibios_init(void)
{
static struct resource galio,galmem;
/* Allocate the registers used by the Galileo */
galio.flags = IORESOURCE_IO;
galio.name = "Galileo GT64011";
galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH;
galmem.name = "Galileo GT64011 DRAM";
allocate_resource(&ioport_resource, &galio, 256,
GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL);
allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE,
PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE,
PCI_DRAM_SIZE, NULL, NULL);
/* ok, do the scan man */
pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
pci_assign_unassigned_resources();
pci_fixup_irqs(no_swizzle, map_od_irq);
#ifdef TEST_DRAM
printk("Testing PCI DRAM - ");
if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
printk("Passed\n");
}else {
printk("FAILED\n");
}
#endif
}
char * __init pcibios_setup(char *str)
{
return str;
}
int pcibios_enable_device(struct pci_dev *dev)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
r = dev->resource + idx;
if (!r->start && r->end) {
printk(KERN_ERR
"PCI: Device %s not available because"
" of resource collisions\n",
pci_name(dev));
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
printk("PCI: enabling device %s (%04x -> %04x)\n",
pci_name(dev), old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
/* We should do some optimisation work here I think. Ok for now though */
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
}
void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size)
{
}
void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
{
unsigned long where, size;
u32 reg;
printk("PCI: Assigning %3s %08lx to %s\n",
res->flags & IORESOURCE_IO ? "IO" : "MEM",
res->start, dev->name);
where = PCI_BASE_ADDRESS_0 + resource * 4;
size = res->end - res->start;
pci_read_config_dword(dev, where, &reg);
reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
pci_write_config_dword(dev, where, reg);
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
/*
* If we set up a device for bus mastering, we need to check the latency
* timer as certain crappy BIOSes forget to set it properly.
*/
unsigned int pcibios_max_latency = 255;
void pcibios_set_master(struct pci_dev *dev)
{
u8 lat;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat < 16)
lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
else if (lat > pcibios_max_latency)
lat = pcibios_max_latency;
else
return;
printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains the I/O routines for use on the overdrive board
*
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/addrspace.h>
#include <asm/overdrive/overdrive.h>
/*
* readX/writeX() are used to access memory mapped devices. On some
* architectures the memory mapped IO stuff needs to be accessed
* differently. On the SuperH architecture, we just read/write the
* memory location directly.
*/
#define dprintk(x...)
/* Translates an IO address to where it is mapped in memory */
#define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE)
unsigned char od_inb(unsigned long port)
{
dprintk("od_inb(%x)\n", port);
return readb(io_addr(port)) & 0xff;
}
unsigned short od_inw(unsigned long port)
{
dprintk("od_inw(%x)\n", port);
return readw(io_addr(port)) & 0xffff;
}
unsigned int od_inl(unsigned long port)
{
dprintk("od_inl(%x)\n", port);
return readl(io_addr(port));
}
void od_outb(unsigned char value, unsigned long port)
{
dprintk("od_outb(%x, %x)\n", value, port);
writeb(value, io_addr(port));
}
void od_outw(unsigned short value, unsigned long port)
{
dprintk("od_outw(%x, %x)\n", value, port);
writew(value, io_addr(port));
}
void od_outl(unsigned int value, unsigned long port)
{
dprintk("od_outl(%x, %x)\n", value, port);
writel(value, io_addr(port));
}
/* This is horrible at the moment - needs more work to do something sensible */
#define IO_DELAY() udelay(10)
#define OUT_DELAY(x,type) \
void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
#define IN_DELAY(x,type) \
unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
OUT_DELAY(b,char)
OUT_DELAY(w,short)
OUT_DELAY(l,int)
IN_DELAY(b,char)
IN_DELAY(w,short)
IN_DELAY(l,int)
/* Now for the string version of these functions */
void od_outsb(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p++) {
outb(*p, port);
}
}
void od_insb(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p++) {
*p = inb(port);
}
}
/* For the 16 and 32 bit string functions, we have to worry about alignment.
* The SH does not do unaligned accesses, so we have to read as bytes and
* then write as a word or dword.
* This can be optimised a lot more, especially in the case where the data
* is aligned
*/
void od_outsw(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned short tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 2) {
tmp = (*p) | ((*(p + 1)) << 8);
outw(tmp, port);
}
}
void od_insw(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned short tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 2) {
tmp = inw(port);
p[0] = tmp & 0xff;
p[1] = (tmp >> 8) & 0xff;
}
}
void od_outsl(unsigned long port, const void *addr, unsigned long count)
{
int i;
unsigned tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 4) {
tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
((*(p + 3)) << 24);
outl(tmp, port);
}
}
void od_insl(unsigned long port, void *addr, unsigned long count)
{
int i;
unsigned tmp;
unsigned char *p = (unsigned char *) addr;
for (i = 0; i < count; i++, p += 4) {
tmp = inl(port);
p[0] = tmp & 0xff;
p[1] = (tmp >> 8) & 0xff;
p[2] = (tmp >> 16) & 0xff;
p[3] = (tmp >> 24) & 0xff;
}
}
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Looks after interrupts on the overdrive board.
*
* Bases on the IPR irq system
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
struct od_data {
int overdrive_irq;
int irq_mask;
};
#define NUM_EXTERNAL_IRQS 16
#define EXTERNAL_IRQ_NOT_IN_USE (-1)
#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
/*
* This table is used to determine what to program into the FPGA's CT register
* for the specified Linux IRQ.
*
* The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
* but is one greater than that because the because the FPGA treats 0
* as disabled, a value of 1 asserts PCI_Int0, and so on.
*
* The overdrive_irq specifies which of the eight interrupt sources generates
* that interrupt, and but is multiplied by four to give the bit offset into
* the CT register.
*
* The seven interrupts levels (SH4 IRL's) we have available here is hardwired
* by the EPLD. The assignments here of which PCI interrupt generates each
* level is arbitary.
*/
static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
/* overdrive_irq , irq_mask */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
{EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
{EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
};
static void set_od_data(int overdrive_irq, int irq)
{
if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
return;
od_data_table[irq].overdrive_irq = overdrive_irq << 2;
}
static void enable_od_irq(unsigned int irq);
void disable_od_irq(unsigned int irq);
/* shutdown is same as "disable" */
#define shutdown_od_irq disable_od_irq
static void mask_and_ack_od(unsigned int);
static void end_od_irq(unsigned int irq);
static unsigned int startup_od_irq(unsigned int irq)
{
enable_od_irq(irq);
return 0; /* never anything pending */
}
static struct hw_interrupt_type od_irq_type = {
.typename = "Overdrive-IRQ",
.startup = startup_od_irq,
.shutdown = shutdown_od_irq,
.enable = enable_od_irq,
.disable = disable_od_irq,
.ack = mask_and_ack_od,
.end = end_od_irq
};
static void disable_od_irq(unsigned int irq)
{
unsigned val, flags;
int overdrive_irq;
unsigned mask;
/* Not a valid interrupt */
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
/* Is is necessary to use a cli here? Would a spinlock not be
* mroe efficient?
*/
local_irq_save(flags);
overdrive_irq = od_data_table[irq].overdrive_irq;
if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
mask = ~(0x7 << overdrive_irq);
val = ctrl_inl(OVERDRIVE_INT_CT);
val &= mask;
ctrl_outl(val, OVERDRIVE_INT_CT);
}
local_irq_restore(flags);
}
static void enable_od_irq(unsigned int irq)
{
unsigned val, flags;
int overdrive_irq;
unsigned mask;
/* Not a valid interrupt */
if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
return;
/* Set priority in OD back to original value */
local_irq_save(flags);
/* This one is not in use currently */
overdrive_irq = od_data_table[irq].overdrive_irq;
if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
val = ctrl_inl(OVERDRIVE_INT_CT);
mask = ~(0x7 << overdrive_irq);
val &= mask;
mask = od_data_table[irq].irq_mask << overdrive_irq;
val |= mask;
ctrl_outl(val, OVERDRIVE_INT_CT);
}
local_irq_restore(flags);
}
/* this functions sets the desired irq handler to be an overdrive type */
static void __init make_od_irq(unsigned int irq)
{
disable_irq_nosync(irq);
irq_desc[irq].chip = &od_irq_type;
disable_od_irq(irq);
}
static void mask_and_ack_od(unsigned int irq)
{
disable_od_irq(irq);
}
static void end_od_irq(unsigned int irq)
{
enable_od_irq(irq);
}
void __init init_overdrive_irq(void)
{
int i;
/* Disable all interrupts */
ctrl_outl(0, OVERDRIVE_INT_CT);
/* Update interrupt pin mode to use encoded interrupts */
i = ctrl_inw(INTC_ICR);
i &= ~INTC_ICR_IRLM;
ctrl_outw(i, INTC_ICR);
for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
make_od_irq(i);
} else if (i != 15) { // Cannot use imask on level 15
make_imask_irq(i);
}
}
/* Set up the interrupts */
set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
}
/*
* linux/arch/sh/overdrive/led.c
*
* Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains an Overdrive specific LED feature.
*/
#include <asm/system.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
static void mach_led(int position, int value)
{
unsigned long flags;
unsigned long reg;
local_irq_save(flags);
reg = readl(OVERDRIVE_CTRL);
if (value) {
reg |= (1<<3);
} else {
reg &= ~(1<<3);
}
writel(reg, OVERDRIVE_CTRL);
local_irq_restore(flags);
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
/* acts like an actual heart beat -- ie thump-thump-pause... */
void heartbeat_od(void)
{
static unsigned cnt = 0, period = 0, dist = 0;
if (cnt == 0 || cnt == dist)
mach_led( -1, 1);
else if (cnt == 7 || cnt == dist+7)
mach_led( -1, 0);
if (++cnt > period) {
cnt = 0;
/* The hyperbolic function below modifies the heartbeat period
* length in dependency of the current (5min) load. It goes
* through the points f(0)=126, f(1)=86, f(5)=51,
* f(inf)->30. */
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
dist = period / 4;
}
}
#endif /* CONFIG_HEARTBEAT */
/*
* linux/arch/sh/overdrive/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Machine vector for the STMicroelectronics Overdrive
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io_unknown.h>
#include <asm/io_generic.h>
#include <asm/overdrive/io.h>
void heartbeat_od(void);
void init_overdrive_irq(void);
void galileo_pcibios_init(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_od __initmv = {
.mv_nr_irqs = 48,
.mv_inb = od_inb,
.mv_inw = od_inw,
.mv_inl = od_inl,
.mv_outb = od_outb,
.mv_outw = od_outw,
.mv_outl = od_outl,
.mv_inb_p = od_inb_p,
.mv_inw_p = od_inw_p,
.mv_inl_p = od_inl_p,
.mv_outb_p = od_outb_p,
.mv_outw_p = od_outw_p,
.mv_outl_p = od_outl_p,
.mv_insb = od_insb,
.mv_insw = od_insw,
.mv_insl = od_insl,
.mv_outsb = od_outsb,
.mv_outsw = od_outsw,
.mv_outsl = od_outsl,
#ifdef CONFIG_PCI
.mv_init_irq = init_overdrive_irq,
#endif
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_od,
#endif
};
ALIAS_MV(od)
/*
* Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* Dynamic DMA mapping support.
*
* On the overdrive, we can only DMA from memory behind the PCI bus!
* this means that all DMA'able memory must come from there.
* this restriction will not apply to later boards.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
#include <asm/io.h>
void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t * dma_handle)
{
void *ret;
int gfp = GFP_ATOMIC;
printk("BUG: pci_alloc_consistent() called - not yet supported\n");
/* We ALWAYS need DMA memory on the overdrive hardware,
* due to it's extreme weirdness
* Need to flush the cache here as well, since the memory
* can still be seen through the cache!
*/
gfp |= GFP_DMA;
ret = (void *) __get_free_pages(gfp, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
*dma_handle = virt_to_bus(ret);
}
return ret;
}
void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
free_pages((unsigned long) vaddr, get_order(size));
}
/*
* arch/sh/overdrive/setup.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* STMicroelectronics Overdrive Support.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/fpga.h>
const char *get_system_type(void)
{
return "SH7750 Overdrive";
}
/*
* Initialize the board
*/
int __init platform_setup(void)
{
#ifdef CONFIG_PCI
init_overdrive_fpga();
galileo_init();
#endif
/* Enable RS232 receive buffers */
writel(0x1e, OVERDRIVE_CTRL);
}
#
# Makefile for the EDOSK7705 specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := setup.o io.o
......@@ -8,19 +8,21 @@
* Modified for edosk7705 development
* board by S. Dunn, 2003.
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/edosk7705/io.h>
static void init_edosk7705(void);
static void __init sh_edosk7705_init_irq(void)
{
/* This is the Ethernet interrupt */
make_imask_irq(0x09);
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_name = "EDOSK7705",
.mv_nr_irqs = 80,
.mv_inb = sh_edosk7705_inb,
......@@ -37,23 +39,6 @@ struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_outsl = sh_edosk7705_outsl,
.mv_isa_port2addr = sh_edosk7705_isa_port2addr,
.mv_init_irq = init_edosk7705,
.mv_init_irq = sh_edosk7705_init_irq,
};
ALIAS_MV(edosk7705)
static void __init init_edosk7705(void)
{
/* This is the Ethernet interrupt */
make_imask_irq(0x09);
}
const char *get_system_type(void)
{
return "EDOSK7705";
}
void __init platform_setup(void)
{
/* Nothing .. */
}
if SH_HS7751RVOIP
menu "HS7751RVoIP options"
config HS7751RVOIP_CODEC
bool "Support VoIP Codec section"
help
Selecting this option will support CODEC section.
endmenu
endif
#
# Makefile for the HS7751RVoIP specific parts of the kernel
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o
obj-y := setup.o io.o irq.o
obj-$(CONFIG_PCI) += pci.o
......@@ -35,30 +35,24 @@ static unsigned int startup_hs7751rvoip_irq(unsigned int irq)
static void disable_hs7751rvoip_irq(unsigned int irq)
{
unsigned long flags;
unsigned short val;
unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
/* Set the priority in IPR to 0 */
local_irq_save(flags);
val = ctrl_inw(IRLCNTR3);
val &= mask;
ctrl_outw(val, IRLCNTR3);
local_irq_restore(flags);
}
static void enable_hs7751rvoip_irq(unsigned int irq)
{
unsigned long flags;
unsigned short val;
unsigned short value = (0x0001 << mask_pos[irq]);
/* Set priority in IPR back to original value */
local_irq_save(flags);
val = ctrl_inw(IRLCNTR3);
val |= value;
ctrl_outw(val, IRLCNTR3);
local_irq_restore(flags);
}
static void ack_hs7751rvoip_irq(unsigned int irq)
......
/*
* linux/arch/sh/kernel/setup_hs7751rvoip.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
* Renesas Technology Sales HS7751RVoIP Support.
*
* Modified for HS7751RVoIP by
* Atom Create Engineering Co., Ltd. 2002.
* Lineo uSolutions, Inc. 2003.
*/
#include <asm/io.h>
#include <asm/hs7751rvoip/hs7751rvoip.h>
extern unsigned int debug_counter;
void debug_led_disp(void)
{
unsigned short value;
value = (unsigned char)debug_counter++;
ctrl_outb((0xf0|value), PA_OUTPORTR);
if (value == 0x0f)
debug_counter = 0;
}
此差异已折叠。
if SH_R7780RP
menu "R7780RP options"
config SH_R7780MP
bool "R7780MP board support"
default y
help
Selecting this option will enable support for the mass-production
version of the R7780RP. If in doubt, say Y.
endmenu
endif
#
# Makefile for the R7780RP-1 specific parts of the kernel
#
obj-y := setup.o io.o irq.o
obj-$(CONFIG_HEARTBEAT) += led.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
if SH_RTS7751R2D
menu "RTS7751R2D options"
config RTS7751R2D_REV11
bool "RTS7751R2D Rev. 1.1 board support"
help
Selecting this option will support version rev. 1.1.
endmenu
endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册