Commit 43450275 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] SH Merge

From: Paul Mundt <lethal@linux-sh.org>

Here's a rather large update for SH (this is a bit large mainly since a
number of things have piled up, and Linus didn't want any of this during
feature freeze time). All of these changes are specific to the SH platform,
and as such, shouldn't effect any other platforms.
parent 1c2a00ad
This file describes the configuration and behavior of KGDB for the SH
kernel. Based on a description from Henry Bell <henry.bell@st.com>, it
has been modified to account for quirks in the current implementation.
Version
=======
This version of KGDB was written for 2.4.xx kernels for the SH architecture.
Further documentation is available from the linux-sh project website.
Debugging Setup: Host
======================
The two machines will be connected together via a serial line - this
should be a null modem cable i.e. with a twist.
On your DEVELOPMENT machine, go to your kernel source directory and
build the kernel, enabling KGDB support in the "kernel hacking" section.
This includes the KGDB code, and also makes the kernel be compiled with
the "-g" option set -- necessary for debugging.
To install this new kernel, use the following installation procedure.
Decide on which tty port you want the machines to communicate, then
cable them up back-to-back using the null modem. On the DEVELOPMENT
machine, you may wish to create an initialization file called .gdbinit
(in the kernel source directory or in your home directory) to execute
commonly-used commands at startup.
A minimal .gdbinit might look like this:
file vmlinux
set remotebaud 115200
target remote /dev/ttyS0
Change the "target" definition so that it specifies the tty port that
you intend to use. Change the "remotebaud" definition to match the
data rate that you are going to use for the com line (115200 is the
default).
Debugging Setup: Target
========================
By default, the KGDB stub will communicate with the host GDB using
ttySC1 at 115200 baud, 8 databits, no parity; these defaults can be
changed in the kernel configuration. As the kernel starts up, KGDB will
initialize so that breakpoints, kernel segfaults, and so forth will
generally enter the debugger.
This behavior can be modified by including the "kgdb" option in the
kernel command line; this option has the general form:
kgdb=<ttyspec>,<action>
The <ttyspec> indicates the port to use, and can optionally specify
baud, parity and databits -- e.g. "ttySC0,9600N8" or "ttySC1,19200".
The <action> can be "halt" or "disabled". The "halt" action enters the
debugger via a breakpoint as soon as kgdb is initialized; the "disabled"
action causes kgdb to ignore kernel segfaults and such until explicitly
entered by a breakpoint in the code or by external action (sysrq or NMI).
(Both <ttyspec> and <action> can appear alone, w/o the separating comma.)
For example, if you wish to debug early in kernel startup code, you
might specify the halt option:
kgdb=halt
Boot the TARGET machinem, which will appear to hang.
On your DEVELOPMENT machine, cd to the source directory and run the gdb
program. (This is likely to be a cross GDB which runs on your host but
is built for an SH target.) If everything is working correctly you
should see gdb print out a few lines indicating that a breakpoint has
been taken. It will actually show a line of code in the target kernel
inside the gdbstub activation code.
NOTE: BE SURE TO TERMINATE OR SUSPEND any other host application which
may be using the same serial port (for example, a terminal emulator you
have been using to connect to the target boot code.) Otherwise, data
from the target may not all get to GDB!
You can now use whatever gdb commands you like to set breakpoints.
Enter "continue" to start your target machine executing again. At this
point the target system will run at full speed until it encounters
your breakpoint or gets a segment violation in the kernel, or whatever.
Serial Ports: KGDB, Console
============================
This version of KGDB may not gracefully handle conflict with other
drivers in the kernel using the same port. If KGDB is configured on the
same port (and with the same parameters) as the kernel console, or if
CONFIG_SH_KGDB_CONSOLE is configured, things should be fine (though in
some cases console messages may appear twice through GDB). But if the
KGDB port is not the kernel console and used by another serial driver
which assumes different serial parameters (e.g. baud rate) KGDB may not
recover.
Also, when KGDB is entered via sysrq-g (requires CONFIG_KGDB_SYSRQ) and
the kgdb port uses the same port as the console, detaching GDB will not
restore the console to working order without the port being re-opened.
Another serious consequence of this is that GDB currently CANNOT break
into KGDB externally (e.g. via ^C or <BREAK>); unless a breakpoint or
error is encountered, the only way to enter KGDB after the initial halt
(see above) is via NMI (CONFIG_KGDB_NMI) or sysrq-g (CONFIG_KGDB_SYSRQ).
Code is included for the basic Hitachi Solution Engine boards to allow
the use of ttyS0 for KGDB if desired; this is less robust, but may be
useful in some cases. (This cannot be selected using the config file,
but only through the kernel command line, e.g. "kgdb=ttyS0", though the
configured defaults for baud rate etc. still apply if not overridden.)
If gdbstub Does Not Work
========================
If it doesn't work, you will have to troubleshoot it. Do the easy
things first like double checking your cabling and data rates. You
might try some non-kernel based programs to see if the back-to-back
connection works properly. Just something simple like cat /etc/hosts
/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
if you can send data from one machine to the other. There is no point
in tearing out your hair in the kernel if the line doesn't work.
If you need to debug the GDB/KGDB communication itself, the gdb commands
"set debug remote 1" and "set debug serial 1" may be useful, but be
warned: they produce a lot of output.
Threads
=======
Each process in a target machine is seen as a gdb thread. gdb thread related
commands (info threads, thread n) can be used. CONFIG_KGDB_THREAD must
be defined for this to work.
In this version, kgdb reports PID_MAX (32768) as the process ID for the
idle process (pid 0), since GDB does not accept 0 as an ID.
Detaching (exiting KGDB)
=========================
There are two ways to resume full-speed target execution: "continue" and
"detach". With "continue", GDB inserts any specified breakpoints in the
target code and resumes execution; the target is still in "gdb mode".
If a breakpoint or other debug event (e.g. NMI) happens, the target
halts and communicates with GDB again, which is waiting for it.
With "detach", GDB does *not* insert any breakpoints; target execution
is resumed and GDB stops communicating (does not wait for the target).
In this case, the target is no longer in "gdb mode" -- for example,
console messages no longer get sent separately to the KGDB port, or
encapsulated for GDB. If a debug event (e.g. NMI) occurs, the target
will re-enter "gdb mode" and will display this fact on the console; you
must give a new "target remote" command to gdb.
NOTE: TO AVOID LOSSING CONSOLE MESSAGES IN CASE THE KERNEL CONSOLE AND
KGDB USING THE SAME PORT, THE TARGET WAITS FOR ANY INPUT CHARACTER ON
THE KGDB PORT AFTER A DETACH COMMAND. For example, after the detach you
could start a terminal emulator on the same host port and enter a <cr>;
however, this program must then be terminated or suspended in order to
use GBD again if KGDB is re-entered.
Acknowledgements
================
This code was mostly generated by Henry Bell <henry.bell@st.com>;
largely from KGDB by Amit S. Kale <akale@veritas.com> - extracts from
code by Glenn Engel, Jim Kingdon, David Grothe <dave@gcom.com>, Tigran
Aivazian <tigran@sco.com>, William Gatliff <bgat@open-widgets.com>, Ben
Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com> are also
included.
Jeremy Siegel
<jsiegel@mvista.com>
This diff is collapsed.
This diff is collapsed.
# $Id: Makefile,v 1.17 2003/05/20 03:12:54 lethal Exp $
# $Id: Makefile,v 1.32 2003/10/26 23:33:49 lethal Exp $
#
# 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
......@@ -25,20 +25,20 @@ ifndef include_config
-include .config
endif
cpu-y := -mb
cpu-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml
cflags-y := -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml
cpu-$(CONFIG_CPU_SH2) += -m2
cpu-$(CONFIG_CPU_SH3) += -m3
cpu-$(CONFIG_CPU_SH4) += -m4 -mno-implicit-fp
cflags-$(CONFIG_CPU_SH2) += -m2
cflags-$(CONFIG_CPU_SH3) += -m3
cflags-$(CONFIG_CPU_SH4) += -m4 \
$(call check_gcc,-mno-implicit-fp,-m4-nofpu)
ifdef CONFIG_SH_KGDB
CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) -g
AFLAGS += -g
ifdef CONFIG_KGDB_MORE
CFLAGS += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
endif
endif
cflags-$(CONFIG_SH_DSP) += -Wa,-dsp
cflags-$(CONFIG_SH_KGDB) += -g
cflags-$(CONFIG_EMBEDDED) += -Os
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S
......@@ -49,13 +49,15 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S
LDFLAGS_vmlinux += -e _stext
ifdef CONFIG_CPU_LITTLE_ENDIAN
LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64' -EL
LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64'
LDFLAGS += -EL
else
LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64+4' -EB
LDFLAGS_vmlinux += --defsym 'jiffies=jiffies_64+4'
LDFLAGS += -EB
endif
CFLAGS += -pipe $(cpu-y)
AFLAGS += $(cpu-y)
CFLAGS += -pipe $(cflags-y)
AFLAGS += $(cflags-y)
head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
......@@ -66,6 +68,7 @@ core-y += arch/sh/kernel/ arch/sh/mm/
# Boards
machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
machdir-$(CONFIG_SH_7751_SYSTEMH) := systemh
machdir-$(CONFIG_SH_STB1_HARP) := harp
machdir-$(CONFIG_SH_STB1_OVERDRIVE) := overdrive
machdir-$(CONFIG_SH_HP620) := hp6xx/hp620
......@@ -81,6 +84,7 @@ machdir-$(CONFIG_SH_BIGSUR) := bigsur
machdir-$(CONFIG_SH_SH2000) := sh2000
machdir-$(CONFIG_SH_ADX) := adx
machdir-$(CONFIG_SH_MPC1211) := mpc1211
machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear
machdir-$(CONFIG_SH_UNKNOWN) := unknown
incdir-y := $(machdir-y)
......@@ -99,7 +103,10 @@ cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2
cpuincdir-$(CONFIG_CPU_SH3) := cpu-sh3
cpuincdir-$(CONFIG_CPU_SH4) := cpu-sh4
libs-y += arch/sh/lib/ $(LIBGCC)
libs-y := arch/sh/lib/ $(libs-y) $(LIBGCC)
drivers-y += arch/sh/drivers/
drivers-$(CONFIG_OPROFILE) += arch/sh/oprofile/
boot := arch/sh/boot
......@@ -110,18 +117,36 @@ prepare: target_links
.PHONY: target_links FORCE
target_links:
@echo ' Making asm-sh/cpu -> asm-sh/$(cpuincdir-y) link'
@rm -f include/asm-sh/cpu
@ln -sf $(cpuincdir-y) include/asm-sh/cpu
@echo ' Making asm-sh/mach -> asm-sh/$(incdir-y) link'
@rm -f include/asm-sh/mach
@ln -sf $(incdir-y) include/asm-sh/mach
$(Q)$(MAKE) $(build)=arch/sh/tools include/asm-sh/machtypes.h
BOOTIMAGE=arch/sh/boot/zImage
zImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
compressed: zImage
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
defconfig-%:
@echo ' Copying arch/sh/configs/$@ -> .config'
@if [ -e .config ]; then mv -f .config .config.old; fi
@cp -f arch/sh/configs/$@ .config
@chmod 644 .config
define archhelp
@echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)'
for board in arch/sh/configs/*; \
do \
echo -n ' ' $$board | sed -e 's|arch/sh/configs/||g' ; \
echo -n ' - Build for ' ; \
echo -e $$board | sed -e 's|.*-||g'; \
done
endef
......@@ -6,5 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o irq_maskreq.o
obj-y := setup.o irq.o irq_maskreq.o
/*
* linux/arch/sh/kernel/io_adx.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/io.h>
#include <asm/machvec.h>
#include <linux/module.h>
#define PORT2ADDR(x) (adx_isa_port2addr(x))
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
unsigned char adx_inb(unsigned long port)
{
return *(volatile unsigned char*)PORT2ADDR(port);
}
unsigned short adx_inw(unsigned long port)
{
return *(volatile unsigned short*)PORT2ADDR(port);
}
unsigned int adx_inl(unsigned long port)
{
return *(volatile unsigned long*)PORT2ADDR(port);
}
unsigned char adx_inb_p(unsigned long port)
{
unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
delay();
return v;
}
unsigned short adx_inw_p(unsigned long port)
{
unsigned long v = *(volatile unsigned short*)PORT2ADDR(port);
delay();
return v;
}
unsigned int adx_inl_p(unsigned long port)
{
unsigned long v = *(volatile unsigned long*)PORT2ADDR(port);
delay();
return v;
}
void adx_insb(unsigned long port, void *buffer, unsigned long count)
{
unsigned char *buf = buffer;
while(count--) *buf++ = inb(port);
}
void adx_insw(unsigned long port, void *buffer, unsigned long count)
{
unsigned short *buf = buffer;
while(count--) *buf++ = inw(port);
}
void adx_insl(unsigned long port, void *buffer, unsigned long count)
{
unsigned long *buf = buffer;
while(count--) *buf++ = inl(port);
}
void adx_outb(unsigned char b, unsigned long port)
{
*(volatile unsigned char*)PORT2ADDR(port) = b;
}
void adx_outw(unsigned short b, unsigned long port)
{
*(volatile unsigned short*)PORT2ADDR(port) = b;
}
void adx_outl(unsigned int b, unsigned long port)
{
*(volatile unsigned long*)PORT2ADDR(port) = b;
}
void adx_outb_p(unsigned char b, unsigned long port)
{
*(volatile unsigned char*)PORT2ADDR(port) = b;
delay();
}
void adx_outw_p(unsigned short b, unsigned long port)
{
*(volatile unsigned short*)PORT2ADDR(port) = b;
delay();
}
void adx_outl_p(unsigned int b, unsigned long port)
{
*(volatile unsigned long*)PORT2ADDR(port) = b;
delay();
}
void adx_outsb(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned char *buf = buffer;
while(count--) outb(*buf++, port);
}
void adx_outsw(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned short *buf = buffer;
while(count--) outw(*buf++, port);
}
void adx_outsl(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned long *buf = buffer;
while(count--) outl(*buf++, port);
}
unsigned char adx_readb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
unsigned short adx_readw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
unsigned int adx_readl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
void adx_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
void adx_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
void adx_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
void *adx_ioremap(unsigned long offset, unsigned long size)
{
return (void *)P2SEGADDR(offset);
}
EXPORT_SYMBOL (adx_ioremap);
void adx_iounmap(void *addr)
{
}
EXPORT_SYMBOL(adx_iounmap);
#ifdef CONFIG_IDE
#include <linux/vmalloc.h>
extern void *cf_io_base;
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)*/
}
#endif
/*
* linux/arch/sh/kernel/mach_adx.c
*
* Copyright (C) 2001 A&D Co., Ltd.
*
* This file may be copied or modified under the terms of the GNU
* General Public License. See linux/COPYING for more information.
*
* Machine vector for the A&D ADX Board
*/
#include <linux/config.h>
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/adx/io.h>
extern void init_adx_IRQ(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_adx __initmv = {
.mv_nr_irqs = 48,
.mv_inb = adx_inb,
.mv_inw = adx_inw,
.mv_inl = adx_inl,
.mv_outb = adx_outb,
.mv_outw = adx_outw,
.mv_outl = adx_outl,
.mv_inb_p = adx_inb_p,
.mv_inw_p = adx_inw,
.mv_inl_p = adx_inl,
.mv_outb_p = adx_outb_p,
.mv_outw_p = adx_outw,
.mv_outl_p = adx_outl,
.mv_insb = adx_insb,
.mv_insw = adx_insw,
.mv_insl = adx_insl,
.mv_outsb = adx_outsb,
.mv_outsw = adx_outsw,
.mv_outsl = adx_outsl,
.mv_readb = adx_readb,
.mv_readw = adx_readw,
.mv_readl = adx_readl,
.mv_writeb = adx_writeb,
.mv_writew = adx_writew,
.mv_writel = adx_writel,
.mv_ioremap = adx_ioremap,
.mv_iounmap = adx_iounmap,
.mv_isa_port2addr = adx_isa_port2addr,
.mv_init_irq = init_adx_IRQ,
};
ALIAS_MV(adx)
......@@ -14,11 +14,43 @@
#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";
}
void platform_setup(void)
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;
}
......@@ -6,7 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o led.o
obj-$(CONFIG_PCI) += pci.o
obj-y := setup.o io.o irq.o led.o
......@@ -21,18 +21,6 @@
#include <asm/io.h>
#include <asm/bigsur/bigsur.h>
//#define BIGSUR_DEBUG 2
#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
/* Low iomap maps port 0-1K to addresses in 8byte chunks */
#define BIGSUR_IOMAP_LO_THRESH 0x400
#define BIGSUR_IOMAP_LO_SHIFT 3
......@@ -53,19 +41,17 @@ static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP];
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
{
u32 port, endport = baseport + nports;
u32 port, endport = baseport + nports;
DPRINTK("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
baseport, nports, addr);
pr_debug("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
baseport, nports, addr);
for (port = baseport ;
port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
DPRINTK(" maplo[0x%x] = 0x%08x\n", port, addr);
pr_debug(" maplo[0x%x] = 0x%08x\n", port, addr);
bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr;
bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift;
addr += (1<<(BIGSUR_IOMAP_LO_SHIFT));
......@@ -74,7 +60,7 @@ void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
DPRINTK(" maphi[0x%x] = 0x%08x\n", port, addr);
pr_debug(" maphi[0x%x] = 0x%08x\n", port, addr);
bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr;
bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift;
addr += (1<<(BIGSUR_IOMAP_HI_SHIFT));
......@@ -84,166 +70,56 @@ EXPORT_SYMBOL(bigsur_port_map);
void bigsur_port_unmap(u32 baseport, u32 nports)
{
u32 port, endport = baseport + nports;
u32 port, endport = baseport + nports;
DPRINTK("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
pr_debug("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
for (port = baseport ;
port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
}
for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
}
}
EXPORT_SYMBOL(bigsur_port_unmap);
unsigned long bigsur_isa_port2addr(unsigned long port)
{
unsigned long addr = 0;
unsigned long addr = 0;
unsigned char shift;
/* Physical address not in P0, do nothing */
if (PXSEG(port)) addr = port;
if (PXSEG(port)) {
addr = port;
/* physical address in P0, map to P2 */
else if (port >= 0x30000)
addr = P2SEGADDR(port);
} else if (port >= 0x30000) {
addr = P2SEGADDR(port);
/* Big Sur I/O + HD64465 registers 0x10000-0x30000 */
else if (port >= BIGSUR_IOMAP_HI_THRESH)
addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
} else if (port >= BIGSUR_IOMAP_HI_THRESH) {
addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
/* Handle remapping of high IO/PCI IO ports */
else if (port >= BIGSUR_IOMAP_LO_THRESH) {
addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
if (addr != 0)
addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
}
/* Handle remapping of low IO ports */
else {
addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
if (addr != 0)
addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
} else if (port >= BIGSUR_IOMAP_LO_THRESH) {
addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
if (addr != 0)
addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
} else {
/* Handle remapping of low IO ports */
addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
if (addr != 0)
addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
}
DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr);
pr_debug("%s(0x%08lx) = 0x%08lx\n", __FUNCTION__, port, addr);
return addr;
}
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
unsigned char bigsur_inb(unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b);
return b;
}
unsigned char bigsur_inb_p(unsigned long port)
{
unsigned long v;
unsigned long addr = PORT2ADDR(port);
v = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
delay();
DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v);
return v;
}
unsigned short bigsur_inw(unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr);
DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b);
return b;
}
unsigned int bigsur_inl(unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr);
DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b);
return b;
}
void bigsur_insb(unsigned long port, void *buffer, unsigned long count)
{
unsigned char *buf=buffer;
while(count--) *buf++=inb(port);
}
void bigsur_insw(unsigned long port, void *buffer, unsigned long count)
{
unsigned short *buf=buffer;
while(count--) *buf++=inw(port);
}
void bigsur_insl(unsigned long port, void *buffer, unsigned long count)
{
unsigned long *buf=buffer;
while(count--) *buf++=inl(port);
}
void bigsur_outb(unsigned char b, unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr);
if (addr != 0)
*(volatile unsigned char*)addr = b;
}
void bigsur_outb_p(unsigned char b, unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr);
if (addr != 0)
*(volatile unsigned char*)addr = b;
delay();
}
void bigsur_outw(unsigned short b, unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr);
if (addr != 0)
*(volatile unsigned short*)addr = b;
}
void bigsur_outl(unsigned int b, unsigned long port)
{
unsigned long addr = PORT2ADDR(port);
DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr);
if (addr != 0)
*(volatile unsigned long*)addr = b;
}
void bigsur_outsb(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned char *buf=buffer;
while(count--) outb(*buf++, port);
}
void bigsur_outsw(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned short *buf=buffer;
while(count--) outw(*buf++, port);
}
void bigsur_outsl(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned long *buf=buffer;
while(count--) outl(*buf++, port);
}
/*
* linux/arch/sh/kernel/mach_bigsur.c
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
* Derived from mach_se.h, 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 Hitachi Big Sur Evaluation Board
*/
#include <linux/config.h>
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/bigsur/io.h>
#include <asm/irq.h>
/*
* 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_inb = bigsur_inb,
.mv_inw = bigsur_inw,
.mv_inl = bigsur_inl,
.mv_outb = bigsur_outb,
.mv_outw = bigsur_outw,
.mv_outl = bigsur_outl,
.mv_inb_p = bigsur_inb_p,
.mv_inw_p = bigsur_inw,
.mv_inl_p = bigsur_inl,
.mv_outb_p = bigsur_outb_p,
.mv_outw_p = bigsur_outw,
.mv_outl_p = bigsur_outl,
.mv_insb = bigsur_insb,
.mv_insw = bigsur_insw,
.mv_insl = bigsur_insl,
.mv_outsb = bigsur_outsb,
.mv_outsw = bigsur_outsw,
.mv_outsl = bigsur_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.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)
/*
* linux/arch/sh/kernel/pci-bigsur.c
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* PCI initialization for the Hitachi Big Sur Evaluation Board
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/pci-sh7751.h>
#include <asm/bigsur/bigsur.h>
#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
/*
* Initialize the Big Sur PCI interface
* Setup hardware to be Central Funtion
* Copy the BSR regs to the PCI interface
* Setup PCI windows into local RAM
*/
int __init pcibios_init_platform(void) {
u32 reg;
u32 word;
PCIDBG(1,"PCI: bigsur_pci_init called\n");
/* Set the BCR's to enable PCI access */
reg = inl(SH7751_BCR1);
reg |= 0x80000;
outl(reg, SH7751_BCR1);
/* Setup the host hardware */
if(inl(PCI_REG(SH7751_PCICONF0)) !=
(u32)((SH7751_DEVICE_ID <<16) | (SH7751_VENDOR_ID))) {
printk("PCI: Unkown PCI host bridge.\n");
return 0;
}
printk("PCI: SH7751 PCI host bridge found.\n");
/* Turn the clocks back on (not done in reset)*/
outl(0, PCI_REG(SH7751_PCICLKR));
/* Clear Powerdown IRQ's (not done in reset) */
word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
outl(word, PCI_REG(SH7751_PCICLKR));
/* toggle PCI reset pin */
word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
outl(word,PCI_REG(SH7751_PCICR));
/* Wait for a long time... not 1 sec. but long enough */
mdelay(100);
word = SH7751_PCICR_PREFIX;
outl(word,PCI_REG(SH7751_PCICR));
/* set the command/status bits to:
* Wait Cycle Control + Parity Enable + Bus Master +
* Mem space enable
*/
word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
outl(word, PCI_REG(SH7751_PCICONF1));
/* define this host as the host bridge */
word = SH7751_PCI_HOST_BRIDGE << 24;
outl(word, PCI_REG(SH7751_PCICONF2));
/* Set IO and Mem windows to local address
* Make PCI and local address the same for easy 1 to 1 mapping
* Window0 = BIGSUR_LSR0_SIZE @ non-cached CS3 base = SDRAM
* Window1 = BIGSUR_LSR1_SIZE @ cached CS3 base = SDRAM
*/
word = BIGSUR_LSR0_SIZE - 1;
outl(word, PCI_REG(SH7751_PCILSR0));
word = BIGSUR_LSR1_SIZE - 1;
outl(word, PCI_REG(SH7751_PCILSR1));
/* Set the values on window 0 PCI config registers */
word = P2SEGADDR(SH7751_CS3_BASE_ADDR);
outl(word, PCI_REG(SH7751_PCILAR0));
outl(word, PCI_REG(SH7751_PCICONF5));
/* Set the values on window 1 PCI config registers */
word = PHYSADDR(SH7751_CS3_BASE_ADDR);
outl(word, PCI_REG(SH7751_PCILAR1));
outl(word, PCI_REG(SH7751_PCICONF6));
/* Set the local 16MB PCI memory space window to
* the lowest PCI mapped address
*/
word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
outl(word , PCI_REG(SH7751_PCIMBR));
/* Map IO space into PCI IO window
* The IO window is 64K-PCIBIOS_MIN_IO in size
* IO addresses will be translated to the
* PCI IO window base address
*/
PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
(64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
/* Make sure the MSB's of IO window are set to access PCI space correctly */
word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
outl(word, PCI_REG(SH7751_PCIIOBR));
/* Set PCI WCRx, BCRx's, copy from BSC locations */
word = inl(SH7751_BCR1);
/* check BCR for SDRAM in area 3 */
if(((word >> 3) & 1) == 0) {
printk("PCI: Area 3 is not configured for SDRAM. BCR1=0x%x\n", word);
return 0;
}
outl(word, PCI_REG(SH7751_PCIBCR1));
word = (u16)inw(SH7751_BCR2);
/* check BCR2 for 32bit SDRAM interface*/
if(((word >> 6) & 0x3) != 0x3) {
printk("PCI: Area 3 is not 32 bit SDRAM. BCR2=0x%x\n", word);
return 0;
}
outl(word, PCI_REG(SH7751_PCIBCR2));
/* configure the wait control registers */
word = inl(SH7751_WCR1);
outl(word, PCI_REG(SH7751_PCIWCR1));
word = inl(SH7751_WCR2);
outl(word, PCI_REG(SH7751_PCIWCR2));
word = inl(SH7751_WCR3);
outl(word, PCI_REG(SH7751_PCIWCR3));
word = inl(SH7751_MCR);
outl(word, PCI_REG(SH7751_PCIMCR));
/* NOTE: I'm ignoring the PCI error IRQs for now..
* TODO: add support for the internal error interrupts and
* DMA interrupts...
*/
/* SH7751 init done, set central function init complete */
word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN;
outl(word,PCI_REG(SH7751_PCICR));
PCIDBG(2,"PCI: bigsur_pci_init finished\n");
return 1;
}
int pcibios_map_platform_irq(u8 slot, u8 pin)
{
/* The Big Sur can be used in a CPCI chassis, but the SH7751 PCI interface is on the
* wrong end of the board so that it can also support a V320 CPI interface chip...
* Therefor the IRQ mapping is somewhat use dependent... I'l assume a linear map for
* now, i.e. INTA=slot0,pin0... INTD=slot3,pin0...
*/
int irq = (slot + pin-1)%4 + BIGSUR_SH7751_PCI_IRQ_BASE;
PCIDBG(2,"PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", slot, pin-1+'A', irq);
return irq;
}
......@@ -33,22 +33,11 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/machvec.h>
#include <asm/bigsur/io.h>
#include <asm/hd64465/hd64465.h>
#include <asm/bigsur/bigsur.h>
//#define BIGSUR_DEBUG 3
#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 */
/*===========================================================*/
// Big Sur Init Routines
/*===========================================================*/
......@@ -58,13 +47,27 @@ const char *get_system_type(void)
return "Big Sur";
}
int __init platform_setup(void)
{
static int done = 0; /* run this only once */
/*
* 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,
if (!MACH_BIGSUR || done) return 0;
done = 1;
.mv_init_irq = init_bigsur_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_bigsur,
#endif
};
ALIAS_MV(bigsur)
int __init platform_setup(void)
{
/* Mask all 2nd level IRQ's */
outb(-1,BIGSUR_IMR0);
outb(-1,BIGSUR_IMR1);
......@@ -88,7 +91,6 @@ int __init platform_setup(void)
/* set the IO port to BIGSUR_ETHER_IOPORT */
outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
return 0;
return 0;
}
module_init(setup_bigsur);
......@@ -6,5 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
obj-y := setup.o irq.o
/*
* linux/arch/sh/boards/cat68701/io.c
*
* Copyright (C) 2000 Niibe Yutaka
* 2001 Yutaro Ebihara
*
* I/O 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 <linux/config.h>
#include <linux/module.h>
#define SH3_PCMCIA_BUG_WORKAROUND 1
#define DUMMY_READ_AREA6 0xba000000
#define PORT2ADDR(x) (cat68701_isa_port2addr(x))
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
unsigned char cat68701_inb(unsigned long port)
{
return *(volatile unsigned char*)PORT2ADDR(port);
}
unsigned short cat68701_inw(unsigned long port)
{
return *(volatile unsigned short*)PORT2ADDR(port);
}
unsigned int cat68701_inl(unsigned long port)
{
return *(volatile unsigned long*)PORT2ADDR(port);
}
unsigned char cat68701_inb_p(unsigned long port)
{
unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
delay();
return v;
}
unsigned short cat68701_inw_p(unsigned long port)
{
unsigned long v = *(volatile unsigned short*)PORT2ADDR(port);
delay();
return v;
}
unsigned int cat68701_inl_p(unsigned long port)
{
unsigned long v = *(volatile unsigned long*)PORT2ADDR(port);
delay();
return v;
}
void cat68701_insb(unsigned long port, void *buffer, unsigned long count)
{
unsigned char *buf=buffer;
while(count--) *buf++=inb(port);
}
void cat68701_insw(unsigned long port, void *buffer, unsigned long count)
{
unsigned short *buf=buffer;
while(count--) *buf++=inw(port);
#ifdef SH3_PCMCIA_BUG_WORKAROUND
ctrl_inb (DUMMY_READ_AREA6);
#endif
}
void cat68701_insl(unsigned long port, void *buffer, unsigned long count)
{
unsigned long *buf=buffer;
while(count--) *buf++=inl(port);
#ifdef SH3_PCMCIA_BUG_WORKAROUND
ctrl_inb (DUMMY_READ_AREA6);
#endif
}
void cat68701_outb(unsigned char b, unsigned long port)
{
*(volatile unsigned char*)PORT2ADDR(port) = b;
}
void cat68701_outw(unsigned short b, unsigned long port)
{
*(volatile unsigned short*)PORT2ADDR(port) = b;
}
void cat68701_outl(unsigned int b, unsigned long port)
{
*(volatile unsigned long*)PORT2ADDR(port) = b;
}
void cat68701_outb_p(unsigned char b, unsigned long port)
{
*(volatile unsigned char*)PORT2ADDR(port) = b;
delay();
}
void cat68701_outw_p(unsigned short b, unsigned long port)
{
*(volatile unsigned short*)PORT2ADDR(port) = b;
delay();
}
void cat68701_outl_p(unsigned int b, unsigned long port)
{
*(volatile unsigned long*)PORT2ADDR(port) = b;
delay();
}
void cat68701_outsb(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned char *buf=buffer;
while(count--) outb(*buf++, port);
}
void cat68701_outsw(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned short *buf=buffer;
while(count--) outw(*buf++, port);
#ifdef SH3_PCMCIA_BUG_WORKAROUND
ctrl_inb (DUMMY_READ_AREA6);
#endif
}
void cat68701_outsl(unsigned long port, const void *buffer, unsigned long count)
{
const unsigned long *buf=buffer;
while(count--) outl(*buf++, port);
#ifdef SH3_PCMCIA_BUG_WORKAROUND
ctrl_inb (DUMMY_READ_AREA6);
#endif
}
unsigned char cat68701_readb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
unsigned short cat68701_readw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
unsigned int cat68701_readl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
void cat68701_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
void cat68701_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
void cat68701_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
void * cat68701_ioremap(unsigned long offset, unsigned long size)
{
return (void *) P2SEGADDR(offset);
}
EXPORT_SYMBOL(cat68701_ioremap);
void cat68701_iounmap(void *addr)
{
}
EXPORT_SYMBOL(cat68701_iounmap);
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)*/
}
/*
* linux/arch/sh/boards/cat68701/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
* 2001 Yutaro Ebihara (ebihara@si-linux.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 A-ONE corp. CAT-68701 SH7708 board
*/
#include <linux/config.h>
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/cat68701/io.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_cat68701 __initmv = {
.mv_nr_irqs = 32,
.mv_inb = cat68701_inb,
.mv_inw = cat68701_inw,
.mv_inl = cat68701_inl,
.mv_outb = cat68701_outb,
.mv_outw = cat68701_outw,
.mv_outl = cat68701_outl,
.mv_inb_p = cat68701_inb_p,
.mv_inw_p = cat68701_inw,
.mv_inl_p = cat68701_inl,
.mv_outb_p = cat68701_outb_p,
.mv_outw_p = cat68701_outw,
.mv_outl_p = cat68701_outl,
.mv_insb = cat68701_insb,
.mv_insw = cat68701_insw,
.mv_insl = cat68701_insl,
.mv_outsb = cat68701_outsb,
.mv_outsw = cat68701_outsw,
.mv_outsl = cat68701_outsl,
.mv_readb = cat68701_readb,
.mv_readw = cat68701_readw,
.mv_readl = cat68701_readl,
.mv_writeb = cat68701_writeb,
.mv_writew = cat68701_writew,
.mv_writel = cat68701_writel,
.mv_ioremap = cat68701_ioremap,
.mv_iounmap = cat68701_iounmap,
.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)
......@@ -14,21 +14,18 @@
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mach/io.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
const char *get_system_type(void)
{
return "CAT-68701";
}
void platform_setup()
{
/* dummy read erea5 (CS8900A) */
}
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
void heartbeat_cat68701()
{
static unsigned int cnt = 0, period = 0 , bit = 0;
......@@ -49,3 +46,41 @@ void heartbeat_cat68701()
}
#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) */
}
......@@ -6,5 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
obj-y := setup.o irq.o
#define IDE_OFFSET 0xA4000000UL
#define ISA_OFFSET 0xA4A00000UL
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;
}
/* $Id: mach.c,v 1.1.2.4.2.1 2003/01/10 17:26:32 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
*
* Copyright (C) 2000 Niibe Yutaka
*
* CqREEK IDE/ISA Bridge Support.
*
*/
#include <asm/rtc.h>
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/cqreek/cqreek.h>
/*
* 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_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw_p,
.mv_inl_p = generic_inl_p,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw_p,
.mv_outl_p = generic_outl_p,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_init_irq = init_cqreek_IRQ,
.mv_isa_port2addr = cqreek_port2addr,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
};
ALIAS_MV(cqreek)
/* $Id: setup.c,v 1.1.2.5 2002/03/02 21:57:07 lethal Exp $
/* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $
*
* arch/sh/kernel/setup_cqreek.c
*
......@@ -13,17 +13,49 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/cqreek/cqreek.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
*/
......
/*
* linux/arch/sh/kernel/mach_dmida.c
* linux/arch/sh/boards/dmida/mach.c
*
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
......@@ -30,8 +30,6 @@
*/
struct sh_machine_vector mv_dmida __initmv = {
.mv_name = "DMIDA",
.mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
.mv_inb = hd64465_inb,
......@@ -55,17 +53,7 @@ struct sh_machine_vector mv_dmida __initmv = {
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64465_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(dmida)
......@@ -6,7 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o rtc.o
obj-$(CONFIG_PCI) += pci.o
obj-y := setup.o irq.o rtc.o
/*
* $Id: io.c,v 1.1.2.1 2002/01/19 23:54:19 mrbrown Exp $
* I/O routines for SEGA Dreamcast
*/
#include <asm/io.h>
#include <asm/machvec.h>
unsigned long dreamcast_isa_port2addr(unsigned long offset)
{
return offset + 0xa0000000;
}
/*
* $Id: mach.c,v 1.4 2003/05/20 03:04:36 lethal Exp $
* SEGA Dreamcast machine vector
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/time.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/io_generic.h>
#include <asm/dreamcast/io.h>
#include <asm/irq.h>
void __init dreamcast_pcibios_init(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_dreamcast __initmv = {
.mv_nr_irqs = NR_IRQS,
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw,
.mv_inl_p = generic_inl,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw,
.mv_outl_p = generic_outl,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = dreamcast_isa_port2addr,
.mv_irq_demux = systemasic_irq_demux,
};
ALIAS_MV(dreamcast)
/* arch/sh/kernel/setup_dc.c
/*
* arch/sh/boards/dreamcast/setup.c
*
* Hardware support for the Sega Dreamcast.
*
* Copyright (c) 2001, 2002 M. R. Brown <mrbrown@linuxdc.org>
* Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org>
* Copyright (c) 2002, 2003 Paul Mundt <lethal@linux-sh.org>
*
* This file is part of the LinuxDC project (www.linuxdc.org)
*
......@@ -23,21 +24,27 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dreamcast/sysasic.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);
const char *get_system_type(void)
{
return "Sega Dreamcast";
}
#ifdef CONFIG_PCI
extern int gapspci_init(void);
#endif
struct sh_machine_vector mv_dreamcast __initmv = {
.mv_nr_irqs = NR_IRQS,
.mv_irq_demux = systemasic_irq_demux,
};
ALIAS_MV(dreamcast)
int __init platform_setup(void)
{
......@@ -49,6 +56,8 @@ int __init platform_setup(void)
/* Acknowledge any previous events */
/* XXX */
__set_io_port_base(0xa0000000);
/* Assign all virtual IRQs to the System ASIC int. handler */
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
irq_desc[i].handler = &systemasic_int;
......
......@@ -6,5 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
obj-y := setup.o io.o irq.o
/*
* linux/arch/sh/kernel/mach_ec3104.c
* EC3104 companion chip support
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
*
*/
/* EC3104 note:
* This code was written without any documentation about the EC3104 chip. While
* I hope I got most of the basic functionality right, the register names I use
* are most likely completely different from those in the chip documentation.
*
* If you have any further information about the EC3104, please tell me
* (prumpf@tux.org).
*/
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/io.h>
#include <asm/irq.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_ec3104 __initmv = {
.mv_name = "EC3104",
.mv_nr_irqs = 96,
.mv_inb = ec3104_inb,
.mv_inw = ec3104_inw,
.mv_inl = ec3104_inl,
.mv_outb = ec3104_outb,
.mv_outw = ec3104_outw,
.mv_outl = ec3104_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw,
.mv_inl_p = generic_inl,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw,
.mv_outl_p = generic_outl,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = ec3104_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(ec3104)
......@@ -24,16 +24,38 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ec3104/ec3104.h>
#include <asm/machvec.h>
#include <asm/mach/ec3104.h>
int __init setup_ec3104(void)
const char *get_system_type(void)
{
return "EC3104";
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_ec3104 __initmv = {
.mv_nr_irqs = 96,
.mv_inb = ec3104_inb,
.mv_inw = ec3104_inw,
.mv_inl = ec3104_inl,
.mv_outb = ec3104_outb,
.mv_outw = ec3104_outw,
.mv_outl = ec3104_outl,
.mv_irq_demux = ec3104_irq_demux,
};
ALIAS_MV(ec3104)
int __init platform_setup(void)
{
char str[8];
int i;
if (!MACH_EC3104)
printk("!MACH_EC3104\n");
if (0)
return 0;
......@@ -54,4 +76,3 @@ int __init setup_ec3104(void)
return 0;
}
module_init(setup_ec3104);
/*
* linux/arch/sh/stboards/mach.c
* linux/arch/sh/boards/harp/mach.c
*
* Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
*
......@@ -14,7 +14,7 @@
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/hd64465.h/io.h>
#include <asm/hd64465/io.h>
#include <asm/hd64465/hd64465.h>
void setup_harp(void);
......@@ -49,16 +49,6 @@ struct sh_machine_vector mv_harp __initmv = {
.mv_outsw = hd64465_outsw,
.mv_outsl = hd64465_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = hd64465_isa_port2addr,
#ifdef CONFIG_PCI
......
......@@ -24,8 +24,6 @@
*/
struct sh_machine_vector mv_hp620 __initmv = {
.mv_name = "hp620",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
......@@ -49,16 +47,6 @@ struct sh_machine_vector mv_hp620 __initmv = {
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(hp620)
......@@ -20,8 +20,6 @@
#include <asm/irq.h>
struct sh_machine_vector mv_hp680 __initmv = {
.mv_name = "hp680",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
......@@ -45,16 +43,6 @@ struct sh_machine_vector mv_hp680 __initmv = {
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(hp680)
......@@ -20,8 +20,6 @@
#include <asm/irq.h>
struct sh_machine_vector mv_hp690 __initmv = {
.mv_name = "hp690",
.mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
.mv_inb = hd64461_inb,
......@@ -45,16 +43,6 @@ struct sh_machine_vector mv_hp690 __initmv = {
.mv_outsw = hd64461_outsw,
.mv_outsl = hd64461_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_irq_demux = hd64461_irq_demux,
.mv_rtc_gettimeofday = sh_rtc_gettimeofday,
.mv_rtc_settimeofday = sh_rtc_settimeofday,
};
ALIAS_MV(hp690)
......@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o rtc.o led.o
obj-y := setup.o rtc.o led.o
obj-$(CONFIG_PCI) += pci.o
/*
* linux/arch/sh/kernel/io_mpc1211.c
*
* Copyright (C) 2001 Saito.K & Jeanne
*
* I/O routine for Interface MPC-1211.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/mpc1211/pci.h>
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
static inline unsigned long port2adr(unsigned long port)
{
return port + PA_PCI_IO;
}
unsigned char mpc1211_inb(unsigned long port)
{
return *(__u8 *)port2adr(port);
}
unsigned short mpc1211_inw(unsigned long port)
{
return *(__u16 *)port2adr(port);
}
unsigned int mpc1211_inl(unsigned long port)
{
return *(__u32 *)port2adr(port);
}
void mpc1211_outb(unsigned char value, unsigned long port)
{
*(__u8 *)port2adr(port) = value;
}
void mpc1211_outw(unsigned short value, unsigned long port)
{
*(__u16 *)port2adr(port) = value;
}
void mpc1211_outl(unsigned int value, unsigned long port)
{
*(__u32 *)port2adr(port) = value;
}
unsigned char mpc1211_inb_p(unsigned long port)
{
unsigned char v;
v = *(__u8 *)port2adr(port);
delay();
return v;
}
void mpc1211_outb_p(unsigned char value, unsigned long port)
{
*(__u8 *)port2adr(port) = value;
delay();
}
void mpc1211_insb(unsigned long port, void *addr, unsigned long count)
{
volatile __u8 *p = (__u8 *)port2adr(port);
while (count--) {
*((__u8 *)addr)++ = *p;
}
}
void mpc1211_insw(unsigned long port, void *addr, unsigned long count)
{
volatile __u16 *p = (__u16 *)port2adr(port);
while (count--) {
*((__u16 *)addr)++ = *p;
}
}
void mpc1211_insl(unsigned long port, void *addr, unsigned long count)
{
volatile __u32 *p = (__u32 *)port2adr(port);
while (count--) {
*((__u32 *)addr)++ = *p;
}
}
void mpc1211_outsb(unsigned long port, const void *addr, unsigned long count)
{
volatile __u8 *p = (__u8 *)port2adr(port);
while (count--) {
*p = *((__u8 *)addr)++;
}
}
void mpc1211_outsw(unsigned long port, const void *addr, unsigned long count)
{
volatile __u16 *p = (__u16 *)port2adr(port);
while (count--) {
*p = *((__u16 *)addr)++;
}
}
void mpc1211_outsl(unsigned long port, const void *addr, unsigned long count)
{
volatile __u32 *p = (__u32 *)port2adr(port);
while (count--) {
*p = *((__u32 *)addr)++;
}
}
unsigned char mpc1211_readb(unsigned long addr)
{
return *(volatile unsigned char *)addr;
}
unsigned short mpc1211_readw(unsigned long addr)
{
return *(volatile unsigned short *)addr;
}
unsigned int mpc1211_readl(unsigned long addr)
{
return *(volatile unsigned int *)addr;
}
void mpc1211_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char *)addr = b;
}
void mpc1211_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short *)addr = b;
}
void mpc1211_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned int *)addr = b;
}
unsigned long mpc1211_isa_port2addr(unsigned long offset)
{
return port2adr(offset);
}
/*
* linux/arch/sh/kernel/mach_mpc1211.c
*
* Copyright (C) 2001 Saito.K & Jeanne
*
* Machine vector for the Interface MPC-1211
*/
#include <linux/config.h>
#include <linux/init.h>
#include <asm/machvec.h>
#include <asm/rtc.h>
#include <asm/machvec_init.h>
#include <asm/mpc1211/io.h>
void heartbeat_mpc1211(void);
void setup_mpc1211(void);
void init_mpc1211_IRQ(void);
/*
* The Machine Vector
*/
struct sh_machine_vector mv_mpc1211 __initmv = {
.mv_name = "MPC-1211",
.mv_nr_irqs = 48,
.mv_inb = mpc1211_inb,
.mv_inw = mpc1211_inw,
.mv_inl = mpc1211_inl,
.mv_outb = mpc1211_outb,
.mv_outw = mpc1211_outw,
.mv_outl = mpc1211_outl,
.mv_inb_p = mpc1211_inb_p,
.mv_inw_p = mpc1211_inw,
.mv_inl_p = mpc1211_inl,
.mv_outb_p = mpc1211_outb_p,
.mv_outw_p = mpc1211_outw,
.mv_outl_p = mpc1211_outl,
.mv_insb = mpc1211_insb,
.mv_insw = mpc1211_insw,
.mv_insl = mpc1211_insl,
.mv_outsb = mpc1211_outsb,
.mv_outsw = mpc1211_outsw,
.mv_outsl = mpc1211_outsl,
.mv_readb = mpc1211_readb,
.mv_readw = mpc1211_readw,
.mv_readl = mpc1211_readl,
.mv_writeb = mpc1211_writeb,
.mv_writew = mpc1211_writew,
.mv_writel = mpc1211_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = mpc1211_isa_port2addr,
.mv_irq_demux = mpc1211_irq_demux,
.mv_init_arch = setup_mpc1211,
.mv_init_irq = init_mpc1211_IRQ,
// mv_init_pci = mpc1211_pcibios_init,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_mpc1211,
#endif
.mv_rtc_gettimeofday = mpc1211_rtc_gettimeofday,
.mv_rtc_settimeofday = mpc1211_rtc_settimeofday,
};
ALIAS_MV(mpc1211)
......@@ -180,7 +180,8 @@ static void __devinit quirk_ali_ide_ports(struct pci_dev *dev)
/* Add future fixups here... */
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL,
PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports },
{ 0 }
};
......@@ -273,8 +274,6 @@ static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}
void __init pcibios_fixup(void) { /* Do nothing. */ }
void __init pcibios_fixup_irqs(void)
{
pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq);
......
......@@ -143,3 +143,10 @@ int mpc1211_rtc_settimeofday(const struct timeval *tv)
return set_rtc_mmss(nowtime);
}
void mpc1211_time_init(void)
{
rtc_get_time = mpc1211_rtc_gettimeofday;
rtc_set_time = mpc1211_rtc_settimeofday;
}
......@@ -13,7 +13,9 @@
#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>
......@@ -54,10 +56,6 @@ const char *get_system_type(void)
return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
}
void platform_setup(void)
{
}
static void __init pci_write_config(unsigned long busNo,
unsigned long devNo,
unsigned long fncNo,
......@@ -265,15 +263,16 @@ void __init init_mpc1211_IRQ(void)
static void delay (void)
{
volatile unsigned short tmp;
tmp = *(volatile unsigned short *) 0xa0000000;
volatile unsigned short tmp;
tmp = *(volatile unsigned short *) 0xa0000000;
}
static void delay1000 (void)
{
int i;
for (i=0; i<1000; i++)
delay ();
int i;
for (i=0; i<1000; i++)
delay ();
}
static int put_smb_blk(unsigned char *p, int address, int command, int no)
......@@ -316,21 +315,46 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no)
return 0;
}
void __init setup_mpc1211(void)
/*
* 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)
{
unsigned char spd_buf[128];
pci_write_config(0,0,0,0x54, 0xb0b00000);
retry:
outb(ALI15X3_ABORT, SMBHSTCNT);
spd_buf[0] = 0x0c;
spd_buf[1] = 0x43;
spd_buf[2] = 0x7f;
spd_buf[3] = 0x03;
spd_buf[4] = 0x00;
spd_buf[5] = 0x03;
spd_buf[6] = 0x00;
if (put_smb_blk(spd_buf, 0x69, 0, 7) < 0) {
goto retry;
}
unsigned char spd_buf[128];
__set_io_port_base(PA_PCI_IO);
pci_write_config(0,0,0,0x54, 0xb0b00000);
do {
outb(ALI15X3_ABORT, SMBHSTCNT);
spd_buf[0] = 0x0c;
spd_buf[1] = 0x43;
spd_buf[2] = 0x7f;
spd_buf[3] = 0x03;
spd_buf[4] = 0x00;
spd_buf[5] = 0x03;
spd_buf[6] = 0x00;
} while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0);
board_time_init = mpc1211_time_init;
return 0;
}
......@@ -51,18 +51,6 @@ struct sh_machine_vector mv_od __initmv = {
.mv_outsw = od_outsw,
.mv_outsl = od_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = generic_isa_port2addr,
#ifdef CONFIG_PCI
.mv_init_irq = init_overdrive_irq,
#endif
......
......@@ -6,7 +6,7 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o irq.o
obj-y := setup.o io.o irq.o
obj-$(CONFIG_SMP) += smp.o
......@@ -7,8 +7,7 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/saturn/saturn.h>
#include <asm/saturn/irq.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <asm/io.h>
......@@ -65,7 +64,7 @@ static inline void unmask_saturn_irq(unsigned int irq_nr)
mask = ctrl_inl(SATURN_IMR);
mask &= ~saturn_irq_mask(irq_nr);
ctrl_outl(SATURN_IMR);
ctrl_outl(mask, SATURN_IMR);
}
static void disable_saturn_irq(unsigned int irq_nr)
......@@ -85,7 +84,7 @@ static void mask_and_ack_saturn_irq(unsigned int irq_nr)
static void end_saturn_irq(unsigned int irq_nr)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
unmask_saturn_irq(irq_nr);
}
......
/*
* arch/sh/boards/saturn/mach.c
*
* machvec definitions for the Sega Saturn.
*
* Copyright (C) 2002 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#include <asm/saturn/io.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_saturn __initmv = {
.mv_nr_irqs = 80, /* Fix this later */
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw_p,
.mv_inl_p = generic_inl_p,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw_p,
.mv_outl_p = generic_outl_p,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_isa_port2addr = saturn_isa_port2addr,
.mv_irq_demux = saturn_irq_demux,
.mv_ioremap = saturn_ioremap,
.mv_iounmap = saturn_iounmap,
};
ALIAS_MV(saturn)
......@@ -10,11 +10,32 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mach/io.h>
extern int saturn_irq_demux(int irq_nr);
const char *get_system_type(void)
{
return "Sega Saturn";
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_saturn __initmv = {
.mv_nr_irqs = 80, /* Fix this later */
.mv_isa_port2addr = saturn_isa_port2addr,
.mv_irq_demux = saturn_irq_demux,
.mv_ioremap = saturn_ioremap,
.mv_iounmap = saturn_iounmap,
};
ALIAS_MV(saturn)
int __init platform_setup(void)
{
return 0;
......
......@@ -34,7 +34,7 @@ unsigned int __smp_probe_cpus(void)
* addition to which, we treat them as write-only, since
* reading from them will return undefined data.
*/
static inline void smpc_slave_off(unsigned int cpu)
static inline void smpc_slave_stop(unsigned int cpu)
{
smpc_barrier();
ctrl_outb(1, SMPC_STATUS);
......@@ -43,7 +43,7 @@ static inline void smpc_slave_off(unsigned int cpu)
smpc_barrier();
}
static inline void smpc_slave_on(unsigned int cpu)
static inline void smpc_slave_start(unsigned int cpu)
{
ctrl_outb(1, SMPC_STATUS);
ctrl_outb(SMPC_CMD_SSHON, SMPC_COMMAND);
......
/* $Id: io.c,v 1.1.2.2 2002/01/20 05:03:25 mrbrown Exp $
/* $Id: io.c,v 1.4 2003/08/03 03:05:10 lethal Exp $
*
* linux/arch/sh/kernel/io_se.c
*
......@@ -189,36 +189,6 @@ void se_outsl(unsigned long port, const void *addr, unsigned long count)
maybebadio(outsw, port);
}
unsigned char se_readb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
unsigned short se_readw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
unsigned int se_readl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
void se_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
void se_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
void se_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
/* Map ISA bus address to the real address. Only for PCMCIA. */
/* ISA page descriptor. */
......
......@@ -56,16 +56,6 @@ struct sh_machine_vector mv_se __initmv = {
.mv_outsw = se_outsw,
.mv_outsl = se_outsl,
.mv_readb = se_readb,
.mv_readw = se_readw,
.mv_readl = se_readl,
.mv_writeb = se_writeb,
.mv_writew = se_writew,
.mv_writel = se_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = se_isa_port2addr,
.mv_init_irq = init_se_IRQ,
......
......@@ -201,76 +201,16 @@ void sh7751se_outl(unsigned int value, unsigned long port)
maybebadio(outl, port);
}
void sh7751se_insb(unsigned long port, void *addr, unsigned long count)
{
unsigned char *p = addr;
while (count--) *p++ = sh7751se_inb(port);
}
void sh7751se_insw(unsigned long port, void *addr, unsigned long count)
{
unsigned short *p = addr;
while (count--) *p++ = sh7751se_inw(port);
}
void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
{
maybebadio(insl, port);
}
void sh7751se_outsb(unsigned long port, const void *addr, unsigned long count)
{
unsigned char *p = (unsigned char*)addr;
while (count--) sh7751se_outb(*p++, port);
}
void sh7751se_outsw(unsigned long port, const void *addr, unsigned long count)
{
unsigned short *p = (unsigned short*)addr;
while (count--) sh7751se_outw(*p++, port);
}
void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
{
maybebadio(outsw, port);
}
/* For read/write calls, just copy generic (pass-thru); PCIMBR is */
/* already set up. For a larger memory space, these would need to */
/* reset PCIMBR as needed on a per-call basis... */
unsigned char sh7751se_readb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
unsigned short sh7751se_readw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
unsigned int sh7751se_readl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
void sh7751se_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
void sh7751se_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
void sh7751se_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
/* Map ISA bus address to the real address. Only for PCMCIA. */
/* ISA page descriptor. */
......
......@@ -42,23 +42,9 @@ struct sh_machine_vector mv_7751se __initmv = {
.mv_outw_p = sh7751se_outw,
.mv_outl_p = sh7751se_outl,
.mv_insb = sh7751se_insb,
.mv_insw = sh7751se_insw,
.mv_insl = sh7751se_insl,
.mv_outsb = sh7751se_outsb,
.mv_outsw = sh7751se_outsw,
.mv_outsl = sh7751se_outsl,
.mv_readb = sh7751se_readb,
.mv_readw = sh7751se_readw,
.mv_readl = sh7751se_readl,
.mv_writeb = sh7751se_writeb,
.mv_writew = sh7751se_writew,
.mv_writel = sh7751se_writel,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
.mv_isa_port2addr = sh7751se_isa_port2addr,
.mv_init_irq = init_7751se_IRQ,
......
......@@ -95,12 +95,11 @@ int __init pcibios_init_platform(void)
/*
* Set the MBR so PCI address is one-to-one with window,
* meaning all calls go straight through... use ifdef to
* meaning all calls go straight through... use BUG_ON to
* catch erroneous assumption.
*/
#if PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE
#error One-to-one assumption for PCI memory mapping is wrong!?!?!?
#endif
BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
/* Set IOBR for window containing area specified in pci.h */
......@@ -125,3 +124,25 @@ int __init pcibios_map_platform_irq(u8 slot, u8 pin)
return -1;
}
}
static struct resource sh7751_io_resource = {
.name = "SH7751 IO",
.start = SH7751_PCI_IO_BASE,
.end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
.flags = IORESOURCE_IO
};
static struct resource sh7751_mem_resource = {
.name = "SH7751 mem",
.start = SH7751_PCI_MEMORY_BASE,
.end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
.flags = IORESOURCE_MEM
};
extern struct pci_ops sh7751_pci_ops;
struct pci_channel board_pci_channels[] = {
{ &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ NULL, NULL, NULL, 0, 0 },
};
......@@ -6,5 +6,5 @@
# unless it's something special (ie not a .c file).
#
obj-y := mach.o setup.o io.o
obj-y := setup.o
/*
* I/O routine for SH-2000
*/
#include <linux/config.h>
#include <asm/io.h>
#include <asm/machvec.h>
#define IDE_OFFSET 0xb6200000
#define NIC_OFFSET 0xb6000000
#define EXTBUS_OFFSET 0xba000000
unsigned long sh2000_isa_port2addr(unsigned long offset)
{
if((offset & ~7) == 0x1f0 || offset == 0x3f6)
return IDE_OFFSET + offset;
else if((offset & ~0x1f) == 0x300)
return NIC_OFFSET + offset;
return EXTBUS_OFFSET + offset;
}
/*
* linux/arch/sh/boards/sh2000/mach.c
*
* Original copyright message:
* Copyright (C) 2001 SUGIOKA Tochinobu
*
* Split into mach.c from setup.c by M. R. Brown <mrbrown@0xd6.org>
*/
#include <asm/io.h>
#include <asm/io_generic.h>
#include <asm/machvec.h>
#include <asm/machvec_init.h>
#include <asm/rtc.h>
#include <asm/sh2000/sh2000.h>
/*
* The Machine Vector
*/
struct sh_machine_vector mv_sh2000 __initmv = {
.mv_nr_irqs = 80,
.mv_inb = generic_inb,
.mv_inw = generic_inw,
.mv_inl = generic_inl,
.mv_outb = generic_outb,
.mv_outw = generic_outw,
.mv_outl = generic_outl,
.mv_inb_p = generic_inb_p,
.mv_inw_p = generic_inw_p,
.mv_inl_p = generic_inl_p,
.mv_outb_p = generic_outb_p,
.mv_outw_p = generic_outw_p,
.mv_outl_p = generic_outl_p,
.mv_insb = generic_insb,
.mv_insw = generic_insw,
.mv_insl = generic_insl,
.mv_outsb = generic_outsb,
.mv_outsw = generic_outsw,
.mv_outsl = generic_outsl,
.mv_readb = generic_readb,
.mv_readw = generic_readw,
.mv_readl = generic_readl,
.mv_writeb = generic_writeb,
.mv_writew = generic_writew,
.mv_writel = generic_writel,
.mv_isa_port2addr = sh2000_isa_port2addr,
.mv_ioremap = generic_ioremap,
.mv_iounmap = generic_iounmap,
};
ALIAS_MV(sh2000)
......@@ -12,6 +12,8 @@
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mach/sh2000.h>
#define CF_CIS_BASE 0xb4200000
......@@ -20,11 +22,34 @@
#define PORT_ICR1 0xa4000010
#define PORT_IRR0 0xa4000004
#define IDE_OFFSET 0xb6200000
#define NIC_OFFSET 0xb6000000
#define EXTBUS_OFFSET 0xba000000
const char *get_system_type(void)
{
return "sh2000";
}
static unsigned long sh2000_isa_port2addr(unsigned long offset)
{
if((offset & ~7) == 0x1f0 || offset == 0x3f6)
return IDE_OFFSET + offset;
else if((offset & ~0x1f) == 0x300)
return NIC_OFFSET + offset;
return EXTBUS_OFFSET + offset;
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_sh2000 __initmv = {
.mv_nr_irqs = 80,
.mv_isa_port2addr = sh2000_isa_port2addr,
};
ALIAS_MV(sh2000)
/*
* Initialize the board
*/
......
#
# Makefile for the SnapGear 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 rtc.o
/*
* linux/arch/sh/kernel/io_7751se.c
*
* Copyright (C) 2002 David McCullough <davidm@snapgear.com>
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
* I/O routine for Hitachi 7751 SolutionEngine.
*
* Initial version only to support LAN access; some
* placeholder code from io_se.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/addrspace.h>
#include <asm/pci.h>
#include "../../drivers/pci/pci-sh7751.h"
#ifdef CONFIG_SH_SECUREEDGE5410
unsigned short secureedge5410_ioport;
#endif
/*
* The SnapGear uses the built-in PCI controller (PCIC)
* of the 7751 processor
*/
#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
#define PCI_IO_AREA SH7751_PCI_IO_BASE
#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
#define maybebadio(name,port) \
printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
#name, (port), (__u32) __builtin_return_address(0))
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
static inline volatile __u16 *port2adr(unsigned int port)
{
#if 0
if (port >= 0x2000)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
#endif
maybebadio(name,(unsigned long)port);
return (volatile __u16*)port;
}
/* In case someone configures the kernel w/o PCI support: in that */
/* scenario, don't ever bother to check for PCI-window addresses */
/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
#if defined(CONFIG_PCI)
#define CHECK_SH7751_PCIIO(port) \
((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
#else
#define CHECK_SH7751_PCIIO(port) (0)
#endif
/*
* 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.
*/
unsigned char snapgear_inb(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned char *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned char *)PCI_IOMAP(port);
else
return (*port2adr(port))&0xff;
}
unsigned char snapgear_inb_p(unsigned long port)
{
unsigned char v;
if (PXSEG(port))
v = *(volatile unsigned char *)port;
else if (CHECK_SH7751_PCIIO(port))
v = *(volatile unsigned char *)PCI_IOMAP(port);
else
v = (*port2adr(port))&0xff;
delay();
return v;
}
unsigned short snapgear_inw(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned short *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned short *)PCI_IOMAP(port);
else if (port >= 0x2000)
return *port2adr(port);
else
maybebadio(inw, port);
return 0;
}
unsigned int snapgear_inl(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned long *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned int *)PCI_IOMAP(port);
else if (port >= 0x2000)
return *port2adr(port);
else
maybebadio(inl, port);
return 0;
}
void snapgear_outb(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned char*)PCI_IOMAP(port)) = value;
else
*(port2adr(port)) = value;
}
void snapgear_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned char*)PCI_IOMAP(port)) = value;
else
*(port2adr(port)) = value;
delay();
}
void snapgear_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned short *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned short *)PCI_IOMAP(port)) = value;
else if (port >= 0x2000)
*port2adr(port) = value;
else
maybebadio(outw, port);
}
void snapgear_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned long *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned long*)PCI_IOMAP(port)) = value;
else
maybebadio(outl, port);
}
void snapgear_insl(unsigned long port, void *addr, unsigned long count)
{
maybebadio(insl, port);
}
void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
{
maybebadio(outsw, port);
}
/* Map ISA bus address to the real address. Only for PCMCIA. */
/* ISA page descriptor. */
static __u32 sh_isa_memmap[256];
#if 0
static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
{
int idx;
if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
return -1;
idx = start >> 12;
sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
#if 0
printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
start, length, offset, idx, sh_isa_memmap[idx]);
#endif
return 0;
}
#endif
unsigned long snapgear_isa_port2addr(unsigned long offset)
{
int idx;
idx = (offset >> 12) & 0xff;
offset &= 0xfff;
return sh_isa_memmap[idx] + offset;
}
This diff is collapsed.
/****************************************************************************/
/*
* linux/arch/sh/boards/snapgear/setup.c
*
* Copyright (C) 2002 David McCullough <davidm@snapgear.com>
* Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
*
* Based on files with the following comments:
*
* Copyright (C) 2000 Kazumoto Kojima
*
* Modified for 7751 Solution Engine by
* Ian da Silva and Jeremy Siegel, 2001.
*/
/****************************************************************************/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/machvec.h>
#include <asm/mach/io.h>
#include <asm/irq.h>
#include <asm/io.h>
extern void (*board_time_init)(void);
extern void secureedge5410_rtc_init(void);
extern void pcibios_init(void);
/****************************************************************************/
/*
* EraseConfig handling functions
*/
static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000;
printk("SnapGear: erase switch interrupt!\n");
return IRQ_HANDLED;
}
static int __init eraseconfig_init(void)
{
printk("SnapGear: EraseConfig init\n");
/* Setup "EraseConfig" switch on external IRQ 0 */
if (request_irq(IRL0_IRQ, eraseconfig_interrupt, SA_INTERRUPT,
"Erase Config", NULL))
printk("SnapGear: failed to register IRQ%d for Reset witch\n",
IRL0_IRQ);
else
printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
IRL0_IRQ);
return(0);
}
module_init(eraseconfig_init);
/****************************************************************************/
/*
* Initialize IRQ setting
*
* IRL0 = erase switch
* IRL1 = eth0
* IRL2 = eth1
* IRL3 = crypto
*/
static void __init init_snapgear_IRQ(void)
{
/* enable individual interrupt mode for externals */
ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
printk("Setup SnapGear IRQ/IPR ...\n");
make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
}
/****************************************************************************/
/*
* Fast poll interrupt simulator.
*/
/*
* Leave all of the fast timer/fast poll stuff commented out for now, since
* it's not clear whether it actually works or not. Since it wasn't being used
* at all in 2.4, we'll assume it's not sane for 2.6 either.. -- PFM
*/
#if 0
#define FAST_POLL 1000
//#define FAST_POLL_INTR
#define FASTTIMER_IRQ 17
#define FASTTIMER_IPR_ADDR INTC_IPRA
#define FASTTIMER_IPR_POS 2
#define FASTTIMER_PRIORITY 3
#ifdef FAST_POLL_INTR
#define TMU1_TCR_INIT 0x0020
#else
#define TMU1_TCR_INIT 0
#endif
#define TMU_TSTR_INIT 1
#define TMU1_TCR_CALIB 0x0000
#define TMU_TOCR 0xffd80000 /* Byte access */
#define TMU_TSTR 0xffd80004 /* Byte access */
#define TMU1_TCOR 0xffd80014 /* Long access */
#define TMU1_TCNT 0xffd80018 /* Long access */
#define TMU1_TCR 0xffd8001c /* Word access */
#ifdef FAST_POLL_INTR
static void fast_timer_irq(int irq, void *dev_instance, struct pt_regs *regs)
{
unsigned long timer_status;
timer_status = ctrl_inw(TMU1_TCR);
timer_status &= ~0x100;
ctrl_outw(timer_status, TMU1_TCR);
}
#endif
/*
* return the current ticks on the fast timer
*/
unsigned long fast_timer_count(void)
{
return(ctrl_inl(TMU1_TCNT));
}
/*
* setup a fast timer for profiling etc etc
*/
static void setup_fast_timer()
{
unsigned long interval;
#ifdef FAST_POLL_INTR
interval = (current_cpu_data.module_clock/4 + FAST_POLL/2) / FAST_POLL;
make_ipr_irq(FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS,
FASTTIMER_PRIORITY);
printk("SnapGear: %dHz fast timer on IRQ %d\n",FAST_POLL,FASTTIMER_IRQ);
if (request_irq(FASTTIMER_IRQ, fast_timer_irq, 0, "SnapGear fast timer",
NULL) != 0)
printk("%s(%d): request_irq() failed?\n", __FILE__, __LINE__);
#else
printk("SnapGear: fast timer running\n",FAST_POLL,FASTTIMER_IRQ);
interval = 0xffffffff;
#endif
ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */
ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
ctrl_outl(interval, TMU1_TCOR);
ctrl_outl(interval, TMU1_TCNT);
ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */
printk("Timer count 1 = 0x%x\n", fast_timer_count());
udelay(1000);
printk("Timer count 2 = 0x%x\n", fast_timer_count());
}
#endif
/****************************************************************************/
const char *get_system_type(void)
{
return "SnapGear SecureEdge5410";
}
/*
* The Machine Vector
*/
struct sh_machine_vector mv_snapgear __initmv = {
.mv_nr_irqs = 72,
.mv_inb = snapgear_inb,
.mv_inw = snapgear_inw,
.mv_inl = snapgear_inl,
.mv_outb = snapgear_outb,
.mv_outw = snapgear_outw,
.mv_outl = snapgear_outl,
.mv_inb_p = snapgear_inb_p,
.mv_inw_p = snapgear_inw,
.mv_inl_p = snapgear_inl,
.mv_outb_p = snapgear_outb_p,
.mv_outw_p = snapgear_outw,
.mv_outl_p = snapgear_outl,
.mv_isa_port2addr = snapgear_isa_port2addr,
.mv_init_irq = init_snapgear_IRQ,
};
ALIAS_MV(snapgear)
/*
* Initialize the board
*/
int __init platform_setup(void)
{
board_time_init = secureedge5410_rtc_init;
return 0;
}
#
# Makefile for the SystemH 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 irq.o io.o
# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
# importantly, with the generic sh7751_pcic_init() code. For now, we'll
# just abuse the hell out of kbuild, because we can..
obj-$(CONFIG_PCI) += pci.o
pci-y := ../se/7751/pci.o
/*
* linux/arch/sh/boards/systemh/io.c
*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
* I/O routine for Hitachi 7751 Systemh.
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/systemh/7751systemh.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <linux/pci.h>
#include "../../drivers/pci/pci-sh7751.h"
/*
* The 7751 SystemH Engine uses the built-in PCI controller (PCIC)
* of the 7751 processor, and has a SuperIO accessible on its memory
* bus.
*/
#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
#define PCI_IO_AREA SH7751_PCI_IO_BASE
#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
of smc lan chip*/
#define maybebadio(name,port) \
printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
#name, (port), (__u32) __builtin_return_address(0))
static inline void delay(void)
{
ctrl_inw(0xa0000000);
}
static inline volatile __u16 *
port2adr(unsigned int port)
{
if (port >= 0x2000)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
#if 0
else
return (volatile __u16 *) (PA_SUPERIO + (port << 1));
#endif
maybebadio(name,(unsigned long)port);
return (volatile __u16*)port;
}
/* In case someone configures the kernel w/o PCI support: in that */
/* scenario, don't ever bother to check for PCI-window addresses */
/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
#if defined(CONFIG_PCI)
#define CHECK_SH7751_PCIIO(port) \
((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
#else
#define CHECK_SH7751_PCIIO(port) (0)
#endif
/*
* 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.
*/
unsigned char sh7751systemh_inb(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned char *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned char *)PCI_IOMAP(port);
else if (port <= 0x3F1)
return *(volatile unsigned char *)ETHER_IOMAP(port);
else
return (*port2adr(port))&0xff;
}
unsigned char sh7751systemh_inb_p(unsigned long port)
{
unsigned char v;
if (PXSEG(port))
v = *(volatile unsigned char *)port;
else if (CHECK_SH7751_PCIIO(port))
v = *(volatile unsigned char *)PCI_IOMAP(port);
else if (port <= 0x3F1)
v = *(volatile unsigned char *)ETHER_IOMAP(port);
else
v = (*port2adr(port))&0xff;
delay();
return v;
}
unsigned short sh7751systemh_inw(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned short *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned short *)PCI_IOMAP(port);
else if (port >= 0x2000)
return *port2adr(port);
else if (port <= 0x3F1)
return *(volatile unsigned int *)ETHER_IOMAP(port);
else
maybebadio(inw, port);
return 0;
}
unsigned int sh7751systemh_inl(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned long *)port;
else if (CHECK_SH7751_PCIIO(port))
return *(volatile unsigned int *)PCI_IOMAP(port);
else if (port >= 0x2000)
return *port2adr(port);
else if (port <= 0x3F1)
return *(volatile unsigned int *)ETHER_IOMAP(port);
else
maybebadio(inl, port);
return 0;
}
void sh7751systemh_outb(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned char*)PCI_IOMAP(port)) = value;
else if (port <= 0x3F1)
*(volatile unsigned char *)ETHER_IOMAP(port) = value;
else
*(port2adr(port)) = value;
}
void sh7751systemh_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned char*)PCI_IOMAP(port)) = value;
else if (port <= 0x3F1)
*(volatile unsigned char *)ETHER_IOMAP(port) = value;
else
*(port2adr(port)) = value;
delay();
}
void sh7751systemh_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned short *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned short *)PCI_IOMAP(port)) = value;
else if (port >= 0x2000)
*port2adr(port) = value;
else if (port <= 0x3F1)
*(volatile unsigned short *)ETHER_IOMAP(port) = value;
else
maybebadio(outw, port);
}
void sh7751systemh_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned long *)port = value;
else if (CHECK_SH7751_PCIIO(port))
*((unsigned long*)PCI_IOMAP(port)) = value;
else
maybebadio(outl, port);
}
void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
{
unsigned char *p = addr;
while (count--) *p++ = sh7751systemh_inb(port);
}
void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
{
unsigned short *p = addr;
while (count--) *p++ = sh7751systemh_inw(port);
}
void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
{
maybebadio(insl, port);
}
void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
{
unsigned char *p = (unsigned char*)addr;
while (count--) sh7751systemh_outb(*p++, port);
}
void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
{
unsigned short *p = (unsigned short*)addr;
while (count--) sh7751systemh_outw(*p++, port);
}
void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
{
maybebadio(outsw, port);
}
/* For read/write calls, just copy generic (pass-thru); PCIMBR is */
/* already set up. For a larger memory space, these would need to */
/* reset PCIMBR as needed on a per-call basis... */
unsigned char sh7751systemh_readb(unsigned long addr)
{
return *(volatile unsigned char*)addr;
}
unsigned short sh7751systemh_readw(unsigned long addr)
{
return *(volatile unsigned short*)addr;
}
unsigned int sh7751systemh_readl(unsigned long addr)
{
return *(volatile unsigned long*)addr;
}
void sh7751systemh_writeb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char*)addr = b;
}
void sh7751systemh_writew(unsigned short b, unsigned long addr)
{
*(volatile unsigned short*)addr = b;
}
void sh7751systemh_writel(unsigned int b, unsigned long addr)
{
*(volatile unsigned long*)addr = b;
}
/* Map ISA bus address to the real address. Only for PCMCIA. */
/* ISA page descriptor. */
static __u32 sh_isa_memmap[256];
#if 0
static int
sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
{
int idx;
if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
return -1;
idx = start >> 12;
sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
start, length, offset, idx, sh_isa_memmap[idx]);
return 0;
}
#endif
unsigned long
sh7751systemh_isa_port2addr(unsigned long offset)
{
int idx;
idx = (offset >> 12) & 0xff;
offset &= 0xfff;
return sh_isa_memmap[idx] + offset;
}
This diff is collapsed.
/*
* linux/arch/sh/boards/systemh/setup.c
*
* Copyright (C) 2000 Kazumoto Kojima
* Copyright (C) 2003 Paul Mundt
*
* Hitachi SystemH Support.
*
* Modified for 7751 SystemH by Jonathan Short.
*
* Rewritten for 2.6 by Paul Mundt.
*
* 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/init.h>
#include <asm/mach/7751systemh.h>
#include <asm/mach/io.h>
#include <asm/machvec.h>
extern void make_systemh_irq(unsigned int irq);
const char *get_system_type(void)
{
return "7751 SystemH";
}
/*
* Initialize IRQ setting
*/
void __init init_7751systemh_IRQ(void)
{
/* make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); LAN */
/* make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-4); */
make_systemh_irq(0xb); /* Ethernet interrupt */
}
struct sh_machine_vector mv_7751systemh __initmv = {
.mv_nr_irqs = 72,
.mv_inb = sh7751systemh_inb,
.mv_inw = sh7751systemh_inw,
.mv_inl = sh7751systemh_inl,
.mv_outb = sh7751systemh_outb,
.mv_outw = sh7751systemh_outw,
.mv_outl = sh7751systemh_outl,
.mv_inb_p = sh7751systemh_inb_p,
.mv_inw_p = sh7751systemh_inw,
.mv_inl_p = sh7751systemh_inl,
.mv_outb_p = sh7751systemh_outb_p,
.mv_outw_p = sh7751systemh_outw,
.mv_outl_p = sh7751systemh_outl,
.mv_insb = sh7751systemh_insb,
.mv_insw = sh7751systemh_insw,
.mv_insl = sh7751systemh_insl,
.mv_outsb = sh7751systemh_outsb,
.mv_outsw = sh7751systemh_outsw,
.mv_outsl = sh7751systemh_outsl,
.mv_readb = sh7751systemh_readb,
.mv_readw = sh7751systemh_readw,
.mv_readl = sh7751systemh_readl,
.mv_writeb = sh7751systemh_writeb,
.mv_writew = sh7751systemh_writew,
.mv_writel = sh7751systemh_writel,
.mv_isa_port2addr = sh7751systemh_isa_port2addr,
.mv_init_irq = init_7751systemh_IRQ,
};
ALIAS_MV(7751systemh)
int __init platform_setup(void)
{
return 0;
}
......@@ -16,9 +16,9 @@ endif
#
# IMAGE_OFFSET is the load offset of the compression loader
#
IMAGE_OFFSET = $(shell printf "0x%8x" $$[0x80000000+0x$(CONFIG_MEMORY_START)+0x200000+0x10000])
IMAGE_OFFSET := $(shell printf "0x%8x" $$[0x80000000+$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../vmlinux.lds.s
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds.s
$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
$(call if_changed,ld)
......
This diff is collapsed.
SECTIONS
{
.data : {
input_len = .;
LONG(input_data_end - input_data) input_data = .;
*(.data)
input_data_end = .;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment