diff options
Diffstat (limited to 'arch/sh/drivers/pci/pci-sh7780.c')
-rw-r--r-- | arch/sh/drivers/pci/pci-sh7780.c | 224 |
1 files changed, 107 insertions, 117 deletions
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index bae6a2cf047d..323b92d565fe 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c | |||
@@ -1,19 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * Low-Level PCI Support for the SH7780 | 2 | * Low-Level PCI Support for the SH7780 |
3 | * | 3 | * |
4 | * Dustin McIntire (dustin@sensoria.com) | 4 | * Copyright (C) 2005 - 2009 Paul Mundt |
5 | * Derived from arch/i386/kernel/pci-*.c which bore the message: | ||
6 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | ||
7 | * | ||
8 | * Ported to the new API by Paul Mundt <lethal@linux-sh.org> | ||
9 | * With cleanup by Paul van Gool <pvangool@mimotech.com> | ||
10 | * | ||
11 | * May be copied or modified under the terms of the GNU General Public | ||
12 | * License. See linux/COPYING for more information. | ||
13 | * | 5 | * |
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
14 | */ | 9 | */ |
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/types.h> | 10 | #include <linux/types.h> |
18 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
19 | #include <linux/init.h> | 12 | #include <linux/init.h> |
@@ -22,135 +15,132 @@ | |||
22 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
23 | #include "pci-sh4.h" | 16 | #include "pci-sh4.h" |
24 | 17 | ||
25 | #define INTC_BASE 0xffd00000 | 18 | static struct resource sh7785_io_resource = { |
26 | #define INTC_ICR0 (INTC_BASE+0x0) | 19 | .name = "SH7785_IO", |
27 | #define INTC_ICR1 (INTC_BASE+0x1c) | 20 | .start = SH7780_PCI_IO_BASE, |
28 | #define INTC_INTPRI (INTC_BASE+0x10) | 21 | .end = SH7780_PCI_IO_BASE + SH7780_PCI_IO_SIZE - 1, |
29 | #define INTC_INTREQ (INTC_BASE+0x24) | 22 | .flags = IORESOURCE_IO |
30 | #define INTC_INTMSK0 (INTC_BASE+0x44) | 23 | }; |
31 | #define INTC_INTMSK1 (INTC_BASE+0x48) | 24 | |
32 | #define INTC_INTMSK2 (INTC_BASE+0x40080) | 25 | static struct resource sh7785_mem_resource = { |
33 | #define INTC_INTMSKCLR0 (INTC_BASE+0x64) | 26 | .name = "SH7785_mem", |
34 | #define INTC_INTMSKCLR1 (INTC_BASE+0x68) | 27 | .start = SH7780_PCI_MEMORY_BASE, |
35 | #define INTC_INTMSKCLR2 (INTC_BASE+0x40084) | 28 | .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1, |
36 | #define INTC_INT2MSKR (INTC_BASE+0x40038) | 29 | .flags = IORESOURCE_MEM |
37 | #define INTC_INT2MSKCR (INTC_BASE+0x4003c) | 30 | }; |
31 | |||
32 | static struct pci_channel sh7780_pci_controller = { | ||
33 | .pci_ops = &sh4_pci_ops, | ||
34 | .mem_resource = &sh7785_mem_resource, | ||
35 | .mem_offset = 0x00000000, | ||
36 | .io_resource = &sh7785_io_resource, | ||
37 | .io_offset = 0x00000000, | ||
38 | .io_map_base = SH7780_PCI_IO_BASE, | ||
39 | }; | ||
40 | |||
41 | static struct sh4_pci_address_map sh7780_pci_map = { | ||
42 | .window0 = { | ||
43 | #if defined(CONFIG_32BIT) | ||
44 | .base = SH7780_32BIT_DDR_BASE_ADDR, | ||
45 | .size = 0x40000000, | ||
46 | #else | ||
47 | .base = SH7780_CS0_BASE_ADDR, | ||
48 | .size = 0x20000000, | ||
49 | #endif | ||
50 | }, | ||
51 | }; | ||
38 | 52 | ||
39 | /* | ||
40 | * Initialization. Try all known PCI access methods. Note that we support | ||
41 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | ||
42 | * to access config space. | ||
43 | * | ||
44 | * Note that the platform specific initialization (BSC registers, and memory | ||
45 | * space mapping) will be called via the platform defined function | ||
46 | * pcibios_init_platform(). | ||
47 | */ | ||
48 | static int __init sh7780_pci_init(void) | 53 | static int __init sh7780_pci_init(void) |
49 | { | 54 | { |
55 | struct pci_channel *chan = &sh7780_pci_controller; | ||
50 | unsigned int id; | 56 | unsigned int id; |
51 | int ret, match = 0; | 57 | const char *type = NULL; |
52 | 58 | int ret; | |
53 | pr_debug("PCI: Starting intialization.\n"); | 59 | u32 word; |
54 | |||
55 | ctrl_outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ | ||
56 | |||
57 | /* check for SH7780/SH7780R hardware */ | ||
58 | id = pci_read_reg(SH7780_PCIVID); | ||
59 | if ((id & 0xffff) == SH7780_VENDOR_ID) { | ||
60 | switch ((id >> 16) & 0xffff) { | ||
61 | case SH7763_DEVICE_ID: | ||
62 | case SH7780_DEVICE_ID: | ||
63 | case SH7781_DEVICE_ID: | ||
64 | case SH7785_DEVICE_ID: | ||
65 | match = 1; | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | 60 | ||
70 | if (unlikely(!match)) { | 61 | printk(KERN_NOTICE "PCI: Starting intialization.\n"); |
71 | printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id); | 62 | |
63 | chan->reg_base = 0xfe040000; | ||
64 | |||
65 | /* Enable CPU access to the PCIC registers. */ | ||
66 | __raw_writel(PCIECR_ENBL, PCIECR); | ||
67 | |||
68 | id = __raw_readw(chan->reg_base + SH7780_PCIVID); | ||
69 | if (id != SH7780_VENDOR_ID) { | ||
70 | printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id); | ||
72 | return -ENODEV; | 71 | return -ENODEV; |
73 | } | 72 | } |
74 | 73 | ||
75 | /* Setup the INTC */ | 74 | id = __raw_readw(chan->reg_base + SH7780_PCIDID); |
76 | if (mach_is_7780se()) { | 75 | type = (id == SH7763_DEVICE_ID) ? "SH7763" : |
77 | /* ICR0: IRL=use separately */ | 76 | (id == SH7780_DEVICE_ID) ? "SH7780" : |
78 | ctrl_outl(0x00C00020, INTC_ICR0); | 77 | (id == SH7781_DEVICE_ID) ? "SH7781" : |
79 | /* ICR1: detect low level(for 2ndcut) */ | 78 | (id == SH7785_DEVICE_ID) ? "SH7785" : |
80 | ctrl_outl(0xAAAA0000, INTC_ICR1); | 79 | NULL; |
81 | /* INTPRI: priority=3(all) */ | 80 | if (unlikely(!type)) { |
82 | ctrl_outl(0x33333333, INTC_INTPRI); | 81 | printk(KERN_ERR "PCI: Found an unsupported Renesas host " |
82 | "controller, device id 0x%04x.\n", id); | ||
83 | return -EINVAL; | ||
83 | } | 84 | } |
84 | 85 | ||
85 | if ((ret = sh4_pci_check_direct()) != 0) | 86 | printk(KERN_NOTICE "PCI: Found a Renesas %s host " |
86 | return ret; | 87 | "controller, revision %d.\n", type, |
88 | __raw_readb(chan->reg_base + SH7780_PCIRID)); | ||
87 | 89 | ||
88 | return pcibios_init_platform(); | 90 | if ((ret = sh4_pci_check_direct(chan)) != 0) |
89 | } | 91 | return ret; |
90 | core_initcall(sh7780_pci_init); | ||
91 | |||
92 | int __init sh7780_pcic_init(struct sh4_pci_address_map *map) | ||
93 | { | ||
94 | u32 word; | ||
95 | 92 | ||
96 | /* | 93 | /* |
97 | * This code is unused for some boards as it is done in the | 94 | * Set the class and sub-class codes. |
98 | * bootloader and doing it here means the MAC addresses loaded | ||
99 | * by the bootloader get lost. | ||
100 | */ | ||
101 | if (!(map->flags & SH4_PCIC_NO_RESET)) { | ||
102 | /* toggle PCI reset pin */ | ||
103 | word = SH4_PCICR_PREFIX | SH4_PCICR_PRST; | ||
104 | pci_write_reg(word, SH4_PCICR); | ||
105 | /* Wait for a long time... not 1 sec. but long enough */ | ||
106 | mdelay(100); | ||
107 | word = SH4_PCICR_PREFIX; | ||
108 | pci_write_reg(word, SH4_PCICR); | ||
109 | } | ||
110 | |||
111 | /* set the command/status bits to: | ||
112 | * Wait Cycle Control + Parity Enable + Bus Master + | ||
113 | * Mem space enable | ||
114 | */ | 95 | */ |
115 | pci_write_reg(0x00000046, SH7780_PCICMD); | 96 | __raw_writeb(PCI_CLASS_BRIDGE_HOST >> 8, |
116 | 97 | chan->reg_base + SH7780_PCIBCC); | |
117 | /* define this host as the host bridge */ | 98 | __raw_writeb(PCI_CLASS_BRIDGE_HOST & 0xff, |
118 | word = PCI_BASE_CLASS_BRIDGE << 24; | 99 | chan->reg_base + SH7780_PCISUB); |
119 | pci_write_reg(word, SH7780_PCIRID); | ||
120 | 100 | ||
121 | /* Set IO and Mem windows to local address | 101 | /* |
102 | * Set IO and Mem windows to local address | ||
122 | * Make PCI and local address the same for easy 1 to 1 mapping | 103 | * Make PCI and local address the same for easy 1 to 1 mapping |
123 | */ | 104 | */ |
124 | pci_write_reg(map->window0.size - 0xfffff, SH4_PCILSR0); | 105 | pci_write_reg(chan, sh7780_pci_map.window0.size - 0xfffff, SH4_PCILSR0); |
125 | pci_write_reg(map->window1.size - 0xfffff, SH4_PCILSR1); | ||
126 | /* Set the values on window 0 PCI config registers */ | 106 | /* Set the values on window 0 PCI config registers */ |
127 | pci_write_reg(map->window0.base, SH4_PCILAR0); | 107 | pci_write_reg(chan, sh7780_pci_map.window0.base, SH4_PCILAR0); |
128 | pci_write_reg(map->window0.base, SH7780_PCIMBAR0); | 108 | pci_write_reg(chan, sh7780_pci_map.window0.base, SH7780_PCIMBAR0); |
129 | /* Set the values on window 1 PCI config registers */ | ||
130 | pci_write_reg(map->window1.base, SH4_PCILAR1); | ||
131 | pci_write_reg(map->window1.base, SH7780_PCIMBAR1); | ||
132 | |||
133 | /* Map IO space into PCI IO window | ||
134 | * The IO window is 64K-PCIBIOS_MIN_IO in size | ||
135 | * IO addresses will be translated to the | ||
136 | * PCI IO window base address | ||
137 | */ | ||
138 | pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", | ||
139 | PCIBIOS_MIN_IO, (64 << 10), | ||
140 | SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO); | ||
141 | 109 | ||
142 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | 110 | pci_write_reg(chan, 0x0000380f, SH4_PCIAINTM); |
143 | * TODO: add support for the internal error interrupts and | 111 | |
144 | * DMA interrupts... | 112 | /* Set up standard PCI config registers */ |
145 | */ | 113 | __raw_writew(0xFB00, chan->reg_base + SH7780_PCISTATUS); |
114 | __raw_writew(0x0047, chan->reg_base + SH7780_PCICMD); | ||
115 | __raw_writew(0x1912, chan->reg_base + SH7780_PCISVID); | ||
116 | __raw_writew(0x0001, chan->reg_base + SH7780_PCISID); | ||
117 | |||
118 | __raw_writeb(0x00, chan->reg_base + SH7780_PCIPIF); | ||
146 | 119 | ||
147 | /* Apply any last-minute PCIC fixups */ | 120 | /* Apply any last-minute PCIC fixups */ |
148 | pci_fixup_pcic(); | 121 | pci_fixup_pcic(chan); |
122 | |||
123 | pci_write_reg(chan, 0xfd000000, SH7780_PCIMBR0); | ||
124 | pci_write_reg(chan, 0x00fc0000, SH7780_PCIMBMR0); | ||
125 | |||
126 | #ifdef CONFIG_32BIT | ||
127 | pci_write_reg(chan, 0xc0000000, SH7780_PCIMBR2); | ||
128 | pci_write_reg(chan, 0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2); | ||
129 | #endif | ||
130 | |||
131 | /* Set IOBR for windows containing area specified in pci.h */ | ||
132 | pci_write_reg(chan, chan->io_resource->start & ~(SH7780_PCI_IO_SIZE-1), | ||
133 | SH7780_PCIIOBR); | ||
134 | pci_write_reg(chan, ((SH7780_PCI_IO_SIZE-1) & (7<<18)), | ||
135 | SH7780_PCIIOBMR); | ||
149 | 136 | ||
150 | /* SH7780 init done, set central function init complete */ | 137 | /* SH7780 init done, set central function init complete */ |
151 | /* use round robin mode to stop a device starving/overruning */ | 138 | /* use round robin mode to stop a device starving/overruning */ |
152 | word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO; | 139 | word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO; |
153 | pci_write_reg(word, SH4_PCICR); | 140 | pci_write_reg(chan, word, SH4_PCICR); |
141 | |||
142 | register_pci_controller(chan); | ||
154 | 143 | ||
155 | return 1; | 144 | return 0; |
156 | } | 145 | } |
146 | arch_initcall(sh7780_pci_init); | ||