Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
new file mode 100644
index 0000000..bd6726c
--- /dev/null
+++ b/arch/sh/drivers/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux SuperH-specific device drivers.
+#
+
+obj-$(CONFIG_PCI)	+= pci/
+obj-$(CONFIG_SH_DMA)	+= dma/
+
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
new file mode 100644
index 0000000..0f15216
--- /dev/null
+++ b/arch/sh/drivers/dma/Kconfig
@@ -0,0 +1,55 @@
+menu "DMA support"
+
+config SH_DMA
+	bool "DMA controller (DMAC) support"
+	help
+	  Selecting this option will provide same API as PC's Direct Memory
+	  Access Controller(8237A) for SuperH DMAC.
+
+	  If unsure, say N.
+
+config NR_ONCHIP_DMA_CHANNELS
+	depends on SH_DMA
+	int "Number of on-chip DMAC channels"
+	default "4"
+	help
+	  This allows you to specify the number of channels that the on-chip
+	  DMAC supports. This will be 4 for SH7750/SH7751 and 8 for the
+	  SH7750R/SH7751R.
+
+config NR_DMA_CHANNELS_BOOL
+	depends on SH_DMA
+	bool "Override default number of maximum DMA channels"
+	help
+	  This allows you to forcibly update the maximum number of supported
+	  DMA channels for a given board. If this is unset, this will default
+	  to the number of channels that the on-chip DMAC has.
+
+config NR_DMA_CHANNELS
+	int "Maximum number of DMA channels"
+	depends on SH_DMA && NR_DMA_CHANNELS_BOOL
+	default NR_ONCHIP_DMA_CHANNELS
+	help
+	  This allows you to specify the maximum number of DMA channels to
+	  support. Setting this to a higher value allows for cascading DMACs
+	  with additional channels.
+
+config DMA_PAGE_OPS
+	bool "Use DMAC for page copy/clear"
+	depends on SH_DMA && BROKEN
+	help
+	  Selecting this option will use a dual-address mode configured channel
+	  in the SH DMAC for copy_page()/clear_page(). Primarily a performance
+	  hack.
+
+config DMA_PAGE_OPS_CHANNEL
+	depends on DMA_PAGE_OPS
+	int "DMA channel for sh memory-manager page copy/clear"
+	default "3"
+	help
+	  This allows the specification of the dual address dma channel,
+	  in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
+	  are dual-address capable.
+
+endmenu
+
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile
new file mode 100644
index 0000000..065d4c9
--- /dev/null
+++ b/arch/sh/drivers/dma/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the SuperH DMA specific kernel interface routines under Linux.
+#
+
+obj-y				+= dma-api.o dma-isa.o
+obj-$(CONFIG_SYSFS)		+= dma-sysfs.o
+obj-$(CONFIG_SH_DMA)		+= dma-sh.o
+obj-$(CONFIG_SH_DREAMCAST)	+= dma-pvr2.o dma-g2.o
+
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c
new file mode 100644
index 0000000..96e3036
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-api.c
@@ -0,0 +1,292 @@
+/*
+ * arch/sh/drivers/dma/dma-api.c
+ *
+ * SuperH-specific DMA management API
+ *
+ * Copyright (C) 2003, 2004  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 <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <asm/dma.h>
+
+DEFINE_SPINLOCK(dma_spin_lock);
+static LIST_HEAD(registered_dmac_list);
+
+/*
+ * A brief note about the reasons for this API as it stands.
+ *
+ * For starters, the old ISA DMA API didn't work for us for a number of
+ * reasons, for one, the vast majority of channels on the SH DMAC are
+ * dual-address mode only, and both the new and the old DMA APIs are after the
+ * concept of managing a DMA buffer, which doesn't overly fit this model very
+ * well. In addition to which, the new API is largely geared at IOMMUs and
+ * GARTs, and doesn't even support the channel notion very well.
+ *
+ * The other thing that's a marginal issue, is the sheer number of random DMA
+ * engines that are present (ie, in boards like the Dreamcast), some of which
+ * cascade off of the SH DMAC, and others do not. As such, there was a real
+ * need for a scalable subsystem that could deal with both single and
+ * dual-address mode usage, in addition to interoperating with cascaded DMACs.
+ *
+ * There really isn't any reason why this needs to be SH specific, though I'm
+ * not aware of too many other processors (with the exception of some MIPS)
+ * that have the same concept of a dual address mode, or any real desire to
+ * actually make use of the DMAC even if such a subsystem were exposed
+ * elsewhere.
+ *
+ * The idea for this was derived from the ARM port, which acted as an excellent
+ * reference when trying to address these issues.
+ *
+ * It should also be noted that the decision to add Yet Another DMA API(tm) to
+ * the kernel wasn't made easily, and was only decided upon after conferring
+ * with jejb with regards to the state of the old and new APIs as they applied
+ * to these circumstances. Philip Blundell was also a great help in figuring
+ * out some single-address mode DMA semantics that were otherwise rather
+ * confusing.
+ */
+
+struct dma_info *get_dma_info(unsigned int chan)
+{
+	struct list_head *pos, *tmp;
+	unsigned int total = 0;
+
+	/*
+	 * Look for each DMAC's range to determine who the owner of
+	 * the channel is.
+	 */
+	list_for_each_safe(pos, tmp, &registered_dmac_list) {
+		struct dma_info *info = list_entry(pos, struct dma_info, list);
+
+		total += info->nr_channels;
+		if (chan > total)
+			continue;
+
+		return info;
+	}
+
+	return NULL;
+}
+
+struct dma_channel *get_dma_channel(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+
+	if (!info)
+		return ERR_PTR(-EINVAL);
+
+	return info->channels + chan;
+}
+
+int get_dma_residue(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	if (info->ops->get_residue)
+		return info->ops->get_residue(channel);
+
+	return 0;
+}
+
+int request_dma(unsigned int chan, const char *dev_id)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	down(&channel->sem);
+
+	if (!info->ops || chan >= MAX_DMA_CHANNELS) {
+		up(&channel->sem);
+		return -EINVAL;
+	}
+
+	atomic_set(&channel->busy, 1);
+
+	strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id));
+
+	up(&channel->sem);
+
+	if (info->ops->request)
+		return info->ops->request(channel);
+
+	return 0;
+}
+
+void free_dma(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	if (info->ops->free)
+		info->ops->free(channel);
+
+	atomic_set(&channel->busy, 0);
+}
+
+void dma_wait_for_completion(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	if (channel->flags & DMA_TEI_CAPABLE) {
+		wait_event(channel->wait_queue,
+			   (info->ops->get_residue(channel) == 0));
+		return;
+	}
+
+	while (info->ops->get_residue(channel))
+		cpu_relax();
+}
+
+void dma_configure_channel(unsigned int chan, unsigned long flags)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	if (info->ops->configure)
+		info->ops->configure(channel, flags);
+}
+
+int dma_xfer(unsigned int chan, unsigned long from,
+	     unsigned long to, size_t size, unsigned int mode)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	channel->sar	= from;
+	channel->dar	= to;
+	channel->count	= size;
+	channel->mode	= mode;
+
+	return info->ops->xfer(channel);
+}
+
+#ifdef CONFIG_PROC_FS
+static int dma_read_proc(char *buf, char **start, off_t off,
+			 int len, int *eof, void *data)
+{
+	struct list_head *pos, *tmp;
+	char *p = buf;
+
+	if (list_empty(&registered_dmac_list))
+		return 0;
+
+	/*
+	 * Iterate over each registered DMAC
+	 */
+	list_for_each_safe(pos, tmp, &registered_dmac_list) {
+		struct dma_info *info = list_entry(pos, struct dma_info, list);
+		int i;
+
+		/*
+		 * Iterate over each channel
+		 */
+		for (i = 0; i < info->nr_channels; i++) {
+			struct dma_channel *channel = info->channels + i;
+
+			if (!(channel->flags & DMA_CONFIGURED))
+				continue;
+
+			p += sprintf(p, "%2d: %14s    %s\n", i,
+				     info->name, channel->dev_id);
+		}
+	}
+
+	return p - buf;
+}
+#endif
+
+
+int __init register_dmac(struct dma_info *info)
+{
+	int i;
+
+	INIT_LIST_HEAD(&info->list);
+
+	printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n",
+	       info->name, info->nr_channels,
+	       info->nr_channels > 1 ? "s" : "");
+
+	BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels);
+
+	/*
+	 * Don't touch pre-configured channels
+	 */
+	if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) {
+		unsigned int size;
+
+		size = sizeof(struct dma_channel) * info->nr_channels;
+
+		info->channels = kmalloc(size, GFP_KERNEL);
+		if (!info->channels)
+			return -ENOMEM;
+
+		memset(info->channels, 0, size);
+	}
+
+	for (i = 0; i < info->nr_channels; i++) {
+		struct dma_channel *chan = info->channels + i;
+
+		chan->chan = i;
+
+		memcpy(chan->dev_id, "Unused", 7);
+
+		if (info->flags & DMAC_CHANNELS_TEI_CAPABLE)
+			chan->flags |= DMA_TEI_CAPABLE;
+
+		init_MUTEX(&chan->sem);
+		init_waitqueue_head(&chan->wait_queue);
+
+#ifdef CONFIG_SYSFS
+		dma_create_sysfs_files(chan);
+#endif
+	}
+
+	list_add(&info->list, &registered_dmac_list);
+
+	return 0;
+}
+
+void __exit unregister_dmac(struct dma_info *info)
+{
+	if (!(info->flags & DMAC_CHANNELS_CONFIGURED))
+		kfree(info->channels);
+
+	list_del(&info->list);
+}
+
+static int __init dma_api_init(void)
+{
+	printk("DMA: Registering DMA API.\n");
+
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("dma", 0, 0, dma_read_proc, 0);
+#endif
+
+	return 0;
+}
+
+subsys_initcall(dma_api_init);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("DMA API for SuperH");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(request_dma);
+EXPORT_SYMBOL(free_dma);
+EXPORT_SYMBOL(register_dmac);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(get_dma_info);
+EXPORT_SYMBOL(get_dma_channel);
+EXPORT_SYMBOL(dma_xfer);
+EXPORT_SYMBOL(dma_wait_for_completion);
+EXPORT_SYMBOL(dma_configure_channel);
+
diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c
new file mode 100644
index 0000000..231e3f6
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-g2.c
@@ -0,0 +1,171 @@
+/*
+ * arch/sh/drivers/dma/dma-g2.c
+ *
+ * G2 bus DMA support
+ *
+ * Copyright (C) 2003, 2004  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <asm/mach/sysasic.h>
+#include <asm/mach/dma.h>
+#include <asm/dma.h>
+
+struct g2_channel {
+	unsigned long g2_addr;		/* G2 bus address */
+	unsigned long root_addr;	/* Root bus (SH-4) address */
+	unsigned long size;		/* Size (in bytes), 32-byte aligned */
+	unsigned long direction;	/* Transfer direction */
+	unsigned long ctrl;		/* Transfer control */
+	unsigned long chan_enable;	/* Channel enable */
+	unsigned long xfer_enable;	/* Transfer enable */
+	unsigned long xfer_stat;	/* Transfer status */
+} __attribute__ ((aligned(32)));
+
+struct g2_status {
+	unsigned long g2_addr;
+	unsigned long root_addr;
+	unsigned long size;
+	unsigned long status;
+} __attribute__ ((aligned(16)));
+
+struct g2_dma_info {
+	struct g2_channel channel[G2_NR_DMA_CHANNELS];
+	unsigned long pad1[G2_NR_DMA_CHANNELS];
+	unsigned long wait_state;
+	unsigned long pad2[10];
+	unsigned long magic;
+	struct g2_status status[G2_NR_DMA_CHANNELS];
+} __attribute__ ((aligned(256)));
+
+static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800;
+
+static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* FIXME: Do some meaningful completion work here.. */
+	return IRQ_HANDLED;
+}
+
+static struct irqaction g2_dma_irq = {
+	.name		= "g2 DMA handler",
+	.handler	= g2_dma_interrupt,
+	.flags		= SA_INTERRUPT,
+};
+
+static int g2_enable_dma(struct dma_channel *chan)
+{
+	unsigned int chan_nr = chan->chan;
+
+	g2_dma->channel[chan_nr].chan_enable = 1;
+	g2_dma->channel[chan_nr].xfer_enable = 1;
+
+	return 0;
+}
+
+static int g2_disable_dma(struct dma_channel *chan)
+{
+	unsigned int chan_nr = chan->chan;
+
+	g2_dma->channel[chan_nr].chan_enable = 0;
+	g2_dma->channel[chan_nr].xfer_enable = 0;
+
+	return 0;
+}
+
+static int g2_xfer_dma(struct dma_channel *chan)
+{
+	unsigned int chan_nr = chan->chan;
+
+	if (chan->sar & 31) {
+		printk("g2dma: unaligned source 0x%lx\n", chan->sar);
+		return -EINVAL;
+	}
+
+	if (chan->dar & 31) {
+		printk("g2dma: unaligned dest 0x%lx\n", chan->dar);
+		return -EINVAL;
+	}
+
+	/* Align the count */
+	if (chan->count & 31)
+		chan->count = (chan->count + (32 - 1)) & ~(32 - 1);
+
+	/* Fixup destination */
+	chan->dar += 0xa0800000;
+
+	/* Fixup direction */
+	chan->mode = !chan->mode;
+
+	flush_icache_range((unsigned long)chan->sar, chan->count);
+
+	g2_disable_dma(chan);
+
+	g2_dma->channel[chan_nr].g2_addr   = chan->dar & 0x1fffffe0;
+	g2_dma->channel[chan_nr].root_addr = chan->sar & 0x1fffffe0;
+	g2_dma->channel[chan_nr].size	   = (chan->count & ~31) | 0x80000000;
+	g2_dma->channel[chan_nr].direction = chan->mode;
+
+	/*
+	 * bit 0 - ???
+	 * bit 1 - if set, generate a hardware event on transfer completion
+	 * bit 2 - ??? something to do with suspend?
+	 */
+	g2_dma->channel[chan_nr].ctrl	= 5; /* ?? */
+
+	g2_enable_dma(chan);
+
+	/* debug cruft */
+	pr_debug("count, sar, dar, mode, ctrl, chan, xfer: %ld, 0x%08lx, "
+		 "0x%08lx, %ld, %ld, %ld, %ld\n",
+		 g2_dma->channel[chan_nr].size,
+		 g2_dma->channel[chan_nr].root_addr,
+		 g2_dma->channel[chan_nr].g2_addr,
+		 g2_dma->channel[chan_nr].direction,
+		 g2_dma->channel[chan_nr].ctrl,
+		 g2_dma->channel[chan_nr].chan_enable,
+		 g2_dma->channel[chan_nr].xfer_enable);
+
+	return 0;
+}
+
+static struct dma_ops g2_dma_ops = {
+	.xfer		= g2_xfer_dma,
+};
+
+static struct dma_info g2_dma_info = {
+	.name		= "G2 DMA",
+	.nr_channels	= 4,
+	.ops		= &g2_dma_ops,
+	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
+};
+
+static int __init g2_dma_init(void)
+{
+	setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq);
+
+	/* Magic */
+	g2_dma->wait_state	= 27;
+	g2_dma->magic		= 0x4659404f;
+
+	return register_dmac(&g2_dma_info);
+}
+
+static void __exit g2_dma_exit(void)
+{
+	free_irq(HW_EVENT_G2_DMA, 0);
+}
+
+subsys_initcall(g2_dma_init);
+module_exit(g2_dma_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("G2 bus DMA driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c
new file mode 100644
index 0000000..1c9bc45
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-isa.c
@@ -0,0 +1,106 @@
+/*
+ * arch/sh/drivers/dma/dma-isa.c
+ *
+ * Generic ISA DMA wrapper for SH DMA API
+ *
+ * Copyright (C) 2003, 2004  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/kernel.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+
+/*
+ * This implements a small wrapper set to make code using the old ISA DMA API
+ * work with the SH DMA API. Since most of the work in the new API happens
+ * at ops->xfer() time, we simply use the various set_dma_xxx() routines to
+ * fill in per-channel info, and then hand hand this off to ops->xfer() at
+ * enable_dma() time.
+ *
+ * For channels that are doing on-demand data transfer via cascading, the
+ * channel itself will still need to be configured through the new API. As
+ * such, this code is meant for only the simplest of tasks (and shouldn't be
+ * used in any new drivers at all).
+ *
+ * It should also be noted that various functions here are labelled as
+ * being deprecated. This is due to the fact that the ops->xfer() method is
+ * the preferred way of doing things (as well as just grabbing the spinlock
+ * directly). As such, any users of this interface will be warned rather
+ * loudly.
+ */
+
+unsigned long __deprecated claim_dma_lock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dma_spin_lock, flags);
+
+	return flags;
+}
+EXPORT_SYMBOL(claim_dma_lock);
+
+void __deprecated release_dma_lock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&dma_spin_lock, flags);
+}
+EXPORT_SYMBOL(release_dma_lock);
+
+void __deprecated disable_dma(unsigned int chan)
+{
+	/* Nothing */
+}
+EXPORT_SYMBOL(disable_dma);
+
+void __deprecated enable_dma(unsigned int chan)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	info->ops->xfer(channel);
+}
+EXPORT_SYMBOL(enable_dma);
+
+void clear_dma_ff(unsigned int chan)
+{
+	/* Nothing */
+}
+EXPORT_SYMBOL(clear_dma_ff);
+
+void set_dma_mode(unsigned int chan, char mode)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	channel->mode = mode;
+}
+EXPORT_SYMBOL(set_dma_mode);
+
+void set_dma_addr(unsigned int chan, unsigned int addr)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	/*
+	 * Single address mode is the only thing supported through
+	 * this interface.
+	 */
+	if ((channel->mode & DMA_MODE_MASK) == DMA_MODE_READ) {
+		channel->sar = addr;
+	} else {
+		channel->dar = addr;
+	}
+}
+EXPORT_SYMBOL(set_dma_addr);
+
+void set_dma_count(unsigned int chan, unsigned int count)
+{
+	struct dma_info *info = get_dma_info(chan);
+	struct dma_channel *channel = &info->channels[chan];
+
+	channel->count = count;
+}
+EXPORT_SYMBOL(set_dma_count);
+
diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c
new file mode 100644
index 0000000..2e1d58f
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-pvr2.c
@@ -0,0 +1,109 @@
+/*
+ * arch/sh/boards/dreamcast/dma-pvr2.c
+ *
+ * NEC PowerVR 2 (Dreamcast) DMA support
+ *
+ * Copyright (C) 2003, 2004  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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <asm/mach/sysasic.h>
+#include <asm/mach/dma.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+static unsigned int xfer_complete = 0;
+static int count = 0;
+
+static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (get_dma_residue(PVR2_CASCADE_CHAN)) {
+		printk(KERN_WARNING "DMA: SH DMAC did not complete transfer "
+		       "on channel %d, waiting..\n", PVR2_CASCADE_CHAN);
+		dma_wait_for_completion(PVR2_CASCADE_CHAN);
+	}
+
+	if (count++ < 10)
+		pr_debug("Got a pvr2 dma interrupt for channel %d\n",
+			 irq - HW_EVENT_PVR2_DMA);
+
+	xfer_complete = 1;
+
+	return IRQ_HANDLED;
+}
+
+static int pvr2_request_dma(struct dma_channel *chan)
+{
+	if (ctrl_inl(PVR2_DMA_MODE) != 0)
+		return -EBUSY;
+
+	ctrl_outl(0, PVR2_DMA_LMMODE0);
+
+	return 0;
+}
+
+static int pvr2_get_dma_residue(struct dma_channel *chan)
+{
+	return xfer_complete == 0;
+}
+
+static int pvr2_xfer_dma(struct dma_channel *chan)
+{
+	if (chan->sar || !chan->dar)
+		return -EINVAL;
+
+	xfer_complete = 0;
+
+	ctrl_outl(chan->dar, PVR2_DMA_ADDR);
+	ctrl_outl(chan->count, PVR2_DMA_COUNT);
+	ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE);
+
+	return 0;
+}
+
+static struct irqaction pvr2_dma_irq = {
+	.name		= "pvr2 DMA handler",
+	.handler	= pvr2_dma_interrupt,
+	.flags		= SA_INTERRUPT,
+};
+
+static struct dma_ops pvr2_dma_ops = {
+	.request	= pvr2_request_dma,
+	.get_residue	= pvr2_get_dma_residue,
+	.xfer		= pvr2_xfer_dma,
+};
+
+static struct dma_info pvr2_dma_info = {
+	.name		= "PowerVR 2 DMA",
+	.nr_channels	= 1,
+	.ops		= &pvr2_dma_ops,
+	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
+};
+
+static int __init pvr2_dma_init(void)
+{
+	setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq);
+	request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade");
+
+	return register_dmac(&pvr2_dma_info);
+}
+
+static void __exit pvr2_dma_exit(void)
+{
+	free_dma(PVR2_CASCADE_CHAN);
+	free_irq(HW_EVENT_PVR2_DMA, 0);
+}
+
+subsys_initcall(pvr2_dma_init);
+module_exit(pvr2_dma_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
new file mode 100644
index 0000000..31dacd4
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -0,0 +1,267 @@
+/*
+ * arch/sh/drivers/dma/dma-sh.c
+ *
+ * SuperH On-chip DMAC Support
+ *
+ * Copyright (C) 2000 Takashi YOSHII
+ * Copyright (C) 2003, 2004 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/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/signal.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include "dma-sh.h"
+
+/*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+ *
+ * Defaults to a 64-bit transfer size.
+ */
+enum {
+	XMIT_SZ_64BIT,
+	XMIT_SZ_8BIT,
+	XMIT_SZ_16BIT,
+	XMIT_SZ_32BIT,
+	XMIT_SZ_256BIT,
+};
+
+/*
+ * The DMA count is defined as the number of bytes to transfer.
+ */
+static unsigned int ts_shift[] = {
+	[XMIT_SZ_64BIT]		= 3,
+	[XMIT_SZ_8BIT]		= 0,
+	[XMIT_SZ_16BIT]		= 1,
+	[XMIT_SZ_32BIT]		= 2,
+	[XMIT_SZ_256BIT]	= 5,
+};
+
+static inline unsigned int get_dmte_irq(unsigned int chan)
+{
+	unsigned int irq;
+
+	/*
+	 * Normally we could just do DMTE0_IRQ + chan outright, though in the
+	 * case of the 7751R, the DMTE IRQs for channels > 4 start right above
+	 * the SCIF
+	 */
+
+	if (chan < 4) {
+		irq = DMTE0_IRQ + chan;
+	} else {
+		irq = DMTE4_IRQ + chan - 4;
+	}
+
+	return irq;
+}
+
+/*
+ * We determine the correct shift size based off of the CHCR transmit size
+ * for the given channel. Since we know that it will take:
+ *
+ *	info->count >> ts_shift[transmit_size]
+ *
+ * iterations to complete the transfer.
+ */
+static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
+{
+	u32 chcr = ctrl_inl(CHCR[chan->chan]);
+
+	chcr >>= 4;
+
+	return ts_shift[chcr & 0x0007];
+}
+
+/*
+ * The transfer end interrupt must read the chcr register to end the
+ * hardware interrupt active condition.
+ * Besides that it needs to waken any waiting process, which should handle
+ * setting up the next transfer.
+ */
+static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct dma_channel *chan = (struct dma_channel *)dev_id;
+	u32 chcr;
+
+	chcr = ctrl_inl(CHCR[chan->chan]);
+
+	if (!(chcr & CHCR_TE))
+		return IRQ_NONE;
+
+	chcr &= ~(CHCR_IE | CHCR_DE);
+	ctrl_outl(chcr, CHCR[chan->chan]);
+
+	wake_up(&chan->wait_queue);
+
+	return IRQ_HANDLED;
+}
+
+static int sh_dmac_request_dma(struct dma_channel *chan)
+{
+	return request_irq(get_dmte_irq(chan->chan), dma_tei,
+			   SA_INTERRUPT, "DMAC Transfer End", chan);
+}
+
+static void sh_dmac_free_dma(struct dma_channel *chan)
+{
+	free_irq(get_dmte_irq(chan->chan), chan);
+}
+
+static void sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
+{
+	if (!chcr)
+		chcr = RS_DUAL;
+
+	ctrl_outl(chcr, CHCR[chan->chan]);
+
+	chan->flags |= DMA_CONFIGURED;
+}
+
+static void sh_dmac_enable_dma(struct dma_channel *chan)
+{
+	int irq = get_dmte_irq(chan->chan);
+	u32 chcr;
+
+	chcr = ctrl_inl(CHCR[chan->chan]);
+	chcr |= CHCR_DE | CHCR_IE;
+	ctrl_outl(chcr, CHCR[chan->chan]);
+
+	enable_irq(irq);
+}
+
+static void sh_dmac_disable_dma(struct dma_channel *chan)
+{
+	int irq = get_dmte_irq(chan->chan);
+	u32 chcr;
+
+	disable_irq(irq);
+
+	chcr = ctrl_inl(CHCR[chan->chan]);
+	chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
+	ctrl_outl(chcr, CHCR[chan->chan]);
+}
+
+static int sh_dmac_xfer_dma(struct dma_channel *chan)
+{
+	/*
+	 * If we haven't pre-configured the channel with special flags, use
+	 * the defaults.
+	 */
+	if (!(chan->flags & DMA_CONFIGURED))
+		sh_dmac_configure_channel(chan, 0);
+
+	sh_dmac_disable_dma(chan);
+
+	/*
+	 * Single-address mode usage note!
+	 *
+	 * It's important that we don't accidentally write any value to SAR/DAR
+	 * (this includes 0) that hasn't been directly specified by the user if
+	 * we're in single-address mode.
+	 *
+	 * In this case, only one address can be defined, anything else will
+	 * result in a DMA address error interrupt (at least on the SH-4),
+	 * which will subsequently halt the transfer.
+	 *
+	 * Channel 2 on the Dreamcast is a special case, as this is used for
+	 * cascading to the PVR2 DMAC. In this case, we still need to write
+	 * SAR and DAR, regardless of value, in order for cascading to work.
+	 */
+	if (chan->sar || (mach_is_dreamcast() && chan->chan == 2))
+		ctrl_outl(chan->sar, SAR[chan->chan]);
+	if (chan->dar || (mach_is_dreamcast() && chan->chan == 2))
+		ctrl_outl(chan->dar, DAR[chan->chan]);
+
+	ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]);
+
+	sh_dmac_enable_dma(chan);
+
+	return 0;
+}
+
+static int sh_dmac_get_dma_residue(struct dma_channel *chan)
+{
+	if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE))
+		return 0;
+
+	return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan);
+}
+
+#if defined(CONFIG_CPU_SH4)
+static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long dmaor = ctrl_inl(DMAOR);
+
+	printk("DMAE: DMAOR=%lx\n", dmaor);
+
+	ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_NMIF, DMAOR);
+	ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_AE, DMAOR);
+	ctrl_outl(ctrl_inl(DMAOR)|DMAOR_DME, DMAOR);
+
+	disable_irq(irq);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+static struct dma_ops sh_dmac_ops = {
+	.request	= sh_dmac_request_dma,
+	.free		= sh_dmac_free_dma,
+	.get_residue	= sh_dmac_get_dma_residue,
+	.xfer		= sh_dmac_xfer_dma,
+	.configure	= sh_dmac_configure_channel,
+};
+
+static struct dma_info sh_dmac_info = {
+	.name		= "SuperH DMAC",
+	.nr_channels	= 4,
+	.ops		= &sh_dmac_ops,
+	.flags		= DMAC_CHANNELS_TEI_CAPABLE,
+};
+
+static int __init sh_dmac_init(void)
+{
+	struct dma_info *info = &sh_dmac_info;
+	int i;
+
+#ifdef CONFIG_CPU_SH4
+	make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+	i = request_irq(DMAE_IRQ, dma_err, SA_INTERRUPT, "DMAC Address Error", 0);
+	if (i < 0)
+		return i;
+#endif
+
+	for (i = 0; i < info->nr_channels; i++) {
+		int irq = get_dmte_irq(i);
+
+		make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+	}
+
+	ctrl_outl(0x8000 | DMAOR_DME, DMAOR);
+
+	return register_dmac(info);
+}
+
+static void __exit sh_dmac_exit(void)
+{
+#ifdef CONFIG_CPU_SH4
+	free_irq(DMAE_IRQ, 0);
+#endif
+}
+
+subsys_initcall(sh_dmac_init);
+module_exit(sh_dmac_exit);
+
+MODULE_LICENSE("GPL");
+
diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h
new file mode 100644
index 0000000..dd9d547
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-sh.h
@@ -0,0 +1,52 @@
+/*
+ * arch/sh/drivers/dma/dma-sh.h
+ *
+ * Copyright (C) 2000  Takashi YOSHII
+ * Copyright (C) 2003  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.
+ */
+#ifndef __DMA_SH_H
+#define __DMA_SH_H
+
+/* Definitions for the SuperH DMAC */
+#define REQ_L	0x00000000
+#define REQ_E	0x00080000
+#define RACK_H	0x00000000
+#define RACK_L	0x00040000
+#define ACK_R	0x00000000
+#define ACK_W	0x00020000
+#define ACK_H	0x00000000
+#define ACK_L	0x00010000
+#define DM_INC	0x00004000
+#define DM_DEC	0x00008000
+#define SM_INC	0x00001000
+#define SM_DEC	0x00002000
+#define RS_IN	0x00000200
+#define RS_OUT	0x00000300
+#define TM_BURST 0x0000080
+#define TS_8	0x00000010
+#define TS_16	0x00000020
+#define TS_32	0x00000030
+#define TS_64	0x00000000
+#define TS_BLK	0x00000040
+#define CHCR_DE 0x00000001
+#define CHCR_TE 0x00000002
+#define CHCR_IE 0x00000004
+
+/* Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_32)
+
+#define DMAOR_COD	0x00000008
+#define DMAOR_AE	0x00000004
+#define DMAOR_NMIF	0x00000002
+#define DMAOR_DME	0x00000001
+
+#define MAX_DMAC_CHANNELS	(CONFIG_NR_ONCHIP_DMA_CHANNELS)
+
+#endif /* __DMA_SH_H */
+
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
new file mode 100644
index 0000000..71a6d4e
--- /dev/null
+++ b/arch/sh/drivers/dma/dma-sysfs.c
@@ -0,0 +1,133 @@
+/*
+ * arch/sh/drivers/dma/dma-sysfs.c
+ *
+ * sysfs interface for SH DMA API
+ *
+ * Copyright (C) 2004  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/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+
+static struct sysdev_class dma_sysclass = {
+	set_kset_name("dma"),
+};
+
+EXPORT_SYMBOL(dma_sysclass);
+
+static ssize_t dma_show_devices(struct sys_device *dev, char *buf)
+{
+	ssize_t len = 0;
+	int i;
+
+	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+		struct dma_info *info = get_dma_info(i);
+		struct dma_channel *channel = &info->channels[i];
+
+		len += sprintf(buf + len, "%2d: %14s    %s\n",
+			       channel->chan, info->name,
+			       channel->dev_id);
+	}
+
+	return len;
+}
+
+static SYSDEV_ATTR(devices, S_IRUGO, dma_show_devices, NULL);
+
+static int __init dma_sysclass_init(void)
+{
+	int ret;
+
+	ret = sysdev_class_register(&dma_sysclass);
+	if (ret == 0)
+		sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr);
+
+	return ret;
+}
+
+postcore_initcall(dma_sysclass_init);
+
+static ssize_t dma_show_dev_id(struct sys_device *dev, char *buf)
+{
+	struct dma_channel *channel = to_dma_channel(dev);
+	return sprintf(buf, "%s\n", channel->dev_id);
+}
+
+static ssize_t dma_store_dev_id(struct sys_device *dev,
+				const char *buf, size_t count)
+{
+	struct dma_channel *channel = to_dma_channel(dev);
+	strcpy(channel->dev_id, buf);
+	return count;
+}
+
+static SYSDEV_ATTR(dev_id, S_IRUGO | S_IWUSR, dma_show_dev_id, dma_store_dev_id);
+
+static ssize_t dma_store_config(struct sys_device *dev,
+				const char *buf, size_t count)
+{
+	struct dma_channel *channel = to_dma_channel(dev);
+	unsigned long config;
+
+	config = simple_strtoul(buf, NULL, 0);
+	dma_configure_channel(channel->chan, config);
+
+	return count;
+}
+
+static SYSDEV_ATTR(config, S_IWUSR, NULL, dma_store_config);
+
+static ssize_t dma_show_mode(struct sys_device *dev, char *buf)
+{
+	struct dma_channel *channel = to_dma_channel(dev);
+	return sprintf(buf, "0x%08x\n", channel->mode);
+}
+
+static ssize_t dma_store_mode(struct sys_device *dev,
+			      const char *buf, size_t count)
+{
+	struct dma_channel *channel = to_dma_channel(dev);
+	channel->mode = simple_strtoul(buf, NULL, 0);
+	return count;
+}
+
+static SYSDEV_ATTR(mode, S_IRUGO | S_IWUSR, dma_show_mode, dma_store_mode);
+
+#define dma_ro_attr(field, fmt)						\
+static ssize_t dma_show_##field(struct sys_device *dev, char *buf)	\
+{									\
+	struct dma_channel *channel = to_dma_channel(dev);		\
+	return sprintf(buf, fmt, channel->field);			\
+}									\
+static SYSDEV_ATTR(field, S_IRUGO, dma_show_##field, NULL);
+
+dma_ro_attr(count, "0x%08x\n");
+dma_ro_attr(flags, "0x%08lx\n");
+
+int __init dma_create_sysfs_files(struct dma_channel *chan)
+{
+	struct sys_device *dev = &chan->dev;
+	int ret;
+
+	dev->id  = chan->chan;
+	dev->cls = &dma_sysclass;
+
+	ret = sysdev_register(dev);
+	if (ret)
+		return ret;
+
+	sysdev_create_file(dev, &attr_dev_id);
+	sysdev_create_file(dev, &attr_count);
+	sysdev_create_file(dev, &attr_mode);
+	sysdev_create_file(dev, &attr_flags);
+	sysdev_create_file(dev, &attr_config);
+
+	return 0;
+}
+
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
new file mode 100644
index 0000000..6d1cbbe
--- /dev/null
+++ b/arch/sh/drivers/pci/Kconfig
@@ -0,0 +1,41 @@
+config PCI
+	bool "PCI support"
+	help
+	  Find out whether you have a PCI motherboard. PCI is the name of a
+	  bus system, i.e. the way the CPU talks to the other stuff inside
+	  your box. If you have PCI, say Y, otherwise N.
+
+	  The PCI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, contains valuable
+	  information about which PCI hardware does work under Linux and which
+	  doesn't.
+
+config SH_PCIDMA_NONCOHERENT
+	bool "Cache and PCI noncoherent"
+	depends on PCI
+	default y
+	help
+	  Enable this option if your platform does not have a CPU cache which
+	  remains coherent with PCI DMA. It is safest to say 'Y', although you
+	  will see better performance if you can say 'N', because the PCI DMA
+	  code will not have to flush the CPU's caches. If you have a PCI host
+	  bridge integrated with your SH CPU, refer carefully to the chip specs
+	  to see if you can say 'N' here. Otherwise, leave it as 'Y'.
+
+# This is also board-specific
+config PCI_AUTO
+	bool
+	depends on PCI
+	default y
+
+config PCI_AUTO_UPDATE_RESOURCES
+	bool
+	depends on PCI_AUTO
+	default y if !SH_DREAMCAST
+	help
+	  Selecting this option will cause the PCI auto code to leave your
+	  BAR values alone. Otherwise they will be updated automatically. If
+	  for some reason, you have a board that simply refuses to work
+	  with its resources updated beyond what they are when the device
+	  is powered up, set this to N. Everyone else will want this as Y.
+
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
new file mode 100644
index 0000000..365bc16
--- /dev/null
+++ b/arch/sh/drivers/pci/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the PCI specific kernel interface routines under Linux.
+#
+
+obj-y					+= pci.o
+obj-$(CONFIG_PCI_AUTO)			+= pci-auto.o
+
+obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= pci-st40.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o 
+
+obj-$(CONFIG_SH_DREAMCAST)		+= ops-dreamcast.o fixups-dreamcast.o \
+					   dma-dreamcast.o
+obj-$(CONFIG_SH_SECUREEDGE5410)		+= ops-snapgear.o
+obj-$(CONFIG_SH_BIGSUR)			+= ops-bigsur.o
+obj-$(CONFIG_SH_RTS7751R2D)		+= ops-rts7751r2d.o fixups-rts7751r2d.o
+obj-$(CONFIG_SH_SH03)			+= ops-sh03.o fixups-sh03.o
diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
new file mode 100644
index 0000000..83de7ef
--- /dev/null
+++ b/arch/sh/drivers/pci/dma-dreamcast.c
@@ -0,0 +1,71 @@
+/*
+ * arch/sh/pci/dma-dreamcast.c
+ *
+ * PCI DMA support for the Sega Dreamcast
+ *
+ * Copyright (C) 2001, 2002  M. R. Brown
+ * Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * This file originally bore the message (with enclosed-$):
+ *	Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+ *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/pci.h>
+
+static int gapspci_dma_used = 0;
+
+void *dreamcast_consistent_alloc(struct device *dev, size_t size,
+				 dma_addr_t *dma_handle, int flag)
+{
+	unsigned long buf;
+
+	if (dev && dev->bus != &pci_bus_type)
+		return NULL;
+
+	if (gapspci_dma_used + size > GAPSPCI_DMA_SIZE)
+		return ERR_PTR(-EINVAL);
+
+	buf = GAPSPCI_DMA_BASE + gapspci_dma_used;
+
+	gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+
+	*dma_handle = (dma_addr_t)buf;
+
+	buf = P2SEGADDR(buf);
+
+	/* Flush the dcache before we hand off the buffer */
+	dma_cache_wback_inv((void *)buf, size);
+
+	return (void *)buf;
+}
+
+int dreamcast_consistent_free(struct device *dev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	if (dev && dev->bus != &pci_bus_type)
+		return -EINVAL;
+
+	/* XXX */
+	gapspci_dma_used = 0;
+
+	return 0;
+}
+
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
new file mode 100644
index 0000000..cf30e2f
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -0,0 +1,81 @@
+/*
+ * arch/sh/pci/fixups-dreamcast.c
+ *
+ * PCI fixups for the Sega Dreamcast
+ *
+ * Copyright (C) 2001, 2002  M. R. Brown
+ * Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * This file originally bore the message (with enclosed-$):
+ *	Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+ *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/pci.h>
+
+static void __init gapspci_fixup_resources(struct pci_dev *dev)
+{
+	struct pci_channel *p = board_pci_channels;
+
+	printk(KERN_NOTICE "PCI: Fixing up device %s\n", pci_name(dev));
+
+	switch (dev->device) {
+	case PCI_DEVICE_ID_SEGA_BBA:
+		/*
+		 * We also assume that dev->devfn == 0
+		 */
+		dev->resource[1].start	= p->io_resource->start  + 0x100;
+		dev->resource[1].end	= dev->resource[1].start + 0x200 - 1;
+		break;
+	default:
+		printk("PCI: Failed resource fixup\n");
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	/* 
+	 * We don't have any sub bus to fix up, and this is a rather
+	 * stupid place to put general device fixups. Don't do it.
+	 * Use the pcibios_fixups table or suffer the consequences.
+	 */
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev = 0;
+
+	for_each_pci_dev(dev) {
+		/*
+		 * The interrupt routing semantics here are quite trivial.
+		 *
+		 * We basically only support one interrupt, so we only bother
+		 * updating a device's interrupt line with this single shared
+		 * interrupt. Keeps routing quite simple, doesn't it?
+		 */
+		printk(KERN_NOTICE "PCI: Fixing up IRQ routing for device %s\n",
+		       pci_name(dev));
+
+		dev->irq = GAPSPCI_IRQ;
+
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
new file mode 100644
index 0000000..0c590fc
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -0,0 +1,43 @@
+/*
+ * arch/sh/drivers/pci/fixups-rts7751r2d.c
+ *
+ * RTS7751R2D PCI fixups
+ *
+ * Copyright (C) 2003  Lineo uSolutions, Inc.
+ * Copyright (C) 2004  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 "pci-sh7751.h"
+#include <asm/io.h>
+
+#define PCIMCR_MRSET_OFF	0xBFFFFFFF
+#define PCIMCR_RFSH_OFF		0xFFFFFFFB
+
+int pci_fixup_pcic(void)
+{
+	unsigned long bcr1, mcr;
+
+	bcr1 = inl(SH7751_BCR1);
+	bcr1 |= 0x40080000;	/* Enable Bit 19 BREQEN, set PCIC to slave */
+	outl(bcr1, PCI_REG(SH7751_PCIBCR1));
+
+	/* Enable all interrupts, so we known what to fix */
+	outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM));
+	outl(0x0000380f, PCI_REG(SH7751_PCIAINTM));
+
+	outl(0xfb900047, PCI_REG(SH7751_PCICONF1));
+	outl(0xab000001, PCI_REG(SH7751_PCICONF4));
+
+	mcr = inl(SH7751_MCR);
+	mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+	outl(mcr, PCI_REG(SH7751_PCIMCR));
+
+	outl(0x0c000000, PCI_REG(SH7751_PCICONF5));
+	outl(0xd0000000, PCI_REG(SH7751_PCICONF6));
+	outl(0x0c000000, PCI_REG(SH7751_PCILAR0));
+	outl(0x00000000, PCI_REG(SH7751_PCILAR1));
+	return 0;
+}
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
new file mode 100644
index 0000000..57ac26c
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -0,0 +1,61 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * 	IRQ functions
+ */
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
+{
+	int irq;
+
+	if (dev->bus->number == 0) {
+		switch (slot) {
+		case 4: return 5;	/* eth0       */
+		case 8: return 5;	/* eth1       */
+		case 6: return 2;	/* PCI bridge */
+		default:
+                	printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+                	return 2;
+		}
+	} else {
+		switch (pin) {
+		case 0:   irq =  2; break;
+		case 1:   irq =  2; break;
+		case 2:   irq =  2; break;
+		case 3:   irq =  2; break;
+		case 4:   irq =  2; break;
+		default:  irq = -1; break;
+		}
+	}
+	return irq;
+}
+
+static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	/* no swizzling */
+	return PCI_SLOT(dev->devfn);
+}
+
+static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq = -1;
+
+	/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+	irq = pcibios_map_platform_irq(slot, pin, dev);
+	if( irq < 0 ) {
+		pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
+		return irq;
+	}
+
+	pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
+
+	return irq;
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq);
+}
diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c
new file mode 100644
index 0000000..9b43da6
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-bigsur.c
@@ -0,0 +1,88 @@
+/*
+ * linux/arch/sh/kernel/pci-bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ *
+ * Ported to new API by Paul Mundt <lethal@linux-sh.org>.
+ *
+ * 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 "pci-sh7751.h"
+#include <asm/bigsur/bigsur.h>
+
+#define BIGSUR_PCI_IO	0x4000
+#define BIGSUR_PCI_MEM	0xfd000000
+
+static struct resource sh7751_io_resource = {
+	.name		= "SH7751 IO",
+	.start		= BIGSUR_PCI_IO,
+	.end		= BIGSUR_PCI_IO + (64*1024) - 1,
+	.flags		= IORESOURCE_IO,
+};
+
+static struct resource sh7751_mem_resource = {
+	.name		= "SH7751 mem",
+	.start		= BIGSUR_PCI_MEM,
+	.end		= BIGSUR_PCI_MEM + (64*1024*1024) - 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 },
+	{ 0, }
+};
+
+static struct sh7751_pci_address_map sh7751_pci_map = {
+	.window0	= {
+		.base	= SH7751_CS3_BASE_ADDR,
+		.size	= BIGSUR_LSR0_SIZE,
+	},
+
+	.window1	= {
+		.base	= SH7751_CS3_BASE_ADDR,
+		.size	= BIGSUR_LSR1_SIZE,
+	},
+};
+
+/*
+ * 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)
+{
+	return sh7751_pcic_init(&sh7751_pci_map);
+}
+
+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;
+}
+
diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c
new file mode 100644
index 0000000..69af80b
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-dreamcast.c
@@ -0,0 +1,169 @@
+/*
+ * arch/sh/pci/ops-dreamcast.c
+ *
+ * PCI operations for the Sega Dreamcast
+ *
+ * Copyright (C) 2001, 2002  M. R. Brown
+ * Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * This file originally bore the message (with enclosed-$):
+ *	Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
+ *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/pci.h>
+
+static struct resource gapspci_io_resource = {
+	.name	= "GAPSPCI IO",
+	.start	= GAPSPCI_BBA_CONFIG,
+	.end	= GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1,
+	.flags	= IORESOURCE_IO,
+};
+
+static struct resource gapspci_mem_resource = {
+	.name	= "GAPSPCI mem",
+	.start	= GAPSPCI_DMA_BASE,
+	.end	= GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct pci_ops gapspci_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+	{ &gapspci_pci_ops, &gapspci_io_resource,
+	  &gapspci_mem_resource, 0, 1 },
+	{ 0, }
+};
+
+/*
+ * The !gapspci_config_access case really shouldn't happen, ever, unless
+ * someone implicitly messes around with the last devfn value.. otherwise we
+ * only support a single device anyways, and if we didn't have a BBA, we
+ * wouldn't make it terribly far through the PCI setup anyways.
+ *
+ * Also, we could very easily support both Type 0 and Type 1 configurations
+ * here, but since it doesn't seem that there is any such implementation in
+ * existance, we don't bother.
+ *
+ * I suppose if someone actually gets around to ripping the chip out of
+ * the BBA and hanging some more devices off of it, then this might be
+ * something to take into consideration. However, due to the cost of the BBA,
+ * and the general lack of activity by DC hardware hackers, this doesn't seem
+ * likely to happen anytime soon.
+ */
+static int gapspci_config_access(unsigned char bus, unsigned int devfn)
+{
+	return (bus == 0) && (devfn == 0);
+}
+
+/*
+ * We can also actually read and write in b/w/l sizes! Thankfully this part
+ * was at least done right, and we don't have to do the stupid masking and
+ * shifting that we do on the 7751! Small wonders never cease to amaze.
+ */
+static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val)
+{
+	*val = 0xffffffff;
+
+	if (!gapspci_config_access(bus->number, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	switch (size) {
+		case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break;
+		case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break;
+		case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break;
+	}	
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+	if (!gapspci_config_access(bus->number, devfn))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	switch (size) {
+		case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break;
+		case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break;
+		case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break;
+	}
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops gapspci_pci_ops = {
+	.read	= gapspci_read,
+	.write	= gapspci_write,
+};
+
+/*
+ * gapspci init
+ */
+
+int __init gapspci_init(void)
+{
+	char idbuf[16];
+	int i;
+
+	/*
+	 * FIXME: All of this wants documenting to some degree,
+	 * even some basic register definitions would be nice.
+	 *
+	 * I haven't seen anything this ugly since.. maple.
+	 */
+
+	for (i=0; i<16; i++)
+		idbuf[i] = inb(GAPSPCI_REGS+i);
+
+	if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+		return -ENODEV;
+
+	outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+	for (i=0; i<1000000; i++)
+		;
+
+	if (inl(GAPSPCI_REGS+0x18) != 1)
+		return -EINVAL;
+
+	outl(0x01000000, GAPSPCI_REGS+0x20);
+	outl(0x01000000, GAPSPCI_REGS+0x24);
+
+	outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+	outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+	outl(1, GAPSPCI_REGS+0x14);
+	outl(1, GAPSPCI_REGS+0x34);
+
+	/* Setting Broadband Adapter */
+	outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+	outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+	outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+	outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+	outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+	outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+	outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+	return 0;
+}
+
+/* Haven't done anything here as yet */
+char * __devinit pcibios_setup(char *str)
+{
+	return str;
+}
diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c
new file mode 100644
index 0000000..beafa11
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-rts7751r2d.c
@@ -0,0 +1,79 @@
+/*
+ * linux/arch/sh/kernel/pci-rts7751r2d.c
+ *
+ * Author:  Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the Renesas SH7751R RTS7751R2D 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 <linux/module.h>
+
+#include <asm/io.h>
+#include "pci-sh7751.h"
+#include <asm/rts7751r2d/rts7751r2d.h>
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+        switch (slot) {
+	case 0: return IRQ_PCISLOT1;	/* PCI Extend slot #1 */
+	case 1: return IRQ_PCISLOT2;	/* PCI Extend slot #2 */
+	case 2: return IRQ_PCMCIA;	/* PCI Cardbus Bridge */
+	case 3: return IRQ_PCIETH;	/* Realtek Ethernet controller */
+	default:
+		printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+		return -1;
+	}
+}
+
+static struct resource sh7751_io_resource = {
+	.name	= "SH7751_IO",
+	.start	= 0x4000,
+	.end	= 0x4000 + 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 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh7751_pci_address_map sh7751_pci_map = {
+	.window0	= {
+		.base	= SH7751_CS3_BASE_ADDR,
+		.size	= 0x04000000,
+	},
+
+	.window1	= {
+		.base	= 0x00000000,	/* Unused */
+		.size	= 0x00000000,	/* Unused */
+	},
+
+	.flags	= SH7751_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+	return sh7751_pcic_init(&sh7751_pci_map);
+}
+
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
new file mode 100644
index 0000000..df21997
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-sh03.c
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-sh03.c
+ *
+ * PCI initialization for the Interface CTP/PCI-SH03 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 "pci-sh7751.h"
+
+/*
+ * Description:  This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+   return 1;
+}
+
+static struct resource sh7751_io_resource = {
+	.name   = "SH03 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   = "SH03 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 },
+};
+
diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c
new file mode 100644
index 0000000..6fdb976
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-snapgear.c
@@ -0,0 +1,102 @@
+/*
+ * arch/sh/drivers/pci/ops-snapgear.c
+ *
+ * Author:  David McCullough <davidm@snapgear.com>
+ * 
+ * Ported to new API by Paul Mundt <lethal@linux-sh.org>
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the SnapGear boards
+ */
+
+#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 "pci-sh7751.h"
+
+#define SNAPGEAR_PCI_IO		0x4000
+#define SNAPGEAR_PCI_MEM	0xfd000000
+
+/* PCI: default LOCAL memory window sizes (seen from PCI bus) */
+#define SNAPGEAR_LSR0_SIZE    (64*(1<<20)) //64MB
+#define SNAPGEAR_LSR1_SIZE    (64*(1<<20)) //64MB
+
+static struct resource sh7751_io_resource = {
+	.name		= "SH7751 IO",
+	.start		= SNAPGEAR_PCI_IO,
+	.end		= SNAPGEAR_PCI_IO + (64*1024) - 1, /* 64KiB I/O */
+	.flags		= IORESOURCE_IO,
+};
+
+static struct resource sh7751_mem_resource = {
+	.name		= "SH7751 mem",
+	.start		= SNAPGEAR_PCI_MEM,
+	.end		= SNAPGEAR_PCI_MEM + (64*1024*1024) - 1, /* 64MiB mem */
+	.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 },
+	{ 0, }
+};
+
+static struct sh7751_pci_address_map sh7751_pci_map = {
+	.window0	= {
+		.base	= SH7751_CS2_BASE_ADDR,
+		.size	= SNAPGEAR_LSR0_SIZE,
+	},
+
+	.window1	= {
+		.base	= SH7751_CS2_BASE_ADDR,
+		.size	= SNAPGEAR_LSR1_SIZE,
+	},
+
+	.flags	= SH7751_PCIC_NO_RESET,
+};
+
+/*
+ * Initialize the SnapGear 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)
+{
+	return sh7751_pcic_init(&sh7751_pci_map);
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+	int irq = -1;
+
+	switch (slot) {
+	case 8:  /* the PCI bridge */ break;
+	case 11: irq = 8;  break; /* USB    */
+	case 12: irq = 11; break; /* PCMCIA */
+	case 13: irq = 5;  break; /* eth0   */
+	case 14: irq = 8;  break; /* eth1   */
+	case 15: irq = 11; break; /* safenet (unused) */
+	}
+
+	printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
+	       slot, pin - 1 + 'A', irq);
+
+	return irq;
+}
+
+void __init pcibios_fixup(void)
+{
+	/* Nothing to fixup .. */
+}
+
diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
new file mode 100644
index 0000000..4cef4d1
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-auto.c
@@ -0,0 +1,555 @@
+/*
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000, 2001 MontaVista Software Inc.
+ * Copyright 2001 Bradley D. LaRonde <brad@ltc.com>
+ * Copyright 2003 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * Modified for MIPS by Jun Sun, jsun@mvista.com
+ *
+ * . Simplify the interface between pci_auto and the rest: a single function.
+ * . Assign resources from low address to upper address.
+ * . change most int to u32.
+ *
+ * Further modified to include it as mips generic code, ppopov@mvista.com.
+ *
+ * 2001-10-26  Bradley D. LaRonde <brad@ltc.com>
+ * - Add a top_bus argument to the "early config" functions so that
+ *   they can set a fake parent bus pointer to convince the underlying
+ *   pci ops to use type 1 configuration for sub busses.
+ * - Set bridge base and limit registers correctly.
+ * - Align io and memory base properly before and after bridge setup.
+ * - Don't fall through to pci_setup_bars for bridge.
+ * - Reformat the debug output to look more like lspci's output.
+ *
+ * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org
+ *
+ * 2003-08-05  Paul Mundt <lethal@linux-sh.org>
+ * - Don't update the BAR values on systems that already have valid addresses
+ *   and don't want these updated for whatever reason, by way of a new config
+ *   option check. However, we still read in the old BAR values so that they
+ *   can still be reported through the debug output.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#undef	DEBUG
+#ifdef 	DEBUG
+#define	DBG(x...)	printk(x)
+#else
+#define	DBG(x...)	
+#endif
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
+	int top_bus, int busnr, int devfn)
+{
+	static struct pci_dev dev;
+	static struct pci_bus bus;
+
+	dev.bus = &bus;
+	dev.sysdata = hose;
+	dev.devfn = devfn;
+	bus.number = busnr;
+	bus.ops = hose->pci_ops;
+
+	if(busnr != top_bus)
+		/* Fake a parent bus structure. */
+		bus.parent = &bus;
+	else
+		bus.parent = NULL;
+
+	return &dev;
+}
+
+#define EARLY_PCI_OP(rw, size, type)					\
+int early_##rw##_config_##size(struct pci_channel *hose,		\
+	int top_bus, int bus, int devfn, int offset, type value)	\
+{									\
+	return pci_##rw##_config_##size(				\
+		fake_pci_dev(hose, top_bus, bus, devfn),		\
+		offset, value);						\
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
+
+static struct resource *io_resource_inuse;
+static struct resource *mem_resource_inuse;
+
+static u32 pciauto_lower_iospc;
+static u32 pciauto_upper_iospc;
+
+static u32 pciauto_lower_memspc;
+static u32 pciauto_upper_memspc;
+
+static void __init 
+pciauto_setup_bars(struct pci_channel *hose,
+		   int top_bus,
+		   int current_bus,
+		   int pci_devfn,
+		   int bar_limit)
+{
+	u32 bar_response, bar_size, bar_value;
+	u32 bar, addr_mask, bar_nr = 0;
+	u32 * upper_limit;
+	u32 * lower_limit;
+	int found_mem64 = 0;
+
+	for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
+#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+		u32 bar_addr;
+
+		/* Read the old BAR value */
+		early_read_config_dword(hose, top_bus,
+					current_bus,
+					pci_devfn,
+					bar,
+					&bar_addr);
+#endif
+
+		/* Tickle the BAR and get the response */
+		early_write_config_dword(hose, top_bus,
+					 current_bus,
+					 pci_devfn,
+					 bar,
+					 0xffffffff);
+
+		early_read_config_dword(hose, top_bus,
+					current_bus,
+					pci_devfn,
+					bar,
+					&bar_response);
+
+#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+		/* 
+		 * Write the old BAR value back out, only update the BAR
+		 * if we implicitly want resources to be updated, which
+		 * is done by the generic code further down. -- PFM.
+		 */
+		early_write_config_dword(hose, top_bus,
+					 current_bus,
+					 pci_devfn,
+					 bar,
+					 bar_addr);
+#endif
+
+		/* If BAR is not implemented go to the next BAR */
+		if (!bar_response)
+			continue;
+
+		/*
+		 * Workaround for a BAR that doesn't use its upper word,
+		 * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457).
+		 * bdl <brad@ltc.com>
+		 */
+		if (!(bar_response & 0xffff0000))
+			bar_response |= 0xffff0000;
+
+retry:
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			addr_mask = PCI_BASE_ADDRESS_IO_MASK;
+			upper_limit = &pciauto_upper_iospc;
+			lower_limit = &pciauto_lower_iospc;
+			DBG("        I/O");
+		} else {
+			if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			    PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
+			upper_limit = &pciauto_upper_memspc;
+			lower_limit = &pciauto_lower_memspc;
+			DBG("        Mem");
+		}
+
+
+		/* Calculate requested size */
+		bar_size = ~(bar_response & addr_mask) + 1;
+
+		/* Allocate a base address */
+		bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size;
+
+		if ((bar_value + bar_size) > *upper_limit) {
+			if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+				if (io_resource_inuse->child) {
+					io_resource_inuse = 
+						io_resource_inuse->child;
+					pciauto_lower_iospc = 
+						io_resource_inuse->start;
+					pciauto_upper_iospc = 
+						io_resource_inuse->end + 1;
+					goto retry;
+				}
+
+			} else {
+				if (mem_resource_inuse->child) {
+					mem_resource_inuse = 
+						mem_resource_inuse->child;
+					pciauto_lower_memspc = 
+						mem_resource_inuse->start;
+					pciauto_upper_memspc = 
+						mem_resource_inuse->end + 1;
+					goto retry;
+				}
+			}
+			DBG(" unavailable -- skipping, value %x size %x\n",
+					bar_value, bar_size);
+			continue;
+		}
+
+#ifdef CONFIG_PCI_AUTO_UPDATE_RESOURCES
+		/* Write it out and update our limit */
+		early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+					 bar, bar_value);
+#endif
+
+		*lower_limit = bar_value + bar_size;
+
+		/*
+		 * If we are a 64-bit decoder then increment to the
+		 * upper 32 bits of the bar and force it to locate
+		 * in the lower 4GB of memory.
+		 */ 
+		if (found_mem64) {
+			bar += 4;
+			early_write_config_dword(hose, top_bus,
+						 current_bus,
+						 pci_devfn,
+						 bar,
+						 0x00000000);
+		}
+
+		DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size);
+
+		bar_nr++;
+	}
+
+}
+
+static void __init
+pciauto_prescan_setup_bridge(struct pci_channel *hose,
+			     int top_bus,
+			     int current_bus,
+			     int pci_devfn,
+			     int sub_bus)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+	                        PCI_PRIMARY_BUS, current_bus);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SECONDARY_BUS, sub_bus + 1);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SUBORDINATE_BUS, 0xff);
+
+	/* Align memory and I/O to 1MB and 4KB boundaries. */
+	pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
+		& ~(0x100000 - 1);
+	pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
+		& ~(0x1000 - 1);
+
+	/* Set base (lower limit) of address range behind bridge. */
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+		PCI_MEMORY_BASE, pciauto_lower_memspc >> 16);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+		PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8);
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+		PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16);
+
+	/* We don't support prefetchable memory for now, so disable */
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+				PCI_PREF_MEMORY_BASE, 0);
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+				PCI_PREF_MEMORY_LIMIT, 0);
+}
+
+static void __init
+pciauto_postscan_setup_bridge(struct pci_channel *hose,
+			      int top_bus,
+			      int current_bus,
+			      int pci_devfn,
+			      int sub_bus)
+{
+	u32 temp;
+
+	/*
+	 * [jsun] we always bump up baselines a little, so that if there
+	 * nothing behind P2P bridge, we don't wind up overlapping IO/MEM
+	 * spaces.
+	 */
+	pciauto_lower_memspc += 1;
+	pciauto_lower_iospc += 1;
+
+	/* Configure bus number registers */
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SUBORDINATE_BUS, sub_bus);
+
+	/* Set upper limit of address range behind bridge. */
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+		PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+		PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8);
+	early_write_config_word(hose, top_bus, current_bus, pci_devfn,
+		PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16);
+
+	/* Align memory and I/O to 1MB and 4KB boundaries. */
+	pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1))
+		& ~(0x100000 - 1);
+	pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1))
+		& ~(0x1000 - 1);
+
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_COMMAND, &temp);
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY
+		| PCI_COMMAND_MASTER);
+}
+
+static void __init
+pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose,
+			int top_bus,
+			int current_bus,
+			int pci_devfn,
+			int sub_bus)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_PRIMARY_BUS, current_bus);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SECONDARY_BUS, sub_bus + 1);
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SUBORDINATE_BUS, 0xff);
+
+	/* Align memory and I/O to 4KB and 4 byte boundaries. */
+	pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
+		& ~(0x1000 - 1);
+	pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
+		& ~(0x4 - 1);
+
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc);
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_CB_IO_BASE_0, pciauto_lower_iospc);
+}
+
+static void __init
+pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
+			int top_bus,
+			int current_bus,
+			int pci_devfn,
+			int sub_bus)
+{
+	u32 temp;
+
+#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+	/*
+	 * [jsun] we always bump up baselines a little, so that if there
+	 * nothing behind P2P bridge, we don't wind up overlapping IO/MEM
+	 * spaces.
+	 */
+	pciauto_lower_memspc += 1;
+	pciauto_lower_iospc += 1;
+#endif
+
+	/*
+	 * Configure subordinate bus number.  The PCI subsystem
+	 * bus scan will renumber buses (reserving three additional
+	 * for this PCI<->CardBus bridge for the case where a CardBus
+	 * adapter contains a P2P or CB2CB bridge.
+	 */
+
+	early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+				PCI_SUBORDINATE_BUS, sub_bus);
+
+	/*
+	 * Reserve an additional 4MB for mem space and 16KB for
+	 * I/O space.  This should cover any additional space
+	 * requirement of unusual CardBus devices with
+	 * additional bridges that can consume more address space.
+	 *
+	 * Although pcmcia-cs currently will reprogram bridge
+	 * windows, the goal is to add an option to leave them
+	 * alone and use the bridge window ranges as the regions
+	 * that are searched for free resources upon hot-insertion
+	 * of a device.  This will allow a PCI<->CardBus bridge
+	 * configured by this routine to happily live behind a
+	 * P2P bridge in a system.
+	 */
+#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
+	pciauto_lower_memspc += 0x00400000;
+	pciauto_lower_iospc += 0x00004000;
+#endif
+
+	/* Align memory and I/O to 4KB and 4 byte boundaries. */
+	pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
+		& ~(0x1000 - 1);
+	pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1))
+		& ~(0x4 - 1);
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1);
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1);
+
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_COMMAND, &temp);
+	early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+		PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		PCI_COMMAND_MASTER);
+}
+
+#define	PCIAUTO_IDE_MODE_MASK		0x05
+
+static int __init
+pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
+{
+	int sub_bus;
+	u32 pci_devfn, pci_class, cmdstat, found_multi=0;
+	unsigned short vid, did;
+	unsigned char header_type;
+	int devfn_start = 0;
+	int devfn_stop = 0xff;
+
+	sub_bus = current_bus;
+	
+	if (hose->first_devfn)
+		devfn_start = hose->first_devfn;
+	if (hose->last_devfn)
+		devfn_stop = hose->last_devfn;
+	
+	for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) {
+
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		early_read_config_word(hose, top_bus, current_bus, pci_devfn,
+				       PCI_VENDOR_ID, &vid);
+
+		if (vid == 0xffff) continue;
+
+		early_read_config_byte(hose, top_bus, current_bus, pci_devfn,
+				       PCI_HEADER_TYPE, &header_type);
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		early_read_config_word(hose, top_bus, current_bus, pci_devfn,
+				       PCI_DEVICE_ID, &did);
+
+		early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
+					PCI_CLASS_REVISION, &pci_class);
+
+		DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x",
+			current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn),
+			pci_class >> 16, vid, did);
+		if (pci_class & 0xff)
+			DBG(" (rev %.2x)", pci_class & 0xff);
+		DBG("\n");
+
+		if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+			DBG("        Bridge: primary=%.2x, secondary=%.2x\n",
+				current_bus, sub_bus + 1);
+#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
+			pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1);
+#endif
+			pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
+						     pci_devfn, sub_bus);
+			DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
+				sub_bus + 1,
+				pciauto_lower_iospc, pciauto_lower_memspc);
+			sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
+			DBG("Back to bus %.2x\n", current_bus);
+			pciauto_postscan_setup_bridge(hose, top_bus, current_bus,
+							pci_devfn, sub_bus);
+			continue;
+		} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
+			DBG("  CARDBUS  Bridge: primary=%.2x, secondary=%.2x\n",
+				current_bus, sub_bus + 1);
+			DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
+			/* Place CardBus Socket/ExCA registers */
+			pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0);
+ 
+			pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
+					current_bus, pci_devfn, sub_bus);
+ 
+			DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
+				sub_bus + 1,
+				pciauto_lower_iospc, pciauto_lower_memspc);
+			sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1);
+			DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus);
+			pciauto_postscan_setup_cardbus_bridge(hose, top_bus,
+					current_bus, pci_devfn, sub_bus);
+			continue;
+		} else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+
+			unsigned char prg_iface;
+
+			early_read_config_byte(hose, top_bus, current_bus,
+				pci_devfn, PCI_CLASS_PROG, &prg_iface);
+			if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+				DBG("Skipping legacy mode IDE controller\n");
+				continue;
+			}
+		}
+
+		/*
+		 * Found a peripheral, enable some standard
+		 * settings
+		 */
+		early_read_config_dword(hose, top_bus, current_bus, pci_devfn,
+					PCI_COMMAND, &cmdstat);
+		early_write_config_dword(hose, top_bus, current_bus, pci_devfn,
+					 PCI_COMMAND, cmdstat | PCI_COMMAND_IO |
+					 PCI_COMMAND_MEMORY |
+					 PCI_COMMAND_MASTER);
+#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
+		early_write_config_byte(hose, top_bus, current_bus, pci_devfn,
+					PCI_LATENCY_TIMER, 0x80);
+#endif
+
+		/* Allocate PCI I/O and/or memory space */
+		pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5);
+	}
+	return sub_bus;
+}
+
+int __init
+pciauto_assign_resources(int busno, struct pci_channel *hose)
+{
+	/* setup resource limits */
+	io_resource_inuse = hose->io_resource;
+	mem_resource_inuse = hose->mem_resource;
+
+	pciauto_lower_iospc = io_resource_inuse->start;
+	pciauto_upper_iospc = io_resource_inuse->end + 1;
+	pciauto_lower_memspc = mem_resource_inuse->start;
+	pciauto_upper_memspc = mem_resource_inuse->end + 1;
+	DBG("Autoconfig PCI channel 0x%p\n", hose);
+	DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n",
+		busno, pciauto_lower_iospc, pciauto_upper_iospc, 
+		pciauto_lower_memspc, pciauto_upper_memspc);
+
+	return pciauto_bus_scan(hose, busno, busno);
+}
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
new file mode 100644
index 0000000..30b14ac
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -0,0 +1,417 @@
+/*
+ *	Low-Level PCI Support for the SH7751
+ *
+ *  Dustin McIntire (dustin@sensoria.com)
+ *	Derived from arch/i386/kernel/pci-*.c which bore the message:
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *
+ *  Ported to the new API by Paul Mundt <lethal@linux-sh.org>
+ *  With cleanup by Paul van Gool <pvangool@mimotech.com>
+ *
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+ */
+
+#undef DEBUG
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include "pci-sh7751.h"
+
+static unsigned int pci_probe = PCI_PROBE_CONF1;
+extern int pci_fixup_pcic(void);
+
+void pcibios_fixup_irqs(void) __attribute__ ((weak));
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn,
+			   int where, int size, u32 *val)
+{
+	unsigned long flags;
+	u32 data;
+
+	/* 
+	 * PCIPDR may only be accessed as 32 bit words, 
+	 * so we must do byte alignment by hand 
+	 */
+	local_irq_save(flags);
+	outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
+	data = inl(PCI_REG(SH7751_PCIPDR));
+	local_irq_restore(flags);
+
+	switch (size) {
+	case 1:
+		*val = (data >> ((where & 3) << 3)) & 0xff;
+		break;
+	case 2:
+		*val = (data >> ((where & 2) << 3)) & 0xffff;
+		break;
+	case 4:
+		*val = data;
+		break;
+	default:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* 
+ * Since SH7751 only does 32bit access we'll have to do a read,
+ * mask,write operation.
+ * We'll allow an odd byte offset, though it should be illegal.
+ */ 
+static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn,
+			    int where, int size, u32 val)
+{
+	unsigned long flags;
+	int shift;
+	u32 data;
+
+	local_irq_save(flags);
+	outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
+	data = inl(PCI_REG(SH7751_PCIPDR));
+	local_irq_restore(flags);
+
+	switch (size) {
+	case 1:
+		shift = (where & 3) << 3;
+		data &= ~(0xff << shift);
+		data |= ((val & 0xff) << shift);
+		break;
+	case 2:
+		shift = (where & 2) << 3;
+		data &= ~(0xffff << shift);
+		data |= ((val & 0xffff) << shift);
+		break;
+	case 4:
+		data = val;
+		break;
+	default:
+		return PCIBIOS_FUNC_NOT_SUPPORTED;
+	}
+
+	outl(data, PCI_REG(SH7751_PCIPDR));
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+struct pci_ops sh7751_pci_ops = {
+	.read 		= sh7751_pci_read,
+	.write		= sh7751_pci_write,
+};
+
+static int __init pci_check_direct(void)
+{
+	unsigned int tmp, id;
+
+	/* check for SH7751/SH7751R hardware */
+	id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0);
+	if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
+	    id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
+		pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
+		return -ENODEV;
+	}
+
+	/*
+	 * Check if configuration works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF1) {
+		tmp = inl (PCI_REG(SH7751_PCIPAR));
+		outl (0x80000000, PCI_REG(SH7751_PCIPAR));
+		if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
+			outl (tmp, PCI_REG(SH7751_PCIPAR));
+			printk(KERN_INFO "PCI: Using configuration type 1\n");
+			request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
+			return 0;
+		}
+		outl (tmp, PCI_REG(SH7751_PCIPAR));
+	}
+
+	pr_debug("PCI: pci_check_direct failed\n");
+	return -EINVAL;
+}
+
+/***************************************************************************************/
+
+/*
+ *  Handle bus scanning and fixups ....
+ */
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space.
+ * 
+ * Note that the platform specific initialization (BSC registers, and memory
+ * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
+ * exitst and via the platform defined function pcibios_init_platform().  
+ * See pci_bigsur.c for implementation;
+ * 
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness.  Currently an error will be genereated at compile time. 
+ */
+
+static int __init sh7751_pci_init(void)
+{
+	int ret;
+
+	pr_debug("PCI: Starting intialization.\n");
+	if ((ret = pci_check_direct()) != 0)
+		return ret;
+
+	return pcibios_init_platform();
+}
+
+subsys_initcall(sh7751_pci_init);
+
+static int __init __area_sdram_check(unsigned int area)
+{
+	u32 word;
+
+	word = inl(SH7751_BCR1);
+	/* check BCR for SDRAM in area */
+	if(((word >> area) & 1) == 0) {
+		printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n",
+		       area, word);
+		return 0;
+	}
+	outl(word, PCI_REG(SH7751_PCIBCR1));
+
+	word = (u16)inw(SH7751_BCR2);
+	/* check BCR2 for 32bit SDRAM interface*/
+	if(((word >> (area << 1)) & 0x3) != 0x3) {
+		printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n",
+		       area, word);
+		return 0;
+	}
+	outl(word, PCI_REG(SH7751_PCIBCR2));
+
+	return 1;
+}
+
+int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
+{
+	u32 reg;
+	u32 word;
+
+	/* Set the BCR's to enable PCI access */
+	reg = inl(SH7751_BCR1);
+	reg |= 0x80000;
+	outl(reg, SH7751_BCR1);
+	
+	/* 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_PCIPINT));
+
+	/*
+	 * This code is unused for some boards as it is done in the
+	 * bootloader and doing it here means the MAC addresses loaded
+	 * by the bootloader get lost.
+	 */
+	if (!(map->flags & SH7751_PCIC_NO_RESET)) {
+		/* 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 = map->window0.size @ non-cached area base = SDRAM
+	 * Window1 = map->window1.size @ cached area base = SDRAM 
+	 */
+	word = map->window0.size - 1;
+	outl(word, PCI_REG(SH7751_PCILSR0));
+	word = map->window1.size - 1;
+	outl(word, PCI_REG(SH7751_PCILSR1));
+	/* Set the values on window 0 PCI config registers */
+	word = P2SEGADDR(map->window0.base);
+	outl(word, PCI_REG(SH7751_PCILAR0));
+	outl(word, PCI_REG(SH7751_PCICONF5));
+	/* Set the values on window 1 PCI config registers */
+	word =  PHYSADDR(map->window1.base);
+	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);
+
+	/* 
+	 * XXX: For now, leave this board-specific. In the event we have other
+	 * boards that need to do similar work, this can be wrapped.
+	 */
+#ifdef CONFIG_SH_BIGSUR
+	bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
+#endif
+
+	/* 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 */
+
+	/* check BCR for SDRAM in specified area */
+	switch (map->window0.base) {
+	case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break;
+	case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break;
+	case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break;
+	case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break;
+	case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break;
+	case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break;
+	case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break;
+	}
+	
+	if (!word)
+		return 0;
+
+	/* 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...
+	 */
+
+#ifdef CONFIG_SH_RTS7751R2D
+	pci_fixup_pcic();
+#endif
+
+	/* SH7751 init done, set central function init complete */
+	/* use round robin mode to stop a device starving/overruning */
+	word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM;
+	outl(word,PCI_REG(SH7751_PCICR)); 
+
+	return 1;
+}
+
+char * __init pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+
+	return str;
+}
+
+/* 
+ * 	IRQ functions 
+ */
+static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	/* no swizzling */
+	return PCI_SLOT(dev->devfn);
+}
+
+static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq = -1;
+
+	/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+	irq = pcibios_map_platform_irq(slot,pin);
+	if( irq < 0 ) {
+		pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
+		return irq;
+	}
+
+	pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
+
+	return irq;
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+	pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq);
+}
+
diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h
new file mode 100644
index 0000000..1fee5ca
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh7751.h
@@ -0,0 +1,303 @@
+/*
+ *	Low-Level PCI Support for SH7751 targets
+ *
+ *  Dustin McIntire (dustin@sensoria.com) (c) 2001
+ *  Paul Mundt (lethal@linux-sh.org) (c) 2003
+ *	
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+ */
+
+#ifndef _PCI_SH7751_H_
+#define _PCI_SH7751_H_
+
+#include <linux/pci.h>
+
+/* set debug level 4=verbose...1=terse */
+//#define DEBUG_PCI 3
+#undef DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
+#else
+#define PCIDBG(n, x...)
+#endif
+
+/* startup values */
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_BIOS_IRQ_SCAN 0x2000
+
+/* Platform Specific Values */
+#define SH7751_VENDOR_ID             0x1054
+#define SH7751_DEVICE_ID             0x3505
+#define SH7751R_DEVICE_ID            0x350e
+
+/* SH7751 Specific Values */
+#define SH7751_PCI_CONFIG_BASE	     0xFD000000  /* Config space base addr */
+#define SH7751_PCI_CONFIG_SIZE       0x1000000   /* Config space size */
+#define SH7751_PCI_MEMORY_BASE	     0xFD000000  /* Memory space base addr */
+#define SH7751_PCI_MEM_SIZE          0x01000000  /* Size of Memory window */
+#define SH7751_PCI_IO_BASE           0xFE240000  /* IO space base address */
+#define SH7751_PCI_IO_SIZE           0x40000     /* Size of IO window */
+
+#define SH7751_PCIREG_BASE           0xFE200000  /* PCI regs base address */
+#define PCI_REG(n)                  (SH7751_PCIREG_BASE+ n)
+
+#define SH7751_PCICONF0            0x0           /* PCI Config Reg 0 */
+  #define SH7751_PCICONF0_DEVID      0xFFFF0000  /* Device ID */
+  #define SH7751_PCICONF0_VNDID      0x0000FFFF  /* Vendor ID */
+#define SH7751_PCICONF1            0x4           /* PCI Config Reg 1 */
+  #define SH7751_PCICONF1_DPE        0x80000000  /* Data Parity Error */
+  #define SH7751_PCICONF1_SSE        0x40000000  /* System Error Status */
+  #define SH7751_PCICONF1_RMA        0x20000000  /* Master Abort */
+  #define SH7751_PCICONF1_RTA        0x10000000  /* Target Abort Rx Status */
+  #define SH7751_PCICONF1_STA        0x08000000  /* Target Abort Exec Status */
+  #define SH7751_PCICONF1_DEV        0x06000000  /* Timing Status */
+  #define SH7751_PCICONF1_DPD        0x01000000  /* Data Parity Status */
+  #define SH7751_PCICONF1_FBBC       0x00800000  /* Back 2 Back Status */
+  #define SH7751_PCICONF1_UDF        0x00400000  /* User Defined Status */
+  #define SH7751_PCICONF1_66M        0x00200000  /* 66Mhz Operation Status */
+  #define SH7751_PCICONF1_PM         0x00100000  /* Power Management Status */
+  #define SH7751_PCICONF1_PBBE       0x00000200  /* Back 2 Back Control */
+  #define SH7751_PCICONF1_SER        0x00000100  /* SERR Output Control */
+  #define SH7751_PCICONF1_WCC        0x00000080  /* Wait Cycle Control */
+  #define SH7751_PCICONF1_PER        0x00000040  /* Parity Error Response */
+  #define SH7751_PCICONF1_VPS        0x00000020  /* VGA Pallet Snoop */
+  #define SH7751_PCICONF1_MWIE       0x00000010  /* Memory Write+Invalidate */
+  #define SH7751_PCICONF1_SPC        0x00000008  /* Special Cycle Control */
+  #define SH7751_PCICONF1_BUM        0x00000004  /* Bus Master Control */
+  #define SH7751_PCICONF1_MES        0x00000002  /* Memory Space Control */
+  #define SH7751_PCICONF1_IOS        0x00000001  /* I/O Space Control */
+#define SH7751_PCICONF2            0x8           /* PCI Config Reg 2 */
+  #define SH7751_PCICONF2_BCC        0xFF000000  /* Base Class Code */
+  #define SH7751_PCICONF2_SCC        0x00FF0000  /* Sub-Class Code */
+  #define SH7751_PCICONF2_RLPI       0x0000FF00  /* Programming Interface */
+  #define SH7751_PCICONF2_REV        0x000000FF  /* Revision ID */
+#define SH7751_PCICONF3            0xC           /* PCI Config Reg 3 */ 
+  #define SH7751_PCICONF3_BIST7      0x80000000  /* Bist Supported */
+  #define SH7751_PCICONF3_BIST6      0x40000000  /* Bist Executing */
+  #define SH7751_PCICONF3_BIST3_0    0x0F000000  /* Bist Passed */
+  #define SH7751_PCICONF3_HD7        0x00800000  /* Single Funtion device */
+  #define SH7751_PCICONF3_HD6_0      0x007F0000  /* Configuration Layout */
+  #define SH7751_PCICONF3_LAT        0x0000FF00  /* Latency Timer */
+  #define SH7751_PCICONF3_CLS        0x000000FF  /* Cache Line Size */
+#define SH7751_PCICONF4            0x10          /* PCI Config Reg 4 */
+  #define SH7751_PCICONF4_BASE       0xFFFFFFFC  /* I/O Space Base Addr */
+  #define SH7751_PCICONF4_ASI        0x00000001  /* Address Space Type */
+#define SH7751_PCICONF5            0x14          /* PCI Config Reg 5 */
+  #define SH7751_PCICONF5_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF5_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF5_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF5_ASI        0x00000001  /* Address Space Type */  
+#define SH7751_PCICONF6            0x18          /* PCI Config Reg 6 */
+  #define SH7751_PCICONF6_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF6_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF6_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF6_ASI        0x00000001  /* Address Space Type */  
+/* PCICONF7 - PCICONF10 are undefined */
+#define SH7751_PCICONF11           0x2C          /* PCI Config Reg 11 */
+  #define SH7751_PCICONF11_SSID      0xFFFF0000  /* Subsystem ID */
+  #define SH7751_PCICONF11_SVID      0x0000FFFF  /* Subsystem Vendor ID */
+/* PCICONF12 is undefined */
+#define SH7751_PCICONF13           0x34          /* PCI Config Reg 13 */
+  #define SH7751_PCICONF13_CPTR      0x000000FF  /* PM function pointer */
+/* PCICONF14 is undefined */
+#define SH7751_PCICONF15           0x3C          /* PCI Config Reg 15 */
+  #define SH7751_PCICONF15_IPIN      0x000000FF  /* Interrupt Pin */
+#define SH7751_PCICONF16           0x40          /* PCI Config Reg 16 */
+  #define SH7751_PCICONF16_PMES      0xF8000000  /* PME Support */
+  #define SH7751_PCICONF16_D2S       0x04000000  /* D2 Support */
+  #define SH7751_PCICONF16_D1S       0x02000000  /* D1 Support */
+  #define SH7751_PCICONF16_DSI       0x00200000  /* Bit Device Init. */
+  #define SH7751_PCICONF16_PMCK      0x00080000  /* Clock for PME req. */
+  #define SH7751_PCICONF16_VER       0x00070000  /* PM Version */
+  #define SH7751_PCICONF16_NIP       0x0000FF00  /* Next Item Pointer */
+  #define SH7751_PCICONF16_CID       0x000000FF  /* Capability Identifier */
+#define SH7751_PCICONF17           0x44          /* PCI Config Reg 17 */
+  #define SH7751_PCICONF17_DATA      0xFF000000  /* Data field for PM */
+  #define SH7751_PCICONF17_PMES      0x00800000  /* PME Status */
+  #define SH7751_PCICONF17_DSCL      0x00600000  /* Data Scaling Value */
+  #define SH7751_PCICONF17_DSEL      0x001E0000  /* Data Select */
+  #define SH7751_PCICONF17_PMEN      0x00010000  /* PME Enable */
+  #define SH7751_PCICONF17_PWST      0x00000003  /* Power State */
+/* SH7715 Internal PCI Registers */
+#define SH7751_PCICR               0x100         /* PCI Control Register */
+  #define SH7751_PCICR_PREFIX        0xA5000000  /* CR prefix for write */
+  #define SH7751_PCICR_TRSB          0x00000200  /* Target Read Single */
+  #define SH7751_PCICR_BSWP          0x00000100  /* Target Byte Swap */
+  #define SH7751_PCICR_PLUP          0x00000080  /* Enable PCI Pullup */
+  #define SH7751_PCICR_ARBM          0x00000040  /* PCI Arbitration Mode */
+  #define SH7751_PCICR_MD            0x00000030  /* MD9 and MD10 status */
+  #define SH7751_PCICR_SERR          0x00000008  /* SERR output assert */
+  #define SH7751_PCICR_INTA          0x00000004  /* INTA output assert */
+  #define SH7751_PCICR_PRST          0x00000002  /* PCI Reset Assert */
+  #define SH7751_PCICR_CFIN          0x00000001  /* Central Fun. Init Done */
+#define SH7751_PCILSR0             0x104         /* PCI Local Space Register0 */
+#define SH7751_PCILSR1             0x108         /* PCI Local Space Register1 */
+#define SH7751_PCILAR0             0x10C         /* PCI Local Address Register1 */
+#define SH7751_PCILAR1             0x110         /* PCI Local Address Register1 */
+#define SH7751_PCIINT              0x114         /* PCI Interrupt Register */
+  #define SH7751_PCIINT_MLCK         0x00008000  /* Master Lock Error */
+  #define SH7751_PCIINT_TABT         0x00004000  /* Target Abort Error */
+  #define SH7751_PCIINT_TRET         0x00000200  /* Target Retry Error */
+  #define SH7751_PCIINT_MFDE         0x00000100  /* Master Func. Disable Error */
+  #define SH7751_PCIINT_PRTY         0x00000080  /* Address Parity Error */
+  #define SH7751_PCIINT_SERR         0x00000040  /* SERR Detection Error */
+  #define SH7751_PCIINT_TWDP         0x00000020  /* Tgt. Write Parity Error */
+  #define SH7751_PCIINT_TRDP         0x00000010  /* Tgt. Read Parity Error Det. */
+  #define SH7751_PCIINT_MTABT        0x00000008  /* Master-Tgt. Abort Error */
+  #define SH7751_PCIINT_MMABT        0x00000004  /* Master-Master Abort Error */
+  #define SH7751_PCIINT_MWPD         0x00000002  /* Master Write PERR Detect */
+  #define SH7751_PCIINT_MRPD         0x00000002  /* Master Read PERR Detect */
+#define SH7751_PCIINTM             0x118         /* PCI Interrupt Mask Register */
+#define SH7751_PCIALR              0x11C         /* Error Address Register */
+#define SH7751_PCICLR              0x120         /* Error Command/Data Register */
+  #define SH7751_PCICLR_MPIO         0x80000000  /* Error Command/Data Register */
+  #define SH7751_PCICLR_MDMA0        0x40000000  /* DMA0 Transfer Error */
+  #define SH7751_PCICLR_MDMA1        0x20000000  /* DMA1 Transfer Error */
+  #define SH7751_PCICLR_MDMA2        0x10000000  /* DMA2 Transfer Error */
+  #define SH7751_PCICLR_MDMA3        0x08000000  /* DMA3 Transfer Error */
+  #define SH7751_PCICLR_TGT          0x04000000  /* Target Transfer Error */
+  #define SH7751_PCICLR_CMDL         0x0000000F  /* PCI Command at Error */
+#define SH7751_PCIAINT             0x130         /* Arbiter Interrupt Register */
+  #define SH7751_PCIAINT_MBKN        0x00002000  /* Master Broken Interrupt */
+  #define SH7751_PCIAINT_TBTO        0x00001000  /* Target Bus Time Out */
+  #define SH7751_PCIAINT_MBTO        0x00001000  /* Master Bus Time Out */
+  #define SH7751_PCIAINT_TABT        0x00000008  /* Target Abort */
+  #define SH7751_PCIAINT_MABT        0x00000004  /* Master Abort */
+  #define SH7751_PCIAINT_RDPE        0x00000002  /* Read Data Parity Error */
+  #define SH7751_PCIAINT_WDPE        0x00000002  /* Write Data Parity Error */
+#define SH7751_PCIAINTM            0x134         /* Arbiter Int. Mask Register */
+#define SH7751_PCIBMLR             0x138         /* Error Bus Master Register */
+  #define SH7751_PCIBMLR_REQ4        0x00000010  /* REQ4 bus master at error */
+  #define SH7751_PCIBMLR_REQ3        0x00000008  /* REQ3 bus master at error */
+  #define SH7751_PCIBMLR_REQ2        0x00000004  /* REQ2 bus master at error */
+  #define SH7751_PCIBMLR_REQ1        0x00000002  /* REQ1 bus master at error */
+  #define SH7751_PCIBMLR_REQ0        0x00000001  /* REQ0 bus master at error */
+#define SH7751_PCIDMABT            0x140         /* DMA Transfer Arb. Register */
+  #define SH7751_PCIDMABT_RRBN       0x00000001  /* DMA Arbitor Round-Robin */
+#define SH7751_PCIDPA0             0x180         /* DMA0 Transfer Addr. Register */
+#define SH7751_PCIDLA0             0x184         /* DMA0 Local Addr. Register */
+#define SH7751_PCIDTC0             0x188         /* DMA0 Transfer Cnt. Register */
+#define SH7751_PCIDCR0             0x18C         /* DMA0 Control Register */
+  #define SH7751_PCIDCR_ALGN         0x00000600  /* DMA Alignment Mode */
+  #define SH7751_PCIDCR_MAST         0x00000100  /* DMA Termination Type */
+  #define SH7751_PCIDCR_INTM         0x00000080  /* DMA Interrupt Done Mask*/
+  #define SH7751_PCIDCR_INTS         0x00000040  /* DMA Interrupt Done Status */
+  #define SH7751_PCIDCR_LHLD         0x00000020  /* Local Address Control */
+  #define SH7751_PCIDCR_PHLD         0x00000010  /* PCI Address Control*/
+  #define SH7751_PCIDCR_IOSEL        0x00000008  /* PCI Address Space Type */
+  #define SH7751_PCIDCR_DIR          0x00000004  /* DMA Transfer Direction */
+  #define SH7751_PCIDCR_STOP         0x00000002  /* Force DMA Stop */
+  #define SH7751_PCIDCR_STRT         0x00000001  /* DMA Start */
+#define SH7751_PCIDPA1             0x190         /* DMA1 Transfer Addr. Register */
+#define SH7751_PCIDLA1             0x194         /* DMA1 Local Addr. Register */
+#define SH7751_PCIDTC1             0x198         /* DMA1 Transfer Cnt. Register */
+#define SH7751_PCIDCR1             0x19C         /* DMA1 Control Register */
+#define SH7751_PCIDPA2             0x1A0         /* DMA2 Transfer Addr. Register */
+#define SH7751_PCIDLA2             0x1A4         /* DMA2 Local Addr. Register */
+#define SH7751_PCIDTC2             0x1A8         /* DMA2 Transfer Cnt. Register */
+#define SH7751_PCIDCR2             0x1AC         /* DMA2 Control Register */
+#define SH7751_PCIDPA3             0x1B0         /* DMA3 Transfer Addr. Register */
+#define SH7751_PCIDLA3             0x1B4         /* DMA3 Local Addr. Register */
+#define SH7751_PCIDTC3             0x1B8         /* DMA3 Transfer Cnt. Register */
+#define SH7751_PCIDCR3             0x1BC         /* DMA3 Control Register */
+#define SH7751_PCIPAR              0x1C0         /* PIO Address Register */
+  #define SH7751_PCIPAR_CFGEN        0x80000000  /* Configuration Enable */
+  #define SH7751_PCIPAR_BUSNO        0x00FF0000  /* Config. Bus Number */
+  #define SH7751_PCIPAR_DEVNO        0x0000FF00  /* Config. Device Number */
+  #define SH7751_PCIPAR_REGAD        0x000000FC  /* Register Address Number */
+#define SH7751_PCIMBR              0x1C4         /* Memory Base Address Register */
+  #define SH7751_PCIMBR_MASK         0xFF000000  /* Memory Space Mask */
+  #define SH7751_PCIMBR_LOCK         0x00000001  /* Lock Memory Space */
+#define SH7751_PCIIOBR             0x1C8         /* I/O Base Address Register */
+  #define SH7751_PCIIOBR_MASK         0xFFFC0000 /* IO Space Mask */
+  #define SH7751_PCIIOBR_LOCK         0x00000001 /* Lock IO Space */
+#define SH7751_PCIPINT             0x1CC         /* Power Mgmnt Int. Register */
+  #define SH7751_PCIPINT_D3           0x00000002 /* D3 Pwr Mgmt. Interrupt */
+  #define SH7751_PCIPINT_D0           0x00000001 /* D0 Pwr Mgmt. Interrupt */  
+#define SH7751_PCIPINTM            0x1D0         /* Power Mgmnt Mask Register */
+#define SH7751_PCICLKR             0x1D4         /* Clock Ctrl. Register */
+  #define SH7751_PCICLKR_PCSTP        0x00000002 /* PCI Clock Stop */
+  #define SH7751_PCICLKR_BCSTP        0x00000002 /* BCLK Clock Stop */
+/* For definitions of BCR, MCR see ... */
+#define SH7751_PCIBCR1             0x1E0         /* Memory BCR1 Register */
+#define SH7751_PCIBCR2             0x1E4         /* Memory BCR2 Register */
+#define SH7751_PCIWCR1             0x1E8         /* Wait Control 1 Register */
+#define SH7751_PCIWCR2             0x1EC         /* Wait Control 2 Register */
+#define SH7751_PCIWCR3             0x1F0         /* Wait Control 3 Register */
+#define SH7751_PCIMCR              0x1F4         /* Memory Control Register */
+#define SH7751_PCIBCR3		   0x1f8	 /* Memory BCR3 Register */
+#define SH7751_PCIPCTR             0x200         /* Port Control Register */
+  #define SH7751_PCIPCTR_P2EN        0x000400000 /* Port 2 Enable */
+  #define SH7751_PCIPCTR_P1EN        0x000200000 /* Port 1 Enable */
+  #define SH7751_PCIPCTR_P0EN        0x000100000 /* Port 0 Enable */
+  #define SH7751_PCIPCTR_P2UP        0x000000020 /* Port2 Pull Up Enable */
+  #define SH7751_PCIPCTR_P2IO        0x000000010 /* Port2 Output Enable */
+  #define SH7751_PCIPCTR_P1UP        0x000000008 /* Port1 Pull Up Enable */
+  #define SH7751_PCIPCTR_P1IO        0x000000004 /* Port1 Output Enable */
+  #define SH7751_PCIPCTR_P0UP        0x000000002 /* Port0 Pull Up Enable */
+  #define SH7751_PCIPCTR_P0IO        0x000000001 /* Port0 Output Enable */
+#define SH7751_PCIPDTR             0x204         /* Port Data Register */
+  #define SH7751_PCIPDTR_PB5         0x000000020 /* Port 5 Enable */
+  #define SH7751_PCIPDTR_PB4         0x000000010 /* Port 4 Enable */
+  #define SH7751_PCIPDTR_PB3         0x000000008 /* Port 3 Enable */
+  #define SH7751_PCIPDTR_PB2         0x000000004 /* Port 2 Enable */
+  #define SH7751_PCIPDTR_PB1         0x000000002 /* Port 1 Enable */
+  #define SH7751_PCIPDTR_PB0         0x000000001 /* Port 0 Enable */
+#define SH7751_PCIPDR              0x220         /* Port IO Data Register */
+
+/* Memory Control Registers */
+#define SH7751_BCR1                0xFF800000    /* Memory BCR1 Register */
+#define SH7751_BCR2                0xFF800004    /* Memory BCR2 Register */
+#define SH7751_BCR3                0xFF800050    /* Memory BCR3 Register */
+#define SH7751_BCR4                0xFE0A00F0    /* Memory BCR4 Register */
+#define SH7751_WCR1                0xFF800008    /* Wait Control 1 Register */
+#define SH7751_WCR2                0xFF80000C    /* Wait Control 2 Register */
+#define SH7751_WCR3                0xFF800010    /* Wait Control 3 Register */
+#define SH7751_MCR                 0xFF800014    /* Memory Control Register */
+
+/* General Memory Config Addresses */
+#define SH7751_CS0_BASE_ADDR       0x0
+#define SH7751_MEM_REGION_SIZE     0x04000000
+#define SH7751_CS1_BASE_ADDR       (SH7751_CS0_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS2_BASE_ADDR       (SH7751_CS1_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS3_BASE_ADDR       (SH7751_CS2_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS4_BASE_ADDR       (SH7751_CS3_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS5_BASE_ADDR       (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS6_BASE_ADDR       (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+
+/* General PCI values */
+#define SH7751_PCI_HOST_BRIDGE		0x6
+
+/* Flags */
+#define SH7751_PCIC_NO_RESET	0x0001
+
+/* External functions defined per platform i.e. Big Sur, SE... (these could be routed 
+ * through the machine vectors... */
+extern int pcibios_init_platform(void);
+extern int pcibios_map_platform_irq(u8 slot, u8 pin);
+
+struct sh7751_pci_address_space {
+	unsigned long base;
+	unsigned long size;
+};
+
+struct sh7751_pci_address_map {
+	struct sh7751_pci_address_space window0;
+	struct sh7751_pci_address_space window1;
+	unsigned long flags;
+};
+
+/* arch/sh/drivers/pci/pci-sh7751.c */
+extern int sh7751_pcic_init(struct sh7751_pci_address_map *map);
+
+#endif /* _PCI_SH7751_H_ */
+
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
new file mode 100644
index 0000000..cb67521
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -0,0 +1,509 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Support functions for the ST40 PCI hardware.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <asm/pci.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>	/* irqreturn_t */
+
+#include "pci-st40.h"
+
+/* This is in P2 of course */
+#define ST40PCI_BASE_ADDRESS     (0xb0000000)
+#define ST40PCI_MEM_ADDRESS      (ST40PCI_BASE_ADDRESS+0x0)
+#define ST40PCI_IO_ADDRESS       (ST40PCI_BASE_ADDRESS+0x06000000)
+#define ST40PCI_REG_ADDRESS      (ST40PCI_BASE_ADDRESS+0x07000000)
+
+#define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x))
+#define ST40PCI_REG_INDEXED(reg, index) 				\
+	(ST40PCI_REG(reg##0) +					\
+	  ((ST40PCI_REG(reg##1) - ST40PCI_REG(reg##0))*index))
+
+#define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg))
+#define ST40PCI_WRITE_INDEXED(reg, index, val)				\
+	 writel((val), ST40PCI_REG_INDEXED(reg, index));
+
+#define ST40PCI_READ(reg) readl(ST40PCI_REG(reg))
+#define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg))
+#define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg))
+
+#define ST40PCI_SERR_IRQ	64
+#define ST40PCI_ERR_IRQ        	65
+
+
+/* Macros to extract PLL params */
+#define PLL_MDIV(reg)  ( ((unsigned)reg) & 0xff )
+#define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff )
+#define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 )
+#define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff )
+
+/* Build up the appropriate settings */
+#define PLL_SET(mdiv,ndiv,pdiv,setup) \
+( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19))
+
+#define PLLPCICR (0xbb040000+0x10)
+
+#define PLLPCICR_POWERON (1<<28)
+#define PLLPCICR_OUT_EN (1<<29)
+#define PLLPCICR_LOCKSELECT (1<<30)
+#define PLLPCICR_LOCK (1<<31)
+
+
+#define PLL_25MHZ 0x793c8512
+#define PLL_33MHZ PLL_SET(18,88,3,295)
+
+static void pci_set_rbar_region(unsigned int region,     unsigned long localAddr,
+			 unsigned long pciOffset, unsigned long regionSize);
+
+/*
+ * The pcibios_map_platform_irq function is defined in the appropriate
+ * board specific code and referenced here
+ */
+extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
+
+static __init void SetPCIPLL(void)
+{
+	{
+		/* Lets play with the PLL values */
+		unsigned long pll1cr1;
+		unsigned long mdiv, ndiv, pdiv;
+		unsigned long muxcr;
+		unsigned int muxcr_ratios[4] = { 8, 16, 21, 1 };
+		unsigned int freq;
+
+#define CLKGENA            0xbb040000
+#define CLKGENA_PLL2_MUXCR CLKGENA + 0x48
+		pll1cr1 = ctrl_inl(PLLPCICR);
+		printk("PLL1CR1 %08lx\n", pll1cr1);
+		mdiv = PLL_MDIV(pll1cr1);
+		ndiv = PLL_NDIV(pll1cr1);
+		pdiv = PLL_PDIV(pll1cr1);
+		printk("mdiv %02lx ndiv %02lx pdiv %02lx\n", mdiv, ndiv, pdiv);
+		freq = ((2*27*ndiv)/mdiv) / (1 << pdiv);
+		printk("PLL freq %dMHz\n", freq);
+		muxcr = ctrl_inl(CLKGENA_PLL2_MUXCR);
+		printk("PCI freq %dMhz\n", freq / muxcr_ratios[muxcr & 3]);
+	}
+}
+
+
+struct pci_err {
+  unsigned mask;
+  const char *error_string;
+};
+
+static struct pci_err int_error[]={
+  { INT_MNLTDIM,"MNLTDIM: Master non-lock transfer"},
+  { INT_TTADI,  "TTADI: Illegal byte enable in I/O transfer"},
+  { INT_TMTO,   "TMTO: Target memory read/write timeout"},
+  { INT_MDEI,   "MDEI: Master function disable error"},
+  { INT_APEDI,  "APEDI: Address parity error"},
+  { INT_SDI,    "SDI: SERR detected"},
+  { INT_DPEITW, "DPEITW: Data parity error target write"},
+  { INT_PEDITR, "PEDITR: PERR detected"},
+  { INT_TADIM,  "TADIM: Target abort detected"},
+  { INT_MADIM,  "MADIM: Master abort detected"},
+  { INT_MWPDI,  "MWPDI: PERR from target at data write"},
+  { INT_MRDPEI, "MRDPEI: Master read data parity error"}
+};
+#define NUM_PCI_INT_ERRS (sizeof(int_error)/sizeof(struct pci_err))
+
+static struct pci_err aint_error[]={
+  { AINT_MBI,   "MBI: Master broken"},
+  { AINT_TBTOI, "TBTOI: Target bus timeout"},
+  { AINT_MBTOI, "MBTOI: Master bus timeout"},
+  { AINT_TAI,   "TAI: Target abort"},
+  { AINT_MAI,   "MAI: Master abort"},
+  { AINT_RDPEI, "RDPEI: Read data parity"},
+  { AINT_WDPE,  "WDPE: Write data parity"}
+};
+
+#define NUM_PCI_AINT_ERRS (sizeof(aint_error)/sizeof(struct pci_err))
+
+static void print_pci_errors(unsigned reg,struct pci_err *error,int num_errors)
+{
+  int i;
+
+  for(i=0;i<num_errors;i++) {
+    if(reg & error[i].mask) {
+      printk("%s\n",error[i].error_string);
+    }
+  }
+
+}
+
+
+static char * pci_commands[16]={
+	"Int Ack",
+	"Special Cycle",
+	"I/O Read",
+	"I/O Write",
+	"Reserved",
+	"Reserved",
+	"Memory Read",
+	"Memory Write",
+	"Reserved",
+	"Reserved",
+	"Configuration Read",
+	"Configuration Write",
+	"Memory Read Multiple",
+	"Dual Address Cycle",
+	"Memory Read Line",
+	"Memory Write-and-Invalidate"
+};
+
+static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	unsigned pci_int, pci_air, pci_cir, pci_aint;
+	static int count=0;
+
+
+	pci_int = ST40PCI_READ(INT);pci_aint = ST40PCI_READ(AINT);
+	pci_cir = ST40PCI_READ(CIR);pci_air = ST40PCI_READ(AIR);
+
+	/* Reset state to stop multiple interrupts */
+        ST40PCI_WRITE(INT, ~0); ST40PCI_WRITE(AINT, ~0);
+
+
+	if(++count>1) return IRQ_HANDLED;
+
+	printk("** PCI ERROR **\n");
+
+        if(pci_int) {
+		printk("** INT register status\n");
+		print_pci_errors(pci_int,int_error,NUM_PCI_INT_ERRS);
+	}
+
+        if(pci_aint) {
+		printk("** AINT register status\n");
+		print_pci_errors(pci_aint,aint_error,NUM_PCI_AINT_ERRS);
+	}
+
+	printk("** Address and command info\n");
+
+	printk("** Command  %s : Address 0x%x\n",
+	       pci_commands[pci_cir&0xf],pci_air);
+
+	if(pci_cir&CIR_PIOTEM) {
+		printk("CIR_PIOTEM:PIO transfer error for master\n");
+	}
+        if(pci_cir&CIR_RWTET) {
+		printk("CIR_RWTET:Read/Write transfer error for target\n");
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+/* Rounds a number UP to the nearest power of two. Used for
+ * sizing the PCI window.
+ */
+static u32 r2p2(u32 num)
+{
+	int i = 31;
+	u32 tmp = num;
+
+	if (num == 0)
+		return 0;
+
+	do {
+		if (tmp & (1 << 31))
+			break;
+		i--;
+		tmp <<= 1;
+	} while (i >= 0);
+
+	tmp = 1 << i;
+	/* If the original number isn't a power of 2, round it up */
+	if (tmp != num)
+		tmp <<= 1;
+
+	return tmp;
+}
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	printk("PCI: IDE base address fixup for %s\n", pci_name(d));
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+
+int __init st40pci_init(unsigned memStart, unsigned memSize)
+{
+	u32 lsr0;
+
+	SetPCIPLL();
+
+	/* Initialises the ST40 pci subsystem, performing a reset, then programming
+	 * up the address space decoders appropriately
+	 */
+
+	/* Should reset core here as well methink */
+
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET);
+
+	/* Loop while core resets */
+	while (ST40PCI_READ(CR) & CR_SOFT_RESET);
+
+	/* Switch off interrupts */
+	ST40PCI_WRITE(INTM, 0);
+	ST40PCI_WRITE(AINT, 0);
+
+	/* Now, lets reset all the cards on the bus with extreme prejudice */
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL);
+	udelay(250);
+
+	/* Set bus active, take it out of reset */
+	ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_BMAM | CR_CFINT | CR_PFCS | CR_PFE);
+
+	/* The PCI spec says that no access must be made to the bus until 1 second
+	 * after reset. This seem ludicrously long, but some delay is needed here
+	 */
+	mdelay(1000);
+
+	/* Switch off interrupts */
+	ST40PCI_WRITE(INTM, 0);
+	ST40PCI_WRITE(AINT, 0);
+
+	/* Allow it to be a master */
+
+	ST40PCI_WRITE_SHORT(CSR_CMD,
+			    PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+			    PCI_COMMAND_IO);
+
+	/* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000
+	 * on the PCI bus. This allows a nice 1-1 bus to phys mapping.
+	 */
+
+
+	ST40PCI_WRITE(MBR, 0x10000000);
+	/* Always set the max size 128M (actually, it is only 96MB wide) */
+	ST40PCI_WRITE(MBMR, 0x07ff0000);
+
+	/* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to 
+	 * allow cards that have legacy io such as vga to function correctly. This gives a 
+	 * maximum of 64K of io/space as only the bottom 16 bits of the address are copied 
+	 * over to the bus  when the transaction is made. 64K of io space is more than enough
+	 */
+	ST40PCI_WRITE(IOBR, 0x0);
+	/* Set up the 64K window */
+	ST40PCI_WRITE(IOBMR, 0x0);
+
+	/* Now we set up the mbars so the PCI bus can see the local memory */
+	/* Expose a 256M window starting at PCI address 0... */
+	ST40PCI_WRITE(CSR_MBAR0, 0);
+	ST40PCI_WRITE(LSR0, 0x0fff0001);
+
+	/* ... and set up the initial incomming window to expose all of RAM */
+	pci_set_rbar_region(7, memStart, memStart, memSize);
+
+	/* Maximise timeout values */
+	ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff);
+	ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff);
+	ST40PCI_WRITE_BYTE(CSR_MIT, 0xff);
+
+	ST40PCI_WRITE_BYTE(PERF,PERF_MASTER_WRITE_POSTING);
+
+	return 1;
+}
+
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
+
+
+#define SET_CONFIG_BITS(bus,devfn,where)\
+  (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
+
+#define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where)
+
+
+static int CheckForMasterAbort(void)
+{
+	if (ST40PCI_READ(INT) & INT_MADIM) {
+		/* Should we clear config space version as well ??? */
+		ST40PCI_WRITE(INT, INT_MADIM);
+		ST40PCI_WRITE_SHORT(CSR_STATUS, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Write to config register */
+static int st40pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+	switch (size) {
+		case 1:
+			*val = (u8)ST40PCI_READ_BYTE(PDR + (where & 3));
+			break;
+		case 2:
+			*val = (u16)ST40PCI_READ_SHORT(PDR + (where & 2));
+			break;
+		case 4:
+			*val = ST40PCI_READ(PDR);
+			break;
+	}
+
+	if (CheckForMasterAbort()){
+		switch (size) {
+			case 1:
+				*val = (u8)0xff;
+				break;
+			case 2:
+				*val = (u16)0xffff;
+				break;
+			case 4:
+				*val = 0xffffffff;
+				break;
+		}
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int st40pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
+{
+	ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where));
+
+	switch (size) {
+		case 1:
+			ST40PCI_WRITE_BYTE(PDR + (where & 3), (u8)val);
+			break;
+		case 2:
+			ST40PCI_WRITE_SHORT(PDR + (where & 2), (u16)val);
+			break;
+		case 4:
+			ST40PCI_WRITE(PDR, val);
+			break;
+	}
+
+	CheckForMasterAbort();
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops st40pci_config_ops = {
+	.read = 	st40pci_read,
+	.write = 	st40pci_write,
+};
+
+
+/* Everything hangs off this */
+static struct pci_bus *pci_root_bus;
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+	return PCI_SLOT(dev->devfn);
+}
+
+
+static int __init pcibios_init(void)
+{
+	extern unsigned long memory_start, memory_end;
+
+	printk(KERN_ALERT "pci-st40.c: pcibios_init\n");
+
+	if (sh_mv.mv_init_pci != NULL) {
+		sh_mv.mv_init_pci();
+	}
+
+	/* The pci subsytem needs to know where memory is and how much 
+	 * of it there is. I've simply made these globals. A better mechanism
+	 * is probably needed.
+	 */
+	st40pci_init(PHYSADDR(memory_start),
+		     PHYSADDR(memory_end) - PHYSADDR(memory_start));
+
+	if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, 
+                        SA_INTERRUPT, "st40pci", NULL)) {
+		printk(KERN_ERR "st40pci: Cannot hook interrupt\n");
+		return -EIO;
+	}
+
+	/* Enable the PCI interrupts on the device */
+	ST40PCI_WRITE(INTM, ~0);
+	ST40PCI_WRITE(AINT, ~0);
+
+	/* Map the io address apprioately */
+#ifdef CONFIG_HD64465
+	hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1,
+			 ST40_IO_ADDR + PCIBIOS_MIN_IO, 0);
+#endif
+
+	/* ok, do the scan man */
+	pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL);
+	pci_assign_unassigned_resources();
+	pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq);
+
+	return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+}
+
+/*
+ * Publish a region of local address space over the PCI bus
+ * to other devices.
+ */
+static void pci_set_rbar_region(unsigned int region,     unsigned long localAddr,
+			 unsigned long pciOffset, unsigned long regionSize)
+{
+	unsigned long mask;
+
+	if (region > 7)
+		return;
+
+	if (regionSize > (512 * 1024 * 1024))
+		return;
+
+	mask = r2p2(regionSize) - 0x10000;
+
+	/* Diable the region (in case currently in use, should never happen) */
+	ST40PCI_WRITE_INDEXED(RSR, region, 0);
+
+	/* Start of local address space to publish */
+	ST40PCI_WRITE_INDEXED(RLAR, region, PHYSADDR(localAddr) );
+
+	/* Start of region in PCI address space as an offset from MBAR0 */
+	ST40PCI_WRITE_INDEXED(RBAR, region, pciOffset);
+
+	/* Size of region */
+	ST40PCI_WRITE_INDEXED(RSR, region, mask | 1);
+}
+
diff --git a/arch/sh/drivers/pci/pci-st40.h b/arch/sh/drivers/pci/pci-st40.h
new file mode 100644
index 0000000..d729e0c
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-st40.h
@@ -0,0 +1,136 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Defintions for the ST40 PCI hardware.
+ */
+
+#ifndef __PCI_ST40_H__
+#define __PCI_ST40_H__
+
+#define ST40PCI_VCR_STATUS    0x00
+
+#define ST40PCI_VCR_VERSION   0x08
+
+#define ST40PCI_CR            0x10
+
+#define CR_SOFT_RESET (1<<12)
+#define CR_PFCS       (1<<11)
+#define CR_PFE        (1<<9)
+#define CR_BMAM       (1<<6)
+#define CR_HOST       (1<<5)
+#define CR_CLKEN      (1<<4)
+#define CR_SOCS       (1<<3)
+#define CR_IOCS       (1<<2)
+#define CR_RSTCTL     (1<<1)
+#define CR_CFINT      (1<<0)
+#define CR_LOCK_MASK  0x5a000000
+
+
+#define ST40PCI_LSR0          0X14
+#define ST40PCI_LAR0          0x1c
+
+#define ST40PCI_INT           0x24
+#define INT_MNLTDIM           (1<<15)
+#define INT_TTADI             (1<<14)
+#define INT_TMTO              (1<<9)
+#define INT_MDEI              (1<<8)
+#define INT_APEDI             (1<<7)
+#define INT_SDI               (1<<6)
+#define INT_DPEITW            (1<<5)
+#define INT_PEDITR            (1<<4)
+#define INT_TADIM             (1<<3)
+#define INT_MADIM             (1<<2)
+#define INT_MWPDI             (1<<1)
+#define INT_MRDPEI            (1<<0)
+
+
+#define ST40PCI_INTM          0x28
+#define ST40PCI_AIR           0x2c
+
+#define ST40PCI_CIR           0x30
+#define CIR_PIOTEM            (1<<31)
+#define CIR_RWTET             (1<<26)
+
+#define ST40PCI_AINT          0x40
+#define AINT_MBI              (1<<13)
+#define AINT_TBTOI            (1<<12)
+#define AINT_MBTOI            (1<<11)
+#define AINT_TAI              (1<<3)
+#define AINT_MAI              (1<<2)
+#define AINT_RDPEI            (1<<1)
+#define AINT_WDPE             (1<<0)
+
+#define ST40PCI_AINTM         0x44
+#define ST40PCI_BMIR          0x48
+#define ST40PCI_PAR           0x4c
+#define ST40PCI_MBR           0x50
+#define ST40PCI_IOBR          0x54
+#define ST40PCI_PINT          0x58
+#define ST40PCI_PINTM         0x5c
+#define ST40PCI_MBMR          0x70
+#define ST40PCI_IOBMR         0x74
+#define ST40PCI_PDR           0x78
+
+/* H8 specific registers start here */
+#define ST40PCI_WCBAR         0x7c
+#define ST40PCI_LOCCFG_UNLOCK 0x34
+
+#define ST40PCI_RBAR0         0x100
+#define ST40PCI_RSR0          0x104
+#define ST40PCI_RLAR0         0x108
+
+#define ST40PCI_RBAR1         0x110
+#define ST40PCI_RSR1          0x114
+#define ST40PCI_RLAR1         0x118
+
+
+#define ST40PCI_RBAR2         0x120
+#define ST40PCI_RSR2          0x124
+#define ST40PCI_RLAR2         0x128
+
+#define ST40PCI_RBAR3         0x130
+#define ST40PCI_RSR3          0x134
+#define ST40PCI_RLAR3         0x138
+
+#define ST40PCI_RBAR4         0x140
+#define ST40PCI_RSR4          0x144
+#define ST40PCI_RLAR4         0x148
+
+#define ST40PCI_RBAR5         0x150
+#define ST40PCI_RSR5          0x154
+#define ST40PCI_RLAR5         0x158
+
+#define ST40PCI_RBAR6         0x160
+#define ST40PCI_RSR6          0x164
+#define ST40PCI_RLAR6         0x168
+
+#define ST40PCI_RBAR7         0x170
+#define ST40PCI_RSR7          0x174
+#define ST40PCI_RLAR7         0x178
+
+
+#define ST40PCI_RBAR(n)      (0x100+(0x10*(n)))
+#define ST40PCI_RSR(n)       (0x104+(0x10*(n)))
+#define ST40PCI_RLAR(n)      (0x108+(0x10*(n)))
+
+#define ST40PCI_PERF               0x80
+#define PERF_MASTER_WRITE_POSTING  (1<<4)
+/* H8 specific registers end here */
+
+
+/* These are configs space registers */
+#define ST40PCI_CSR_VID               0x10000
+#define ST40PCI_CSR_DID               0x10002
+#define ST40PCI_CSR_CMD               0x10004
+#define ST40PCI_CSR_STATUS            0x10006
+#define ST40PCI_CSR_MBAR0             0x10010
+#define ST40PCI_CSR_TRDY              0x10040
+#define ST40PCI_CSR_RETRY             0x10041
+#define ST40PCI_CSR_MIT               0x1000d
+
+#define ST40_IO_ADDR 0xb6000000       
+
+#endif /* __PCI_ST40_H__ */
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
new file mode 100644
index 0000000..c166990
--- /dev/null
+++ b/arch/sh/drivers/pci/pci.c
@@ -0,0 +1,155 @@
+/* arch/sh/kernel/pci.c
+ * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $
+ *
+ * Copyright (c) 2002 M. R. Brown  <mrbrown@linux-sh.org>
+ * 
+ * 
+ * These functions are collected here to reduce duplication of common
+ * code amongst the many platform-specific PCI support code files.
+ * 
+ * These routines require the following board-specific routines:
+ * void pcibios_fixup_irqs();
+ *
+ * See include/asm-sh/pci.h for more information.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+static int __init pcibios_init(void)
+{
+	struct pci_channel *p;
+	struct pci_bus *bus;
+	int busno;
+
+#ifdef CONFIG_PCI_AUTO
+	/* assign resources */
+	busno = 0;
+	for (p = board_pci_channels; p->pci_ops != NULL; p++) {
+		busno = pciauto_assign_resources(busno, p) + 1;
+	}
+#endif
+
+	/* scan the buses */
+	busno = 0;
+	for (p= board_pci_channels; p->pci_ops != NULL; p++) {
+		bus = pci_scan_bus(busno, p->pci_ops, p);
+		busno = bus->subordinate+1;
+	}
+
+	/* board-specific fixups */
+	pcibios_fixup_irqs();
+
+	return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= IORESOURCE_ROM_ENABLE;
+		new |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+	
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", pci_name(dev), resource,
+		       new, check);
+	}
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
+			    __attribute__ ((weak));
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size, unsigned long align)
+{
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		if (!(mask & (1 << idx)))
+			continue;
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because "
+			       "of resource collisions\n", pci_name(dev));
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n",
+		       pci_name(dev), old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check and set
+ *  the latency timer as it may not be properly set.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}