diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 15:59:17 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 15:59:17 +0900 |
commit | 5283ecb5ccbdb90d49fce6488d3944bba63a591c (patch) | |
tree | a58e20bd532fa5f933d099bb7b5dd0637b581d33 /arch/sh/drivers | |
parent | d7c30c682a278abe1a52db83f69efec1a9d8f8c2 (diff) |
sh: Add support for R7780RP and R7780MP boards.
This adds support for the Renesas SH7780 development boards,
R7780RP and R7780MP.
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/drivers')
-rw-r--r-- | arch/sh/drivers/dma/Kconfig | 3 | ||||
-rw-r--r-- | arch/sh/drivers/dma/dma-sh.c | 4 | ||||
-rw-r--r-- | arch/sh/drivers/pci/Makefile | 2 | ||||
-rw-r--r-- | arch/sh/drivers/pci/fixups-r7780rp.c | 39 | ||||
-rw-r--r-- | arch/sh/drivers/pci/ops-r7780rp.c | 77 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-auto.c | 44 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7751.c | 4 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 341 | ||||
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.h | 168 |
9 files changed, 651 insertions, 31 deletions
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig index 0f15216cd39..defc13c37d4 100644 --- a/arch/sh/drivers/dma/Kconfig +++ b/arch/sh/drivers/dma/Kconfig @@ -11,6 +11,8 @@ config SH_DMA config NR_ONCHIP_DMA_CHANNELS depends on SH_DMA int "Number of on-chip DMAC channels" + default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R + default "12" if CPU_SUBTYPE_SH7780 default "4" help This allows you to specify the number of channels that the on-chip @@ -52,4 +54,3 @@ config DMA_PAGE_OPS_CHANNEL are dual-address capable. endmenu - diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c index e028a2d2a4e..4428ee80965 100644 --- a/arch/sh/drivers/dma/dma-sh.c +++ b/arch/sh/drivers/dma/dma-sh.c @@ -11,14 +11,10 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. */ - #include <linux/init.h> -#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/module.h> #include <asm/dreamcast/dma.h> -#include <asm/signal.h> -#include <asm/irq.h> #include <asm/dma.h> #include <asm/io.h> #include "dma-sh.h" diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile index 86d6d0660d4..3d8078f1c05 100644 --- a/arch/sh/drivers/pci/Makefile +++ b/arch/sh/drivers/pci/Makefile @@ -7,6 +7,7 @@ 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_CPU_SUBTYPE_SH7780) += pci-sh7780.o obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ dma-dreamcast.o @@ -14,4 +15,5 @@ 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 +obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o obj-$(CONFIG_SH_TITAN) += ops-titan.o diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c new file mode 100644 index 00000000000..b656b562ec9 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-r7780rp.c @@ -0,0 +1,39 @@ +/* + * arch/sh/drivers/pci/fixups-r7780rp.c + * + * Highlander R7780RP-1 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-sh7780.h" +#include <asm/io.h> + +int pci_fixup_pcic(void) +{ + outl(0x000043ff, PCI_REG(SH7780_PCIIMR)); + outl(0x0000380f, PCI_REG(SH7780_PCIAINTM)); + + outl(0xfbb00047, PCI_REG(SH7780_PCICMD)); + outl(0x00000000, PCI_REG(SH7780_PCIIBAR)); + + outl(0x00011912, PCI_REG(SH7780_PCISVID)); + outl(0x08000000, PCI_REG(SH7780_PCICSCR0)); + outl(0x0000001b, PCI_REG(SH7780_PCICSAR0)); + outl(0xfd000000, PCI_REG(SH7780_PCICSCR1)); + outl(0x0000000f, PCI_REG(SH7780_PCICSAR1)); + + outl(0xfd000000, PCI_REG(SH7780_PCIMBR0)); + outl(0x00fc0000, PCI_REG(SH7780_PCIMBMR0)); + + /* Set IOBR for windows containing area specified in pci.h */ + outl((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1)), PCI_REG(SH7780_PCIIOBR)); + outl(((SH7780_PCI_IO_SIZE-1) & (7<<18)), PCI_REG(SH7780_PCIIOBMR)); + + return 0; +} + diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c new file mode 100644 index 00000000000..3254c4e917a --- /dev/null +++ b/arch/sh/drivers/pci/ops-r7780rp.c @@ -0,0 +1,77 @@ +/* + * 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 SH7780 Highlander R7780RP-1 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-sh7780.h" +#include <asm/r7780rp/r7780rp.h> + +int __init pcibios_map_platform_irq(u8 slot, u8 pin) +{ + switch (slot) { + case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */ + case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */ + case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */ + case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */ + default: + printk("PCI: Bad IRQ mapping request for slot %d, func %d\n", slot, pin-1); + return -1; + } +} + +static struct resource sh7780_io_resource = { + .name = "SH7780_IO", + .start = 0x2000, + .end = 0x2000 + SH7780_PCI_IO_SIZE - 1, + .flags = IORESOURCE_IO +}; + +static struct resource sh7780_mem_resource = { + .name = "SH7780_mem", + .start = SH7780_PCI_MEMORY_BASE, + .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, + .flags = IORESOURCE_MEM +}; + +extern struct pci_ops sh7780_pci_ops; + +struct pci_channel board_pci_channels[] = { + { &sh7780_pci_ops, &sh7780_io_resource, &sh7780_mem_resource, 0, 0xff }, + { NULL, NULL, NULL, 0, 0 }, +}; +EXPORT_SYMBOL(board_pci_channels); + +static struct sh7780_pci_address_map sh7780_pci_map = { + .window0 = { + .base = SH7780_CS2_BASE_ADDR, + .size = 0x04000000, + }, + + .window1 = { + .base = SH7780_CS3_BASE_ADDR, + .size = 0x04000000, + }, + + .flags = SH7780_PCIC_NO_RESET, +}; + +int __init pcibios_init_platform(void) +{ + return sh7780_pcic_init(&sh7780_pci_map); +} + diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c index 4cef4d1d8c8..d55e4661854 100644 --- a/arch/sh/drivers/pci/pci-auto.c +++ b/arch/sh/drivers/pci/pci-auto.c @@ -45,11 +45,11 @@ #include <linux/types.h> #include <linux/pci.h> -#undef DEBUG -#ifdef DEBUG +#define DEBUG +#ifdef DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) +#define DBG(x...) #endif /* @@ -102,7 +102,7 @@ static u32 pciauto_upper_iospc; static u32 pciauto_lower_memspc; static u32 pciauto_upper_memspc; -static void __init +static void __init pciauto_setup_bars(struct pci_channel *hose, int top_bus, int current_bus, @@ -116,7 +116,6 @@ pciauto_setup_bars(struct pci_channel *hose, 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 */ @@ -125,7 +124,6 @@ pciauto_setup_bars(struct pci_channel *hose, pci_devfn, bar, &bar_addr); -#endif /* Tickle the BAR and get the response */ early_write_config_dword(hose, top_bus, @@ -140,8 +138,7 @@ pciauto_setup_bars(struct pci_channel *hose, 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. @@ -151,7 +148,6 @@ pciauto_setup_bars(struct pci_channel *hose, pci_devfn, bar, bar_addr); -#endif /* If BAR is not implemented go to the next BAR */ if (!bar_response) @@ -177,7 +173,7 @@ retry: PCI_BASE_ADDRESS_MEM_TYPE_64) found_mem64 = 1; - addr_mask = PCI_BASE_ADDRESS_MEM_MASK; + addr_mask = PCI_BASE_ADDRESS_MEM_MASK; upper_limit = &pciauto_upper_memspc; lower_limit = &pciauto_lower_memspc; DBG(" Mem"); @@ -193,22 +189,22 @@ retry: 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 = io_resource_inuse->child; - pciauto_lower_iospc = + pciauto_lower_iospc = io_resource_inuse->start; - pciauto_upper_iospc = + pciauto_upper_iospc = io_resource_inuse->end + 1; goto retry; } } else { if (mem_resource_inuse->child) { - mem_resource_inuse = + mem_resource_inuse = mem_resource_inuse->child; - pciauto_lower_memspc = + pciauto_lower_memspc = mem_resource_inuse->start; - pciauto_upper_memspc = + pciauto_upper_memspc = mem_resource_inuse->end + 1; goto retry; } @@ -230,7 +226,7 @@ retry: * 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, @@ -362,7 +358,7 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, { u32 temp; -#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) +#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) && !defined(CONFIG_SH_R7780RP) /* * [jsun] we always bump up baselines a little, so that if there * nothing behind P2P bridge, we don't wind up overlapping IO/MEM @@ -396,7 +392,7 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, * configured by this routine to happily live behind a * P2P bridge in a system. */ -#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) +#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) || defined(CONFIG_SH_R7780RP) pciauto_lower_memspc += 0x00400000; pciauto_lower_iospc += 0x00004000; #endif @@ -433,12 +429,12 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) 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) @@ -471,7 +467,7 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) 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) +#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) || defined(CONFIG_SH_R7780RP) pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1); #endif pciauto_prescan_setup_bridge(hose, top_bus, current_bus, @@ -490,10 +486,10 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) 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); diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 682f3dae305..65093ec1b55 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -223,7 +223,7 @@ static int __init __area_sdram_check(unsigned int area) word = inl(SH7751_BCR1); /* check BCR for SDRAM in area */ - if(((word >> area) & 1) == 0) { + if (((word >> area) & 1) == 0) { printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", area, word); return 0; @@ -232,7 +232,7 @@ static int __init __area_sdram_check(unsigned int area) word = (u16)inw(SH7751_BCR2); /* check BCR2 for 32bit SDRAM interface*/ - if(((word >> (area << 1)) & 0x3) != 0x3) { + if (((word >> (area << 1)) & 0x3) != 0x3) { printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", area, word); return 0; diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c new file mode 100644 index 00000000000..e09721330ac --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -0,0 +1,341 @@ +/* + * Low-Level PCI Support for the SH7780 + * + * 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-sh7780.h" + +static unsigned int pci_probe = PCI_PROBE_CONF1; +extern int pci_fixup_pcic(void); + +/* + * 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 sh7780_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(SH7780_PCIPAR)); + data = inl(PCI_REG(SH7780_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 SH7780 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 sh7780_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(SH7780_PCIPAR)); + data = inl(PCI_REG(SH7780_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(SH7780_PCIPDR)); + + return PCIBIOS_SUCCESSFUL; +} + +#undef CONFIG_CMD + +struct pci_ops sh7780_pci_ops = { + .read = sh7780_pci_read, + .write = sh7780_pci_write, +}; + +static int __init pci_check_direct(void) +{ + unsigned int tmp, id; + + outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ + + /* check for SH7780/SH7780R hardware */ + id = inl(PCI_REG(SH7780_PCIVID)); + if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) && + (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) { + printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); + return -ENODEV; + } + + /* + * Check if configuration works. + */ + if (pci_probe & PCI_PROBE_CONF1) { + tmp = inl(PCI_REG(SH7780_PCIPAR)); + outl(0x80000000, PCI_REG(SH7780_PCIPAR)); + if (inl(PCI_REG(SH7780_PCIPAR)) == 0x80000000) { + outl(tmp, PCI_REG(SH7780_PCIPAR)); + printk(KERN_INFO "PCI: Using configuration type 1\n"); + request_region(PCI_REG(SH7780_PCIPAR), 8, "PCI conf1"); + return 0; + } + outl(tmp, PCI_REG(SH7780_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 + * exists 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 sh7780_pci_init(void) +{ + int ret; + + pr_debug("PCI: Starting intialization.\n"); + + /* Setup the INTC */ + ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */ + ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */ + ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */ + ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */ + ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */ + ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */ + + if ((ret = pci_check_direct()) != 0) + return ret; + + return pcibios_init_platform(); +} + +core_initcall(sh7780_pci_init); + +int __init sh7780_pcic_init(struct sh7780_pci_address_map *map) +{ + u32 word; + + /* + * 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 & SH7780_PCIC_NO_RESET)) { + /* toggle PCI reset pin */ + word = SH7780_PCICR_PREFIX | SH7780_PCICR_PRST; + outl(word,PCI_REG(SH7780_PCICR)); + /* Wait for a long time... not 1 sec. but long enough */ + mdelay(100); + word = SH7780_PCICR_PREFIX; + outl(word,PCI_REG(SH7780_PCICR)); + } + + /* set the command/status bits to: + * Wait Cycle Control + Parity Enable + Bus Master + + * Mem space enable + */ + outl(0x00000046, PCI_REG(SH7780_PCICMD)); + + /* define this host as the host bridge */ + word = SH7780_PCI_HOST_BRIDGE << 24; + outl(word, PCI_REG(SH7780_PCIRID)); + + /* 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) & 0x1ff00001) | 0x01; + outl(0x07f00001, PCI_REG(SH7780_PCILSR0)); + word = ((map->window1.size - 1) & 0x1ff00001) | 0x01; + outl(0x00000001, PCI_REG(SH7780_PCILSR1)); + /* Set the values on window 0 PCI config registers */ + word = P2SEGADDR(map->window0.base); + outl(0xa8000000, PCI_REG(SH7780_PCILAR0)); + outl(0x08000000, PCI_REG(SH7780_PCIMBAR0)); + /* Set the values on window 1 PCI config registers */ + word = P2SEGADDR(map->window1.base); + outl(0x00000000, PCI_REG(SH7780_PCILAR1)); + outl(0x00000000, PCI_REG(SH7780_PCIMBAR1)); + + /* 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), SH7780_PCI_IO_BASE+PCIBIOS_MIN_IO); + + /* NOTE: I'm ignoring the PCI error IRQs for now.. + * TODO: add support for the internal error interrupts and + * DMA interrupts... + */ + +#ifdef CONFIG_SH_R7780RP + pci_fixup_pcic(); +#endif + + /* SH7780 init done, set central function init complete */ + /* use round robin mode to stop a device starving/overruning */ + word = SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | /* SH7780_PCICR_ARBM |*/ SH7780_PCICR_FTO; + outl(word, PCI_REG(SH7780_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 sh7780_no_swizzle(struct pci_dev *dev, u8 *pin) +{ + /* no swizzling */ + return PCI_SLOT(dev->devfn); +} + +static int sh7780_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(sh7780_no_swizzle, sh7780_pci_lookup_irq); +} + diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h new file mode 100644 index 00000000000..750d5d7753a --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7780.h @@ -0,0 +1,168 @@ +/* + * Low-Level PCI Support for SH7780 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_SH7780_H_ +#define _PCI_SH7780_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 SH7780_VENDOR_ID 0x1912 +#define SH7780_DEVICE_ID 0x0002 +#define SH7781_DEVICE_ID 0x0001 + +/* SH7780 Control Registers */ +#define SH7780_PCI_VCR0 0xFE000000 +#define SH7780_PCI_VCR1 0xFE000004 +#define SH7780_PCI_VCR2 0xFE000008 + +/* SH7780 Specific Values */ +#define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */ +#define SH7780_PCI_CONFIG_SIZE 0x01000000 /* Config space size */ +#define SH7780_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */ +#define SH7780_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */ +#if 1 +#define SH7780_PCI_IO_BASE 0xFE400000 /* IO space base address */ +#define SH7780_PCI_IO_SIZE 0x00400000 /* Size of IO window */ +#else +#define SH7780_PCI_IO_BASE 0xFE200000 /* IO space base address */ +#define SH7780_PCI_IO_SIZE 0x00200000 /* Size of IO window */ +#endif + +#define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */ +#define PCI_REG(n) (SH7780_PCIREG_BASE+n) + +/* SH7780 PCI Config Registers */ +#define SH7780_PCIVID 0x000 /* Vendor ID */ +#define SH7780_PCIDID 0x002 /* Device ID */ +#define SH7780_PCICMD 0x004 /* Command */ +#define SH7780_PCISTATUS 0x006 /* Status */ +#define SH7780_PCIRID 0x008 /* Revision ID */ +#define SH7780_PCIPIF 0x009 /* Program Interface */ +#define SH7780_PCISUB 0x00a /* Sub class code */ +#define SH7780_PCIBCC 0x00b /* Base class code */ +#define SH7780_PCICLS 0x00c /* Cache line size */ +#define SH7780_PCILTM 0x00d /* latency timer */ +#define SH7780_PCIHDR 0x00e /* Header type */ +#define SH7780_PCIBIST 0x00f /* BIST */ +#define SH7780_PCIIBAR 0x010 /* IO Base address */ +#define SH7780_PCIMBAR0 0x014 /* Memory base address0 */ +#define SH7780_PCIMBAR1 0x018 /* Memory base address1 */ +#define SH7780_PCISVID 0x02c /* Sub system vendor ID */ +#define SH7780_PCISID 0x02e /* Sub system ID */ +#define SH7780_PCICP 0x034 +#define SH7780_PCIINTLINE 0x03c /* Interrupt line */ +#define SH7780_PCIINTPIN 0x03d /* Interrupt pin */ +#define SH7780_PCIMINGNT 0x03e /* Minumum grand */ +#define SH7780_PCIMAXLAT 0x03f /* Maxmum latency */ +#define SH7780_PCICID 0x040 +#define SH7780_PCINIP 0x041 +#define SH7780_PCIPMC 0x042 +#define SH7780_PCIPMCSR 0x044 +#define SH7780_PCIPMCSR_BSE 0x046 +#define SH7780_PCICDD 0x047 + +/* SH7780 PCI Local Registers */ +#define SH7780_PCICR 0x100 /* PCI Control Register */ + #define SH7780_PCICR_PREFIX 0xA5000000 /* CR prefix for write */ + #define SH7780_PCICR_PFCS 0x00000800 /* TRDY/IRDY Enable */ + #define SH7780_PCICR_FTO 0x00000400 /* TRDY/IRDY Enable */ + #define SH7780_PCICR_PFE 0x00000200 /* Target Read Single */ + #define SH7780_PCICR_TBS 0x00000100 /* Target Byte Swap */ + #define SH7780_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */ + #define SH7780_PCICR_IOCS 0x00000004 /* INTA output assert */ + #define SH7780_PCICR_PRST 0x00000002 /* PCI Reset Assert */ + #define SH7780_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */ +#define SH7780_PCILSR0 0x104 /* PCI Local Space Register0 */ +#define SH7780_PCILSR1 0x108 /* PCI Local Space Register1 */ +#define SH7780_PCILAR0 0x10C /* PCI Local Address Register1 */ +#define SH7780_PCILAR1 0x110 /* PCI Local Address Register1 */ +#define SH7780_PCIIR 0x114 /* PCI Interrupt Register */ +#define SH7780_PCIIMR 0x118 /* PCI Interrupt Mask Register */ +#define SH7780_PCIAIR 0x11C /* Error Address Register */ +#define SH7780_PCICIR 0x120 /* Error Command/Data Register */ +#define SH7780_PCIAINT 0x130 /* Arbiter Interrupt Register */ +#define SH7780_PCIAINTM 0x134 /* Arbiter Int. Mask Register */ +#define SH7780_PCIBMIR 0x138 /* Error Bus Master Register */ +#define SH7780_PCIPAR 0x1C0 /* PIO Address Register */ +#define SH7780_PCIPINT 0x1CC /* Power Management Int. Register */ +#define SH7780_PCIPINTM 0x1D0 /* Power Management Mask Register */ +#define SH7780_PCIMBR0 0x1E0 /* Memory Bank0 Register */ +#define SH7780_PCIMBMR0 0x1E4 /* Memory Bank0 Mask Register */ +#define SH7780_PCIMBR1 0x1E8 /* Memory Bank1 Register */ +#define SH7780_PCIMBMR1 0x1EC /* Memory Bank1 Mask Register */ +#define SH7780_PCIMBR2 0x1F0 /* Memory Bank2 Register */ +#define SH7780_PCIMBMR2 0x1F4 /* Memory Bank2 Mask Register */ +#define SH7780_PCIIOBR 0x1F8 /* Bank Register */ +#define SH7780_PCIIOBMR 0x1FC /* Bank Mask Register */ +#define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */ +#define SH7780_PCICSCR1 0x214 /* Cache Snoop2 Cnt. Register */ +#define SH7780_PCICSAR0 0x218 /* Cache Snoop1 Addr. Register */ +#define SH7780_PCICSAR1 0x21C /* Cache Snoop2 Addr. Register */ +#define SH7780_PCIPDR 0x220 /* Port IO Data Register */ + +/* General Memory Config Addresses */ +#define SH7780_CS0_BASE_ADDR 0x0 +#define SH7780_MEM_REGION_SIZE 0x04000000 +#define SH7780_CS1_BASE_ADDR (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE) +#define SH7780_CS2_BASE_ADDR (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE) +#define SH7780_CS3_BASE_ADDR (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE) +#define SH7780_CS4_BASE_ADDR (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE) +#define SH7780_CS5_BASE_ADDR (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE) +#define SH7780_CS6_BASE_ADDR (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE) + +/* General PCI values */ +#define SH7780_PCI_HOST_BRIDGE 0x6 + +/* Flags */ +#define SH7780_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 sh7780_pci_address_space { + unsigned long base; + unsigned long size; +}; + +struct sh7780_pci_address_map { + struct sh7780_pci_address_space window0; + struct sh7780_pci_address_space window1; + unsigned long flags; +}; + +/* arch/sh/drivers/pci/pci-sh7780.c */ +extern int sh7780_pcic_init(struct sh7780_pci_address_map *map); + +#endif /* _PCI_SH7780_H_ */ + |