diff options
author | Manuel Lauss <manuel.lauss@googlemail.com> | 2011-08-12 05:39:44 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2011-10-24 18:34:24 -0400 |
commit | 7517de348663b08a808aff44b5300e817157a568 (patch) | |
tree | b70b0bdbb30f2ef796c4ca319ad922e7686ca51c /arch/mips | |
parent | 7cc2e272da3d88c0de9e05b32729402785bd9206 (diff) |
MIPS: Alchemy: Redo PCI as platform driver
- Rewrite Alchemy PCI support as a platform driver.
- Fixup boards which have PCI.
Run-tested on DB1500 and DB1550.
Signed-off-by: Manuel Lauss <manuel.lauss@googlemail.com>
To: Linux-MIPS <linux-mips@linux-mips.org>
Patchwork: https://patchwork.linux-mips.org/patch/2706/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
delete mode 100644 arch/mips/alchemy/common/pci.c
delete mode 100644 arch/mips/pci/fixup-au1000.c
delete mode 100644 arch/mips/pci/ops-au1000.c
create mode 100644 arch/mips/pci/pci-alchemy.c
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/alchemy/common/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/alchemy/common/pci.c | 104 | ||||
-rw-r--r-- | arch/mips/alchemy/common/setup.c | 6 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1x00/board_setup.c | 24 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1x00/platform.c | 123 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/pb1500/board_setup.c | 33 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/pb1500/platform.c | 48 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/pb1550/board_setup.c | 6 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/pb1550/platform.c | 48 | ||||
-rw-r--r-- | arch/mips/alchemy/gpr/board_setup.c | 12 | ||||
-rw-r--r-- | arch/mips/alchemy/gpr/platform.c | 47 | ||||
-rw-r--r-- | arch/mips/alchemy/mtx-1/board_setup.c | 40 | ||||
-rw-r--r-- | arch/mips/alchemy/mtx-1/platform.c | 62 | ||||
-rw-r--r-- | arch/mips/alchemy/xxs1500/board_setup.c | 8 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-au1x00/au1000.h | 142 | ||||
-rw-r--r-- | arch/mips/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/pci/fixup-au1000.c | 43 | ||||
-rw-r--r-- | arch/mips/pci/ops-au1000.c | 308 | ||||
-rw-r--r-- | arch/mips/pci/pci-alchemy.c | 516 |
19 files changed, 950 insertions, 625 deletions
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index 62f0d39e93cd..811ece7b22e3 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile | |||
@@ -14,5 +14,3 @@ obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o | |||
14 | ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) | 14 | ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) |
15 | obj-$(CONFIG_GPIOLIB) += gpiolib.o | 15 | obj-$(CONFIG_GPIOLIB) += gpiolib.o |
16 | endif | 16 | endif |
17 | |||
18 | obj-$(CONFIG_PCI) += pci.o | ||
diff --git a/arch/mips/alchemy/common/pci.c b/arch/mips/alchemy/common/pci.c deleted file mode 100644 index 7866cf50cf99..000000000000 --- a/arch/mips/alchemy/common/pci.c +++ /dev/null | |||
@@ -1,104 +0,0 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Alchemy/AMD Au1x00 PCI support. | ||
4 | * | ||
5 | * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) | ||
9 | * | ||
10 | * Support for all devices (greater than 16) added by David Gathright. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
19 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
20 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
23 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
24 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License along | ||
29 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
30 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | */ | ||
32 | |||
33 | #include <linux/pci.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/init.h> | ||
36 | |||
37 | #include <asm/mach-au1x00/au1000.h> | ||
38 | |||
39 | /* TBD */ | ||
40 | static struct resource pci_io_resource = { | ||
41 | .start = PCI_IO_START, | ||
42 | .end = PCI_IO_END, | ||
43 | .name = "PCI IO space", | ||
44 | .flags = IORESOURCE_IO | ||
45 | }; | ||
46 | |||
47 | static struct resource pci_mem_resource = { | ||
48 | .start = PCI_MEM_START, | ||
49 | .end = PCI_MEM_END, | ||
50 | .name = "PCI memory space", | ||
51 | .flags = IORESOURCE_MEM | ||
52 | }; | ||
53 | |||
54 | extern struct pci_ops au1x_pci_ops; | ||
55 | |||
56 | static struct pci_controller au1x_controller = { | ||
57 | .pci_ops = &au1x_pci_ops, | ||
58 | .io_resource = &pci_io_resource, | ||
59 | .mem_resource = &pci_mem_resource, | ||
60 | }; | ||
61 | |||
62 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
63 | static unsigned long virt_io_addr; | ||
64 | #endif | ||
65 | |||
66 | static int __init au1x_pci_setup(void) | ||
67 | { | ||
68 | extern void au1x_pci_cfg_init(void); | ||
69 | |||
70 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
71 | virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, | ||
72 | Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1); | ||
73 | |||
74 | if (!virt_io_addr) { | ||
75 | printk(KERN_ERR "Unable to ioremap pci space\n"); | ||
76 | return 1; | ||
77 | } | ||
78 | au1x_controller.io_map_base = virt_io_addr; | ||
79 | |||
80 | #ifdef CONFIG_DMA_NONCOHERENT | ||
81 | { | ||
82 | /* | ||
83 | * Set the NC bit in controller for Au1500 pre-AC silicon | ||
84 | */ | ||
85 | u32 prid = read_c0_prid(); | ||
86 | |||
87 | if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { | ||
88 | au_writel((1 << 16) | au_readl(Au1500_PCI_CFG), | ||
89 | Au1500_PCI_CFG); | ||
90 | printk(KERN_INFO "Non-coherent PCI accesses enabled\n"); | ||
91 | } | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | set_io_port_base(virt_io_addr); | ||
96 | #endif | ||
97 | |||
98 | au1x_pci_cfg_init(); | ||
99 | |||
100 | register_pci_controller(&au1x_controller); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | arch_initcall(au1x_pci_setup); | ||
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 1b887c868417..37ffd997c616 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c | |||
@@ -73,8 +73,8 @@ void __init plat_mem_setup(void) | |||
73 | /* This routine should be valid for all Au1x based boards */ | 73 | /* This routine should be valid for all Au1x based boards */ |
74 | phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) | 74 | phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) |
75 | { | 75 | { |
76 | u32 start = (u32)Au1500_PCI_MEM_START; | 76 | unsigned long start = ALCHEMY_PCI_MEMWIN_START; |
77 | u32 end = (u32)Au1500_PCI_MEM_END; | 77 | unsigned long end = ALCHEMY_PCI_MEMWIN_END; |
78 | 78 | ||
79 | /* Don't fixup 36-bit addresses */ | 79 | /* Don't fixup 36-bit addresses */ |
80 | if ((phys_addr >> 32) != 0) | 80 | if ((phys_addr >> 32) != 0) |
@@ -82,7 +82,7 @@ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) | |||
82 | 82 | ||
83 | /* Check for PCI memory window */ | 83 | /* Check for PCI memory window */ |
84 | if (phys_addr >= start && (phys_addr + size - 1) <= end) | 84 | if (phys_addr >= start && (phys_addr + size - 1) <= end) |
85 | return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START); | 85 | return (phys_t)(AU1500_PCI_MEM_PHYS_ADDR + phys_addr); |
86 | 86 | ||
87 | /* default nop */ | 87 | /* default nop */ |
88 | return phys_addr; | 88 | return phys_addr; |
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c index 5c956fe8760f..2b2178f3f30b 100644 --- a/arch/mips/alchemy/devboards/db1x00/board_setup.c +++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c | |||
@@ -40,24 +40,6 @@ | |||
40 | 40 | ||
41 | #include <prom.h> | 41 | #include <prom.h> |
42 | 42 | ||
43 | #ifdef CONFIG_MIPS_DB1500 | ||
44 | char irq_tab_alchemy[][5] __initdata = { | ||
45 | [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT371 */ | ||
46 | [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ | ||
47 | }; | ||
48 | |||
49 | #endif | ||
50 | |||
51 | |||
52 | #ifdef CONFIG_MIPS_DB1550 | ||
53 | char irq_tab_alchemy[][5] __initdata = { | ||
54 | [11] = { -1, AU1550_PCI_INTC, 0xff, 0xff, 0xff }, /* IDSEL 11 - on-board HPT371 */ | ||
55 | [12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */ | ||
56 | [13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */ | ||
57 | }; | ||
58 | #endif | ||
59 | |||
60 | |||
61 | #ifdef CONFIG_MIPS_BOSPORUS | 43 | #ifdef CONFIG_MIPS_BOSPORUS |
62 | char irq_tab_alchemy[][5] __initdata = { | 44 | char irq_tab_alchemy[][5] __initdata = { |
63 | [11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI */ | 45 | [11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI */ |
@@ -91,12 +73,6 @@ const char *get_system_type(void) | |||
91 | 73 | ||
92 | 74 | ||
93 | #ifdef CONFIG_MIPS_MIRAGE | 75 | #ifdef CONFIG_MIPS_MIRAGE |
94 | char irq_tab_alchemy[][5] __initdata = { | ||
95 | [11] = { -1, AU1500_PCI_INTD, 0xff, 0xff, 0xff }, /* IDSEL 11 - SMI VGX */ | ||
96 | [12] = { -1, 0xff, 0xff, AU1500_PCI_INTC, 0xff }, /* IDSEL 12 - PNX1300 */ | ||
97 | [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 13 - miniPCI */ | ||
98 | }; | ||
99 | |||
100 | static void mirage_power_off(void) | 76 | static void mirage_power_off(void) |
101 | { | 77 | { |
102 | alchemy_gpio_direction_output(210, 1); | 78 | alchemy_gpio_direction_output(210, 1); |
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c index ef8017f23cdc..9030108928a4 100644 --- a/arch/mips/alchemy/devboards/db1x00/platform.c +++ b/arch/mips/alchemy/devboards/db1x00/platform.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <asm/mach-db1x00/bcsr.h> | 25 | #include <asm/mach-db1x00/bcsr.h> |
26 | #include "../platform.h" | 26 | #include "../platform.h" |
27 | 27 | ||
28 | struct pci_dev; | ||
29 | |||
28 | /* DB1xxx PCMCIA interrupt sources: | 30 | /* DB1xxx PCMCIA interrupt sources: |
29 | * CD0/1 GPIO0/3 | 31 | * CD0/1 GPIO0/3 |
30 | * STSCHG0/1 GPIO1/4 | 32 | * STSCHG0/1 GPIO1/4 |
@@ -85,6 +87,127 @@ | |||
85 | #endif | 87 | #endif |
86 | #endif | 88 | #endif |
87 | 89 | ||
90 | #ifdef CONFIG_PCI | ||
91 | #ifdef CONFIG_MIPS_DB1500 | ||
92 | static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
93 | { | ||
94 | if ((slot < 12) || (slot > 13) || pin == 0) | ||
95 | return -1; | ||
96 | if (slot == 12) | ||
97 | return (pin == 1) ? AU1500_PCI_INTA : 0xff; | ||
98 | if (slot == 13) { | ||
99 | switch (pin) { | ||
100 | case 1: return AU1500_PCI_INTA; | ||
101 | case 2: return AU1500_PCI_INTB; | ||
102 | case 3: return AU1500_PCI_INTC; | ||
103 | case 4: return AU1500_PCI_INTD; | ||
104 | } | ||
105 | } | ||
106 | return -1; | ||
107 | } | ||
108 | #endif | ||
109 | |||
110 | #ifdef CONFIG_MIPS_DB1550 | ||
111 | static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
112 | { | ||
113 | if ((slot < 11) || (slot > 13) || pin == 0) | ||
114 | return -1; | ||
115 | if (slot == 11) | ||
116 | return (pin == 1) ? AU1550_PCI_INTC : 0xff; | ||
117 | if (slot == 12) { | ||
118 | switch (pin) { | ||
119 | case 1: return AU1550_PCI_INTB; | ||
120 | case 2: return AU1550_PCI_INTC; | ||
121 | case 3: return AU1550_PCI_INTD; | ||
122 | case 4: return AU1550_PCI_INTA; | ||
123 | } | ||
124 | } | ||
125 | if (slot == 13) { | ||
126 | switch (pin) { | ||
127 | case 1: return AU1550_PCI_INTA; | ||
128 | case 2: return AU1550_PCI_INTB; | ||
129 | case 3: return AU1550_PCI_INTC; | ||
130 | case 4: return AU1550_PCI_INTD; | ||
131 | } | ||
132 | } | ||
133 | return -1; | ||
134 | } | ||
135 | #endif | ||
136 | |||
137 | #ifdef CONFIG_MIPS_BOSPORUS | ||
138 | static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
139 | { | ||
140 | if ((slot < 11) || (slot > 13) || pin == 0) | ||
141 | return -1; | ||
142 | if (slot == 12) | ||
143 | return (pin == 1) ? AU1500_PCI_INTA : 0xff; | ||
144 | if (slot == 11) { | ||
145 | switch (pin) { | ||
146 | case 1: return AU1500_PCI_INTA; | ||
147 | case 2: return AU1500_PCI_INTB; | ||
148 | default: return 0xff; | ||
149 | } | ||
150 | } | ||
151 | if (slot == 13) { | ||
152 | switch (pin) { | ||
153 | case 1: return AU1500_PCI_INTA; | ||
154 | case 2: return AU1500_PCI_INTB; | ||
155 | case 3: return AU1500_PCI_INTC; | ||
156 | case 4: return AU1500_PCI_INTD; | ||
157 | } | ||
158 | } | ||
159 | return -1; | ||
160 | } | ||
161 | #endif | ||
162 | |||
163 | #ifdef CONFIG_MIPS_MIRAGE | ||
164 | static int db1xxx_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
165 | { | ||
166 | if ((slot < 11) || (slot > 13) || pin == 0) | ||
167 | return -1; | ||
168 | if (slot == 11) | ||
169 | return (pin == 1) ? AU1500_PCI_INTD : 0xff; | ||
170 | if (slot == 12) | ||
171 | return (pin == 3) ? AU1500_PCI_INTC : 0xff; | ||
172 | if (slot == 13) { | ||
173 | switch (pin) { | ||
174 | case 1: return AU1500_PCI_INTA; | ||
175 | case 2: return AU1500_PCI_INTB; | ||
176 | default: return 0xff; | ||
177 | } | ||
178 | } | ||
179 | return -1; | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | static struct resource alchemy_pci_host_res[] = { | ||
184 | [0] = { | ||
185 | .start = AU1500_PCI_PHYS_ADDR, | ||
186 | .end = AU1500_PCI_PHYS_ADDR + 0xfff, | ||
187 | .flags = IORESOURCE_MEM, | ||
188 | }, | ||
189 | }; | ||
190 | |||
191 | static struct alchemy_pci_platdata db1xxx_pci_pd = { | ||
192 | .board_map_irq = db1xxx_map_pci_irq, | ||
193 | }; | ||
194 | |||
195 | static struct platform_device db1xxx_pci_host_dev = { | ||
196 | .dev.platform_data = &db1xxx_pci_pd, | ||
197 | .name = "alchemy-pci", | ||
198 | .id = 0, | ||
199 | .num_resources = ARRAY_SIZE(alchemy_pci_host_res), | ||
200 | .resource = alchemy_pci_host_res, | ||
201 | }; | ||
202 | |||
203 | static int __init db15x0_pci_init(void) | ||
204 | { | ||
205 | return platform_device_register(&db1xxx_pci_host_dev); | ||
206 | } | ||
207 | /* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */ | ||
208 | arch_initcall(db15x0_pci_init); | ||
209 | #endif | ||
210 | |||
88 | static int __init db1xxx_dev_init(void) | 211 | static int __init db1xxx_dev_init(void) |
89 | { | 212 | { |
90 | #ifdef DB1XXX_HAS_PCMCIA | 213 | #ifdef DB1XXX_HAS_PCMCIA |
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c index 3b4fa3206969..37c1883b5ea9 100644 --- a/arch/mips/alchemy/devboards/pb1500/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c | |||
@@ -33,13 +33,6 @@ | |||
33 | 33 | ||
34 | #include <prom.h> | 34 | #include <prom.h> |
35 | 35 | ||
36 | |||
37 | char irq_tab_alchemy[][5] __initdata = { | ||
38 | [12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT370 */ | ||
39 | [13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */ | ||
40 | }; | ||
41 | |||
42 | |||
43 | const char *get_system_type(void) | 36 | const char *get_system_type(void) |
44 | { | 37 | { |
45 | return "Alchemy Pb1500"; | 38 | return "Alchemy Pb1500"; |
@@ -101,20 +94,18 @@ void __init board_setup(void) | |||
101 | #endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ | 94 | #endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ |
102 | 95 | ||
103 | #ifdef CONFIG_PCI | 96 | #ifdef CONFIG_PCI |
104 | /* Setup PCI bus controller */ | 97 | { |
105 | au_writel(0, Au1500_PCI_CMEM); | 98 | void __iomem *base = |
106 | au_writel(0x00003fff, Au1500_CFG_BASE); | 99 | (void __iomem *)KSEG1ADDR(AU1500_PCI_PHYS_ADDR); |
107 | #if defined(__MIPSEB__) | 100 | /* Setup PCI bus controller */ |
108 | au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG); | 101 | __raw_writel(0x00003fff, base + PCI_REG_CMEM); |
109 | #else | 102 | __raw_writel(0xf0000000, base + PCI_REG_MWMASK_DEV); |
110 | au_writel(0xf, Au1500_PCI_CFG); | 103 | __raw_writel(0, base + PCI_REG_MWBASE_REV_CCL); |
111 | #endif | 104 | __raw_writel(0x02a00356, base + PCI_REG_STATCMD); |
112 | au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV); | 105 | __raw_writel(0x00003c04, base + PCI_REG_PARAM); |
113 | au_writel(0, Au1500_PCI_MWBASE_REV_CCL); | 106 | __raw_writel(0x00000008, base + PCI_REG_MBAR); |
114 | au_writel(0x02a00356, Au1500_PCI_STATCMD); | 107 | wmb(); |
115 | au_writel(0x00003c04, Au1500_PCI_HDRTYPE); | 108 | } |
116 | au_writel(0x00000008, Au1500_PCI_MBAR); | ||
117 | au_sync(); | ||
118 | #endif | 109 | #endif |
119 | 110 | ||
120 | /* Enable sys bus clock divider when IDLE state or no bus activity. */ | 111 | /* Enable sys bus clock divider when IDLE state or no bus activity. */ |
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c index 42b0e6b8cd58..9f0b5a0b4795 100644 --- a/arch/mips/alchemy/devboards/pb1500/platform.c +++ b/arch/mips/alchemy/devboards/pb1500/platform.c | |||
@@ -19,11 +19,56 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/platform_device.h> | ||
22 | #include <asm/mach-au1x00/au1000.h> | 23 | #include <asm/mach-au1x00/au1000.h> |
23 | #include <asm/mach-db1x00/bcsr.h> | 24 | #include <asm/mach-db1x00/bcsr.h> |
24 | 25 | ||
25 | #include "../platform.h" | 26 | #include "../platform.h" |
26 | 27 | ||
28 | static int pb1500_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
29 | { | ||
30 | if ((slot < 12) || (slot > 13) || pin == 0) | ||
31 | return -1; | ||
32 | if (slot == 12) | ||
33 | return (pin == 1) ? AU1500_PCI_INTA : 0xff; | ||
34 | if (slot == 13) { | ||
35 | switch (pin) { | ||
36 | case 1: return AU1500_PCI_INTA; | ||
37 | case 2: return AU1500_PCI_INTB; | ||
38 | case 3: return AU1500_PCI_INTC; | ||
39 | case 4: return AU1500_PCI_INTD; | ||
40 | } | ||
41 | } | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | static struct resource alchemy_pci_host_res[] = { | ||
46 | [0] = { | ||
47 | .start = AU1500_PCI_PHYS_ADDR, | ||
48 | .end = AU1500_PCI_PHYS_ADDR + 0xfff, | ||
49 | .flags = IORESOURCE_MEM, | ||
50 | }, | ||
51 | }; | ||
52 | |||
53 | static struct alchemy_pci_platdata pb1500_pci_pd = { | ||
54 | .board_map_irq = pb1500_map_pci_irq, | ||
55 | .pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H | | ||
56 | PCI_CONFIG_CH | | ||
57 | #if defined(__MIPSEB__) | ||
58 | PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM, | ||
59 | #else | ||
60 | 0, | ||
61 | #endif | ||
62 | }; | ||
63 | |||
64 | static struct platform_device pb1500_pci_host = { | ||
65 | .dev.platform_data = &pb1500_pci_pd, | ||
66 | .name = "alchemy-pci", | ||
67 | .id = 0, | ||
68 | .num_resources = ARRAY_SIZE(alchemy_pci_host_res), | ||
69 | .resource = alchemy_pci_host_res, | ||
70 | }; | ||
71 | |||
27 | static int __init pb1500_dev_init(void) | 72 | static int __init pb1500_dev_init(void) |
28 | { | 73 | { |
29 | int swapped; | 74 | int swapped; |
@@ -41,7 +86,8 @@ static int __init pb1500_dev_init(void) | |||
41 | 86 | ||
42 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; | 87 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_DB1000_SWAPBOOT; |
43 | db1x_register_norflash(64 * 1024 * 1024, 4, swapped); | 88 | db1x_register_norflash(64 * 1024 * 1024, 4, swapped); |
89 | platform_device_register(&pb1500_pci_host); | ||
44 | 90 | ||
45 | return 0; | 91 | return 0; |
46 | } | 92 | } |
47 | device_initcall(pb1500_dev_init); | 93 | arch_initcall(pb1500_dev_init); |
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c index b790213848bd..0f62d1e3df24 100644 --- a/arch/mips/alchemy/devboards/pb1550/board_setup.c +++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c | |||
@@ -37,12 +37,6 @@ | |||
37 | 37 | ||
38 | #include <prom.h> | 38 | #include <prom.h> |
39 | 39 | ||
40 | |||
41 | char irq_tab_alchemy[][5] __initdata = { | ||
42 | [12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */ | ||
43 | [13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */ | ||
44 | }; | ||
45 | |||
46 | const char *get_system_type(void) | 40 | const char *get_system_type(void) |
47 | { | 41 | { |
48 | return "Alchemy Pb1550"; | 42 | return "Alchemy Pb1550"; |
diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c index 87c79b7f3123..0c5711fa0734 100644 --- a/arch/mips/alchemy/devboards/pb1550/platform.c +++ b/arch/mips/alchemy/devboards/pb1550/platform.c | |||
@@ -19,13 +19,56 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | 22 | #include <linux/platform_device.h> | |
23 | #include <asm/mach-au1x00/au1000.h> | 23 | #include <asm/mach-au1x00/au1000.h> |
24 | #include <asm/mach-pb1x00/pb1550.h> | 24 | #include <asm/mach-pb1x00/pb1550.h> |
25 | #include <asm/mach-db1x00/bcsr.h> | 25 | #include <asm/mach-db1x00/bcsr.h> |
26 | 26 | ||
27 | #include "../platform.h" | 27 | #include "../platform.h" |
28 | 28 | ||
29 | static int pb1550_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
30 | { | ||
31 | if ((slot < 12) || (slot > 13) || pin == 0) | ||
32 | return -1; | ||
33 | if (slot == 12) { | ||
34 | switch (pin) { | ||
35 | case 1: return AU1500_PCI_INTB; | ||
36 | case 2: return AU1500_PCI_INTC; | ||
37 | case 3: return AU1500_PCI_INTD; | ||
38 | case 4: return AU1500_PCI_INTA; | ||
39 | } | ||
40 | } | ||
41 | if (slot == 13) { | ||
42 | switch (pin) { | ||
43 | case 1: return AU1500_PCI_INTA; | ||
44 | case 2: return AU1500_PCI_INTB; | ||
45 | case 3: return AU1500_PCI_INTC; | ||
46 | case 4: return AU1500_PCI_INTD; | ||
47 | } | ||
48 | } | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | static struct resource alchemy_pci_host_res[] = { | ||
53 | [0] = { | ||
54 | .start = AU1500_PCI_PHYS_ADDR, | ||
55 | .end = AU1500_PCI_PHYS_ADDR + 0xfff, | ||
56 | .flags = IORESOURCE_MEM, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | static struct alchemy_pci_platdata pb1550_pci_pd = { | ||
61 | .board_map_irq = pb1550_map_pci_irq, | ||
62 | }; | ||
63 | |||
64 | static struct platform_device pb1550_pci_host = { | ||
65 | .dev.platform_data = &pb1550_pci_pd, | ||
66 | .name = "alchemy-pci", | ||
67 | .id = 0, | ||
68 | .num_resources = ARRAY_SIZE(alchemy_pci_host_res), | ||
69 | .resource = alchemy_pci_host_res, | ||
70 | }; | ||
71 | |||
29 | static int __init pb1550_dev_init(void) | 72 | static int __init pb1550_dev_init(void) |
30 | { | 73 | { |
31 | int swapped; | 74 | int swapped; |
@@ -57,7 +100,8 @@ static int __init pb1550_dev_init(void) | |||
57 | 100 | ||
58 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT; | 101 | swapped = bcsr_read(BCSR_STATUS) & BCSR_STATUS_PB1550_SWAPBOOT; |
59 | db1x_register_norflash(128 * 1024 * 1024, 4, swapped); | 102 | db1x_register_norflash(128 * 1024 * 1024, 4, swapped); |
103 | platform_device_register(&pb1550_pci_host); | ||
60 | 104 | ||
61 | return 0; | 105 | return 0; |
62 | } | 106 | } |
63 | device_initcall(pb1550_dev_init); | 107 | arch_initcall(pb1550_dev_init); |
diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c index 5f8f0691ed2d..dea45c78fdcd 100644 --- a/arch/mips/alchemy/gpr/board_setup.c +++ b/arch/mips/alchemy/gpr/board_setup.c | |||
@@ -36,10 +36,6 @@ | |||
36 | 36 | ||
37 | #include <prom.h> | 37 | #include <prom.h> |
38 | 38 | ||
39 | char irq_tab_alchemy[][5] __initdata = { | ||
40 | [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, | ||
41 | }; | ||
42 | |||
43 | static void gpr_reset(char *c) | 39 | static void gpr_reset(char *c) |
44 | { | 40 | { |
45 | /* switch System-LED to orange (red# and green# on) */ | 41 | /* switch System-LED to orange (red# and green# on) */ |
@@ -76,12 +72,4 @@ void __init board_setup(void) | |||
76 | 72 | ||
77 | /* Take away Reset of UMTS-card */ | 73 | /* Take away Reset of UMTS-card */ |
78 | alchemy_gpio_direction_output(215, 1); | 74 | alchemy_gpio_direction_output(215, 1); |
79 | |||
80 | #ifdef CONFIG_PCI | ||
81 | #if defined(__MIPSEB__) | ||
82 | au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG); | ||
83 | #else | ||
84 | au_writel(0xf, Au1500_PCI_CFG); | ||
85 | #endif | ||
86 | #endif | ||
87 | } | 75 | } |
diff --git a/arch/mips/alchemy/gpr/platform.c b/arch/mips/alchemy/gpr/platform.c index 14b46629cfc8..982ce85db60d 100644 --- a/arch/mips/alchemy/gpr/platform.c +++ b/arch/mips/alchemy/gpr/platform.c | |||
@@ -167,6 +167,45 @@ static struct i2c_board_info gpr_i2c_info[] __initdata = { | |||
167 | } | 167 | } |
168 | }; | 168 | }; |
169 | 169 | ||
170 | |||
171 | |||
172 | static struct resource alchemy_pci_host_res[] = { | ||
173 | [0] = { | ||
174 | .start = AU1500_PCI_PHYS_ADDR, | ||
175 | .end = AU1500_PCI_PHYS_ADDR + 0xfff, | ||
176 | .flags = IORESOURCE_MEM, | ||
177 | }, | ||
178 | }; | ||
179 | |||
180 | static int gpr_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
181 | { | ||
182 | if ((slot == 0) && (pin == 1)) | ||
183 | return AU1550_PCI_INTA; | ||
184 | else if ((slot == 0) && (pin == 2)) | ||
185 | return AU1550_PCI_INTB; | ||
186 | |||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | static struct alchemy_pci_platdata gpr_pci_pd = { | ||
191 | .board_map_irq = gpr_map_pci_irq, | ||
192 | .pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H | | ||
193 | PCI_CONFIG_CH | | ||
194 | #if defined(__MIPSEB__) | ||
195 | PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM, | ||
196 | #else | ||
197 | 0, | ||
198 | #endif | ||
199 | }; | ||
200 | |||
201 | static struct platform_device gpr_pci_host_dev = { | ||
202 | .dev.platform_data = &gpr_pci_pd, | ||
203 | .name = "alchemy-pci", | ||
204 | .id = 0, | ||
205 | .num_resources = ARRAY_SIZE(alchemy_pci_host_res), | ||
206 | .resource = alchemy_pci_host_res, | ||
207 | }; | ||
208 | |||
170 | static struct platform_device *gpr_devices[] __initdata = { | 209 | static struct platform_device *gpr_devices[] __initdata = { |
171 | &gpr_wdt_device, | 210 | &gpr_wdt_device, |
172 | &gpr_mtd_device, | 211 | &gpr_mtd_device, |
@@ -174,6 +213,14 @@ static struct platform_device *gpr_devices[] __initdata = { | |||
174 | &gpr_led_devices, | 213 | &gpr_led_devices, |
175 | }; | 214 | }; |
176 | 215 | ||
216 | static int __init gpr_pci_init(void) | ||
217 | { | ||
218 | return platform_device_register(&gpr_pci_host_dev); | ||
219 | } | ||
220 | /* must be arch_initcall; MIPS PCI scans busses in a subsys_initcall */ | ||
221 | arch_initcall(gpr_pci_init); | ||
222 | |||
223 | |||
177 | static int __init gpr_dev_init(void) | 224 | static int __init gpr_dev_init(void) |
178 | { | 225 | { |
179 | i2c_register_board_info(0, gpr_i2c_info, ARRAY_SIZE(gpr_i2c_info)); | 226 | i2c_register_board_info(0, gpr_i2c_info, ARRAY_SIZE(gpr_i2c_info)); |
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c index 3ae984cf98cf..851a5ab4c8f2 100644 --- a/arch/mips/alchemy/mtx-1/board_setup.c +++ b/arch/mips/alchemy/mtx-1/board_setup.c | |||
@@ -38,20 +38,6 @@ | |||
38 | 38 | ||
39 | #include <prom.h> | 39 | #include <prom.h> |
40 | 40 | ||
41 | char irq_tab_alchemy[][5] __initdata = { | ||
42 | [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 00 - AdapterA-Slot0 (top) */ | ||
43 | [1] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */ | ||
44 | [2] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 02 - AdapterB-Slot0 (top) */ | ||
45 | [3] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */ | ||
46 | [4] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 04 - AdapterC-Slot0 (top) */ | ||
47 | [5] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */ | ||
48 | [6] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 06 - AdapterD-Slot0 (top) */ | ||
49 | [7] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */ | ||
50 | }; | ||
51 | |||
52 | extern int (*board_pci_idsel)(unsigned int devsel, int assert); | ||
53 | int mtx1_pci_idsel(unsigned int devsel, int assert); | ||
54 | |||
55 | static void mtx1_reset(char *c) | 41 | static void mtx1_reset(char *c) |
56 | { | 42 | { |
57 | /* Jump to the reset vector */ | 43 | /* Jump to the reset vector */ |
@@ -74,15 +60,6 @@ void __init board_setup(void) | |||
74 | alchemy_gpio_direction_output(204, 0); | 60 | alchemy_gpio_direction_output(204, 0); |
75 | #endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ | 61 | #endif /* defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) */ |
76 | 62 | ||
77 | #ifdef CONFIG_PCI | ||
78 | #if defined(__MIPSEB__) | ||
79 | au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG); | ||
80 | #else | ||
81 | au_writel(0xf, Au1500_PCI_CFG); | ||
82 | #endif | ||
83 | board_pci_idsel = mtx1_pci_idsel; | ||
84 | #endif | ||
85 | |||
86 | /* Initialize sys_pinfunc */ | 63 | /* Initialize sys_pinfunc */ |
87 | au_writel(SYS_PF_NI2, SYS_PINFUNC); | 64 | au_writel(SYS_PF_NI2, SYS_PINFUNC); |
88 | 65 | ||
@@ -104,23 +81,6 @@ void __init board_setup(void) | |||
104 | printk(KERN_INFO "4G Systems MTX-1 Board\n"); | 81 | printk(KERN_INFO "4G Systems MTX-1 Board\n"); |
105 | } | 82 | } |
106 | 83 | ||
107 | int | ||
108 | mtx1_pci_idsel(unsigned int devsel, int assert) | ||
109 | { | ||
110 | /* This function is only necessary to support a proprietary Cardbus | ||
111 | * adapter on the mtx-1 "singleboard" variant. It triggers a custom | ||
112 | * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals. | ||
113 | */ | ||
114 | if (assert && devsel != 0) | ||
115 | /* Suppress signal to Cardbus */ | ||
116 | alchemy_gpio_set_value(1, 0); /* set EXT_IO3 OFF */ | ||
117 | else | ||
118 | alchemy_gpio_set_value(1, 1); /* set EXT_IO3 ON */ | ||
119 | |||
120 | udelay(1); | ||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | static int __init mtx1_init_irq(void) | 84 | static int __init mtx1_init_irq(void) |
125 | { | 85 | { |
126 | irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); | 86 | irq_set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH); |
diff --git a/arch/mips/alchemy/mtx-1/platform.c b/arch/mips/alchemy/mtx-1/platform.c index 55628e390fd7..cc47b6868ca3 100644 --- a/arch/mips/alchemy/mtx-1/platform.c +++ b/arch/mips/alchemy/mtx-1/platform.c | |||
@@ -135,7 +135,69 @@ static struct platform_device mtx1_mtd = { | |||
135 | .resource = &mtx1_mtd_resource, | 135 | .resource = &mtx1_mtd_resource, |
136 | }; | 136 | }; |
137 | 137 | ||
138 | static struct resource alchemy_pci_host_res[] = { | ||
139 | [0] = { | ||
140 | .start = AU1500_PCI_PHYS_ADDR, | ||
141 | .end = AU1500_PCI_PHYS_ADDR + 0xfff, | ||
142 | .flags = IORESOURCE_MEM, | ||
143 | }, | ||
144 | }; | ||
145 | |||
146 | static int mtx1_pci_idsel(unsigned int devsel, int assert) | ||
147 | { | ||
148 | /* This function is only necessary to support a proprietary Cardbus | ||
149 | * adapter on the mtx-1 "singleboard" variant. It triggers a custom | ||
150 | * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals. | ||
151 | */ | ||
152 | if (assert && devsel != 0) | ||
153 | /* Suppress signal to Cardbus */ | ||
154 | alchemy_gpio_set_value(1, 0); /* set EXT_IO3 OFF */ | ||
155 | else | ||
156 | alchemy_gpio_set_value(1, 1); /* set EXT_IO3 ON */ | ||
157 | |||
158 | udelay(1); | ||
159 | return 1; | ||
160 | } | ||
161 | |||
162 | static const char mtx1_irqtab[][5] = { | ||
163 | [0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 00 - AdapterA-Slot0 (top) */ | ||
164 | [1] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */ | ||
165 | [2] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 02 - AdapterB-Slot0 (top) */ | ||
166 | [3] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */ | ||
167 | [4] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 04 - AdapterC-Slot0 (top) */ | ||
168 | [5] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */ | ||
169 | [6] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 06 - AdapterD-Slot0 (top) */ | ||
170 | [7] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */ | ||
171 | }; | ||
172 | |||
173 | static int mtx1_map_pci_irq(const struct pci_dev *d, u8 slot, u8 pin) | ||
174 | { | ||
175 | return mtx1_irqtab[slot][pin]; | ||
176 | } | ||
177 | |||
178 | static struct alchemy_pci_platdata mtx1_pci_pd = { | ||
179 | .board_map_irq = mtx1_map_pci_irq, | ||
180 | .board_pci_idsel = mtx1_pci_idsel, | ||
181 | .pci_cfg_set = PCI_CONFIG_AEN | PCI_CONFIG_R2H | PCI_CONFIG_R1H | | ||
182 | PCI_CONFIG_CH | | ||
183 | #if defined(__MIPSEB__) | ||
184 | PCI_CONFIG_SIC_HWA_DAT | PCI_CONFIG_SM, | ||
185 | #else | ||
186 | 0, | ||
187 | #endif | ||
188 | }; | ||
189 | |||
190 | static struct platform_device mtx1_pci_host = { | ||
191 | .dev.platform_data = &mtx1_pci_pd, | ||
192 | .name = "alchemy-pci", | ||
193 | .id = 0, | ||
194 | .num_resources = ARRAY_SIZE(alchemy_pci_host_res), | ||
195 | .resource = alchemy_pci_host_res, | ||
196 | }; | ||
197 | |||
198 | |||
138 | static struct __initdata platform_device * mtx1_devs[] = { | 199 | static struct __initdata platform_device * mtx1_devs[] = { |
200 | &mtx1_pci_host, | ||
139 | &mtx1_gpio_leds, | 201 | &mtx1_gpio_leds, |
140 | &mtx1_wdt, | 202 | &mtx1_wdt, |
141 | &mtx1_button, | 203 | &mtx1_button, |
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c index 81e57fad07ab..3fa83f72e014 100644 --- a/arch/mips/alchemy/xxs1500/board_setup.c +++ b/arch/mips/alchemy/xxs1500/board_setup.c | |||
@@ -70,14 +70,6 @@ void __init board_setup(void) | |||
70 | /* Enable DTR (MCR bit 0) = USB power up */ | 70 | /* Enable DTR (MCR bit 0) = USB power up */ |
71 | __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); | 71 | __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18)); |
72 | wmb(); | 72 | wmb(); |
73 | |||
74 | #ifdef CONFIG_PCI | ||
75 | #if defined(__MIPSEB__) | ||
76 | au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG); | ||
77 | #else | ||
78 | au_writel(0xf, Au1500_PCI_CFG); | ||
79 | #endif | ||
80 | #endif | ||
81 | } | 73 | } |
82 | 74 | ||
83 | static int __init xxs1500_init_irq(void) | 75 | static int __init xxs1500_init_irq(void) |
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index 1bbcb30c4ab9..49a227d681e3 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h | |||
@@ -254,6 +254,14 @@ enum alchemy_usb_block { | |||
254 | }; | 254 | }; |
255 | int alchemy_usb_control(int block, int enable); | 255 | int alchemy_usb_control(int block, int enable); |
256 | 256 | ||
257 | /* PCI controller platform data */ | ||
258 | struct alchemy_pci_platdata { | ||
259 | int (*board_map_irq)(const struct pci_dev *d, u8 slot, u8 pin); | ||
260 | int (*board_pci_idsel)(unsigned int devsel, int assert); | ||
261 | /* bits to set/clear in PCI_CONFIG register */ | ||
262 | unsigned long pci_cfg_set; | ||
263 | unsigned long pci_cfg_clr; | ||
264 | }; | ||
257 | 265 | ||
258 | /* SOC Interrupt numbers */ | 266 | /* SOC Interrupt numbers */ |
259 | 267 | ||
@@ -1309,58 +1317,30 @@ enum soc_au1200_ints { | |||
1309 | # define AC97C_RS (1 << 1) | 1317 | # define AC97C_RS (1 << 1) |
1310 | # define AC97C_CE (1 << 0) | 1318 | # define AC97C_CE (1 << 0) |
1311 | 1319 | ||
1312 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
1313 | /* Au1500 PCI Controller */ | ||
1314 | #define Au1500_CFG_BASE 0xB4005000 /* virtual, KSEG1 addr */ | ||
1315 | #define Au1500_PCI_CMEM (Au1500_CFG_BASE + 0) | ||
1316 | #define Au1500_PCI_CFG (Au1500_CFG_BASE + 4) | ||
1317 | # define PCI_ERROR ((1 << 22) | (1 << 23) | (1 << 24) | \ | ||
1318 | (1 << 25) | (1 << 26) | (1 << 27)) | ||
1319 | #define Au1500_PCI_B2BMASK_CCH (Au1500_CFG_BASE + 8) | ||
1320 | #define Au1500_PCI_B2B0_VID (Au1500_CFG_BASE + 0xC) | ||
1321 | #define Au1500_PCI_B2B1_ID (Au1500_CFG_BASE + 0x10) | ||
1322 | #define Au1500_PCI_MWMASK_DEV (Au1500_CFG_BASE + 0x14) | ||
1323 | #define Au1500_PCI_MWBASE_REV_CCL (Au1500_CFG_BASE + 0x18) | ||
1324 | #define Au1500_PCI_ERR_ADDR (Au1500_CFG_BASE + 0x1C) | ||
1325 | #define Au1500_PCI_SPEC_INTACK (Au1500_CFG_BASE + 0x20) | ||
1326 | #define Au1500_PCI_ID (Au1500_CFG_BASE + 0x100) | ||
1327 | #define Au1500_PCI_STATCMD (Au1500_CFG_BASE + 0x104) | ||
1328 | #define Au1500_PCI_CLASSREV (Au1500_CFG_BASE + 0x108) | ||
1329 | #define Au1500_PCI_HDRTYPE (Au1500_CFG_BASE + 0x10C) | ||
1330 | #define Au1500_PCI_MBAR (Au1500_CFG_BASE + 0x110) | ||
1331 | |||
1332 | #define Au1500_PCI_HDR 0xB4005100 /* virtual, KSEG1 addr */ | ||
1333 | 1320 | ||
1334 | /* | 1321 | /* The PCI chip selects are outside the 32bit space, and since we can't |
1335 | * All of our structures, like PCI resource, have 32-bit members. | 1322 | * just program the 36bit addresses into BARs, we have to take a chunk |
1336 | * Drivers are expected to do an ioremap on the PCI MEM resource, but it's | 1323 | * out of the 32bit space and reserve it for PCI. When these addresses |
1337 | * hard to store 0x4 0000 0000 in a 32-bit type. We require a small patch | 1324 | * are ioremap()ed, they'll be fixed up to the real 36bit address before |
1338 | * to __ioremap to check for addresses between (u32)Au1500_PCI_MEM_START and | 1325 | * being passed to the real ioremap function. |
1339 | * (u32)Au1500_PCI_MEM_END and change those to the full 36-bit PCI MEM | ||
1340 | * addresses. For PCI I/O, it's simpler because we get to do the ioremap | ||
1341 | * ourselves and then adjust the device's resources. | ||
1342 | */ | 1326 | */ |
1343 | #define Au1500_EXT_CFG 0x600000000ULL | 1327 | #define ALCHEMY_PCI_MEMWIN_START (AU1500_PCI_MEM_PHYS_ADDR >> 4) |
1344 | #define Au1500_EXT_CFG_TYPE1 0x680000000ULL | 1328 | #define ALCHEMY_PCI_MEMWIN_END (ALCHEMY_PCI_MEMWIN_START + 0x0FFFFFFF) |
1345 | #define Au1500_PCI_IO_START 0x500000000ULL | ||
1346 | #define Au1500_PCI_IO_END 0x5000FFFFFULL | ||
1347 | #define Au1500_PCI_MEM_START 0x440000000ULL | ||
1348 | #define Au1500_PCI_MEM_END 0x44FFFFFFFULL | ||
1349 | 1329 | ||
1350 | #define PCI_IO_START 0x00001000 | 1330 | /* for PCI IO it's simpler because we get to do the ioremap ourselves and then |
1351 | #define PCI_IO_END 0x000FFFFF | 1331 | * adjust the device's resources. |
1352 | #define PCI_MEM_START 0x40000000 | 1332 | */ |
1353 | #define PCI_MEM_END 0x4FFFFFFF | 1333 | #define ALCHEMY_PCI_IOWIN_START 0x00001000 |
1334 | #define ALCHEMY_PCI_IOWIN_END 0x0000FFFF | ||
1354 | 1335 | ||
1355 | #define PCI_FIRST_DEVFN (0 << 3) | 1336 | #ifdef CONFIG_PCI |
1356 | #define PCI_LAST_DEVFN (19 << 3) | ||
1357 | 1337 | ||
1358 | #define IOPORT_RESOURCE_START 0x00001000 /* skip legacy probing */ | 1338 | #define IOPORT_RESOURCE_START 0x00001000 /* skip legacy probing */ |
1359 | #define IOPORT_RESOURCE_END 0xffffffff | 1339 | #define IOPORT_RESOURCE_END 0xffffffff |
1360 | #define IOMEM_RESOURCE_START 0x10000000 | 1340 | #define IOMEM_RESOURCE_START 0x10000000 |
1361 | #define IOMEM_RESOURCE_END 0xfffffffffULL | 1341 | #define IOMEM_RESOURCE_END 0xfffffffffULL |
1362 | 1342 | ||
1363 | #else /* Au1000 and Au1100 and Au1200 */ | 1343 | #else |
1364 | 1344 | ||
1365 | /* Don't allow any legacy ports probing */ | 1345 | /* Don't allow any legacy ports probing */ |
1366 | #define IOPORT_RESOURCE_START 0x10000000 | 1346 | #define IOPORT_RESOURCE_START 0x10000000 |
@@ -1368,13 +1348,77 @@ enum soc_au1200_ints { | |||
1368 | #define IOMEM_RESOURCE_START 0x10000000 | 1348 | #define IOMEM_RESOURCE_START 0x10000000 |
1369 | #define IOMEM_RESOURCE_END 0xfffffffffULL | 1349 | #define IOMEM_RESOURCE_END 0xfffffffffULL |
1370 | 1350 | ||
1371 | #define PCI_IO_START 0 | ||
1372 | #define PCI_IO_END 0 | ||
1373 | #define PCI_MEM_START 0 | ||
1374 | #define PCI_MEM_END 0 | ||
1375 | #define PCI_FIRST_DEVFN 0 | ||
1376 | #define PCI_LAST_DEVFN 0 | ||
1377 | |||
1378 | #endif | 1351 | #endif |
1379 | 1352 | ||
1353 | /* PCI controller block register offsets */ | ||
1354 | #define PCI_REG_CMEM 0x0000 | ||
1355 | #define PCI_REG_CONFIG 0x0004 | ||
1356 | #define PCI_REG_B2BMASK_CCH 0x0008 | ||
1357 | #define PCI_REG_B2BBASE0_VID 0x000C | ||
1358 | #define PCI_REG_B2BBASE1_SID 0x0010 | ||
1359 | #define PCI_REG_MWMASK_DEV 0x0014 | ||
1360 | #define PCI_REG_MWBASE_REV_CCL 0x0018 | ||
1361 | #define PCI_REG_ERR_ADDR 0x001C | ||
1362 | #define PCI_REG_SPEC_INTACK 0x0020 | ||
1363 | #define PCI_REG_ID 0x0100 | ||
1364 | #define PCI_REG_STATCMD 0x0104 | ||
1365 | #define PCI_REG_CLASSREV 0x0108 | ||
1366 | #define PCI_REG_PARAM 0x010C | ||
1367 | #define PCI_REG_MBAR 0x0110 | ||
1368 | #define PCI_REG_TIMEOUT 0x0140 | ||
1369 | |||
1370 | /* PCI controller block register bits */ | ||
1371 | #define PCI_CMEM_E (1 << 28) /* enable cacheable memory */ | ||
1372 | #define PCI_CMEM_CMBASE(x) (((x) & 0x3fff) << 14) | ||
1373 | #define PCI_CMEM_CMMASK(x) ((x) & 0x3fff) | ||
1374 | #define PCI_CONFIG_ERD (1 << 27) /* pci error during R/W */ | ||
1375 | #define PCI_CONFIG_ET (1 << 26) /* error in target mode */ | ||
1376 | #define PCI_CONFIG_EF (1 << 25) /* fatal error */ | ||
1377 | #define PCI_CONFIG_EP (1 << 24) /* parity error */ | ||
1378 | #define PCI_CONFIG_EM (1 << 23) /* multiple errors */ | ||
1379 | #define PCI_CONFIG_BM (1 << 22) /* bad master error */ | ||
1380 | #define PCI_CONFIG_PD (1 << 20) /* PCI Disable */ | ||
1381 | #define PCI_CONFIG_BME (1 << 19) /* Byte Mask Enable for reads */ | ||
1382 | #define PCI_CONFIG_NC (1 << 16) /* mark mem access non-coherent */ | ||
1383 | #define PCI_CONFIG_IA (1 << 15) /* INTA# enabled (target mode) */ | ||
1384 | #define PCI_CONFIG_IP (1 << 13) /* int on PCI_PERR# */ | ||
1385 | #define PCI_CONFIG_IS (1 << 12) /* int on PCI_SERR# */ | ||
1386 | #define PCI_CONFIG_IMM (1 << 11) /* int on master abort */ | ||
1387 | #define PCI_CONFIG_ITM (1 << 10) /* int on target abort (as master) */ | ||
1388 | #define PCI_CONFIG_ITT (1 << 9) /* int on target abort (as target) */ | ||
1389 | #define PCI_CONFIG_IPB (1 << 8) /* int on PERR# in bus master acc */ | ||
1390 | #define PCI_CONFIG_SIC_NO (0 << 6) /* no byte mask changes */ | ||
1391 | #define PCI_CONFIG_SIC_BA_ADR (1 << 6) /* on byte/hw acc, invert adr bits */ | ||
1392 | #define PCI_CONFIG_SIC_HWA_DAT (2 << 6) /* on halfword acc, swap data */ | ||
1393 | #define PCI_CONFIG_SIC_ALL (3 << 6) /* swap data bytes on all accesses */ | ||
1394 | #define PCI_CONFIG_ST (1 << 5) /* swap data by target transactions */ | ||
1395 | #define PCI_CONFIG_SM (1 << 4) /* swap data from PCI ctl */ | ||
1396 | #define PCI_CONFIG_AEN (1 << 3) /* enable internal arbiter */ | ||
1397 | #define PCI_CONFIG_R2H (1 << 2) /* REQ2# to hi-prio arbiter */ | ||
1398 | #define PCI_CONFIG_R1H (1 << 1) /* REQ1# to hi-prio arbiter */ | ||
1399 | #define PCI_CONFIG_CH (1 << 0) /* PCI ctl to hi-prio arbiter */ | ||
1400 | #define PCI_B2BMASK_B2BMASK(x) (((x) & 0xffff) << 16) | ||
1401 | #define PCI_B2BMASK_CCH(x) ((x) & 0xffff) /* 16 upper bits of class code */ | ||
1402 | #define PCI_B2BBASE0_VID_B0(x) (((x) & 0xffff) << 16) | ||
1403 | #define PCI_B2BBASE0_VID_SV(x) ((x) & 0xffff) | ||
1404 | #define PCI_B2BBASE1_SID_B1(x) (((x) & 0xffff) << 16) | ||
1405 | #define PCI_B2BBASE1_SID_SI(x) ((x) & 0xffff) | ||
1406 | #define PCI_MWMASKDEV_MWMASK(x) (((x) & 0xffff) << 16) | ||
1407 | #define PCI_MWMASKDEV_DEVID(x) ((x) & 0xffff) | ||
1408 | #define PCI_MWBASEREVCCL_BASE(x) (((x) & 0xffff) << 16) | ||
1409 | #define PCI_MWBASEREVCCL_REV(x) (((x) & 0xff) << 8) | ||
1410 | #define PCI_MWBASEREVCCL_CCL(x) ((x) & 0xff) | ||
1411 | #define PCI_ID_DID(x) (((x) & 0xffff) << 16) | ||
1412 | #define PCI_ID_VID(x) ((x) & 0xffff) | ||
1413 | #define PCI_STATCMD_STATUS(x) (((x) & 0xffff) << 16) | ||
1414 | #define PCI_STATCMD_CMD(x) ((x) & 0xffff) | ||
1415 | #define PCI_CLASSREV_CLASS(x) (((x) & 0x00ffffff) << 8) | ||
1416 | #define PCI_CLASSREV_REV(x) ((x) & 0xff) | ||
1417 | #define PCI_PARAM_BIST(x) (((x) & 0xff) << 24) | ||
1418 | #define PCI_PARAM_HT(x) (((x) & 0xff) << 16) | ||
1419 | #define PCI_PARAM_LT(x) (((x) & 0xff) << 8) | ||
1420 | #define PCI_PARAM_CLS(x) ((x) & 0xff) | ||
1421 | #define PCI_TIMEOUT_RETRIES(x) (((x) & 0xff) << 8) /* max retries */ | ||
1422 | #define PCI_TIMEOUT_TO(x) ((x) & 0xff) /* target ready timeout */ | ||
1423 | |||
1380 | #endif | 1424 | #endif |
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 4df879937446..bb82cbdbc62a 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile | |||
@@ -18,14 +18,13 @@ obj-$(CONFIG_PCI_TX4927) += ops-tx4927.o | |||
18 | obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o | 18 | obj-$(CONFIG_BCM47XX) += pci-bcm47xx.o |
19 | obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ | 19 | obj-$(CONFIG_BCM63XX) += pci-bcm63xx.o fixup-bcm63xx.o \ |
20 | ops-bcm63xx.o | 20 | ops-bcm63xx.o |
21 | obj-$(CONFIG_MIPS_ALCHEMY) += pci-alchemy.o | ||
21 | 22 | ||
22 | # | 23 | # |
23 | # These are still pretty much in the old state, watch, go blind. | 24 | # These are still pretty much in the old state, watch, go blind. |
24 | # | 25 | # |
25 | obj-$(CONFIG_LASAT) += pci-lasat.o | 26 | obj-$(CONFIG_LASAT) += pci-lasat.o |
26 | obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o | 27 | obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o |
27 | obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o | ||
28 | obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o | ||
29 | obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o | 28 | obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o |
30 | obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o | 29 | obj-$(CONFIG_LEMOTE_FULOONG2E) += fixup-fuloong2e.o ops-loongson2.o |
31 | obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o | 30 | obj-$(CONFIG_LEMOTE_MACH2F) += fixup-lemote2f.o ops-loongson2.o |
diff --git a/arch/mips/pci/fixup-au1000.c b/arch/mips/pci/fixup-au1000.c deleted file mode 100644 index e2ddfc49237c..000000000000 --- a/arch/mips/pci/fixup-au1000.c +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Board specific PCI fixups. | ||
4 | * | ||
5 | * Copyright 2001-2003, 2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License along | ||
25 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
27 | */ | ||
28 | |||
29 | #include <linux/pci.h> | ||
30 | #include <linux/init.h> | ||
31 | |||
32 | extern char irq_tab_alchemy[][5]; | ||
33 | |||
34 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
35 | { | ||
36 | return irq_tab_alchemy[slot][pin]; | ||
37 | } | ||
38 | |||
39 | /* Do platform specific device initialization at pci_enable_device() time */ | ||
40 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
41 | { | ||
42 | return 0; | ||
43 | } | ||
diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c deleted file mode 100644 index 9a57c5ab91dd..000000000000 --- a/arch/mips/pci/ops-au1000.c +++ /dev/null | |||
@@ -1,308 +0,0 @@ | |||
1 | /* | ||
2 | * BRIEF MODULE DESCRIPTION | ||
3 | * Alchemy/AMD Au1xx0 PCI support. | ||
4 | * | ||
5 | * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. | ||
6 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
7 | * | ||
8 | * Support for all devices (greater than 16) added by David Gathright. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
21 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License along | ||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/vmalloc.h> | ||
36 | |||
37 | #include <asm/mach-au1x00/au1000.h> | ||
38 | |||
39 | #undef DEBUG | ||
40 | #ifdef DEBUG | ||
41 | #define DBG(x...) printk(KERN_DEBUG x) | ||
42 | #else | ||
43 | #define DBG(x...) | ||
44 | #endif | ||
45 | |||
46 | #define PCI_ACCESS_READ 0 | ||
47 | #define PCI_ACCESS_WRITE 1 | ||
48 | |||
49 | int (*board_pci_idsel)(unsigned int devsel, int assert); | ||
50 | |||
51 | void mod_wired_entry(int entry, unsigned long entrylo0, | ||
52 | unsigned long entrylo1, unsigned long entryhi, | ||
53 | unsigned long pagemask) | ||
54 | { | ||
55 | unsigned long old_pagemask; | ||
56 | unsigned long old_ctx; | ||
57 | |||
58 | /* Save old context and create impossible VPN2 value */ | ||
59 | old_ctx = read_c0_entryhi() & 0xff; | ||
60 | old_pagemask = read_c0_pagemask(); | ||
61 | write_c0_index(entry); | ||
62 | write_c0_pagemask(pagemask); | ||
63 | write_c0_entryhi(entryhi); | ||
64 | write_c0_entrylo0(entrylo0); | ||
65 | write_c0_entrylo1(entrylo1); | ||
66 | tlb_write_indexed(); | ||
67 | write_c0_entryhi(old_ctx); | ||
68 | write_c0_pagemask(old_pagemask); | ||
69 | } | ||
70 | |||
71 | static struct vm_struct *pci_cfg_vm; | ||
72 | static int pci_cfg_wired_entry; | ||
73 | static unsigned long last_entryLo0, last_entryLo1; | ||
74 | |||
75 | /* | ||
76 | * We can't ioremap the entire pci config space because it's too large. | ||
77 | * Nor can we call ioremap dynamically because some device drivers use | ||
78 | * the PCI config routines from within interrupt handlers and that | ||
79 | * becomes a problem in get_vm_area(). We use one wired TLB to handle | ||
80 | * all config accesses for all busses. | ||
81 | */ | ||
82 | void __init au1x_pci_cfg_init(void) | ||
83 | { | ||
84 | /* Reserve a wired entry for PCI config accesses */ | ||
85 | pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); | ||
86 | if (!pci_cfg_vm) | ||
87 | panic(KERN_ERR "PCI unable to get vm area\n"); | ||
88 | pci_cfg_wired_entry = read_c0_wired(); | ||
89 | add_wired_entry(0, 0, (unsigned long)pci_cfg_vm->addr, PM_4K); | ||
90 | last_entryLo0 = last_entryLo1 = 0xffffffff; | ||
91 | } | ||
92 | |||
93 | static int config_access(unsigned char access_type, struct pci_bus *bus, | ||
94 | unsigned int dev_fn, unsigned char where, u32 *data) | ||
95 | { | ||
96 | #if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) | ||
97 | unsigned int device = PCI_SLOT(dev_fn); | ||
98 | unsigned int function = PCI_FUNC(dev_fn); | ||
99 | unsigned long offset, status; | ||
100 | unsigned long cfg_base; | ||
101 | unsigned long flags; | ||
102 | int error = PCIBIOS_SUCCESSFUL; | ||
103 | unsigned long entryLo0, entryLo1; | ||
104 | |||
105 | if (device > 19) { | ||
106 | *data = 0xffffffff; | ||
107 | return -1; | ||
108 | } | ||
109 | |||
110 | local_irq_save(flags); | ||
111 | au_writel(((0x2000 << 16) | (au_readl(Au1500_PCI_STATCMD) & 0xffff)), | ||
112 | Au1500_PCI_STATCMD); | ||
113 | au_sync_udelay(1); | ||
114 | |||
115 | /* | ||
116 | * Allow board vendors to implement their own off-chip IDSEL. | ||
117 | * If it doesn't succeed, may as well bail out at this point. | ||
118 | */ | ||
119 | if (board_pci_idsel && board_pci_idsel(device, 1) == 0) { | ||
120 | *data = 0xffffffff; | ||
121 | local_irq_restore(flags); | ||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | /* Setup the config window */ | ||
126 | if (bus->number == 0) | ||
127 | cfg_base = (1 << device) << 11; | ||
128 | else | ||
129 | cfg_base = 0x80000000 | (bus->number << 16) | (device << 11); | ||
130 | |||
131 | /* Setup the lower bits of the 36-bit address */ | ||
132 | offset = (function << 8) | (where & ~0x3); | ||
133 | /* Pick up any address that falls below the page mask */ | ||
134 | offset |= cfg_base & ~PAGE_MASK; | ||
135 | |||
136 | /* Page boundary */ | ||
137 | cfg_base = cfg_base & PAGE_MASK; | ||
138 | |||
139 | /* | ||
140 | * To improve performance, if the current device is the same as | ||
141 | * the last device accessed, we don't touch the TLB. | ||
142 | */ | ||
143 | entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7; | ||
144 | entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7; | ||
145 | if ((entryLo0 != last_entryLo0) || (entryLo1 != last_entryLo1)) { | ||
146 | mod_wired_entry(pci_cfg_wired_entry, entryLo0, entryLo1, | ||
147 | (unsigned long)pci_cfg_vm->addr, PM_4K); | ||
148 | last_entryLo0 = entryLo0; | ||
149 | last_entryLo1 = entryLo1; | ||
150 | } | ||
151 | |||
152 | if (access_type == PCI_ACCESS_WRITE) | ||
153 | au_writel(*data, (int)(pci_cfg_vm->addr + offset)); | ||
154 | else | ||
155 | *data = au_readl((int)(pci_cfg_vm->addr + offset)); | ||
156 | |||
157 | au_sync_udelay(2); | ||
158 | |||
159 | DBG("cfg_access %d bus->number %u dev %u at %x *data %x conf %lx\n", | ||
160 | access_type, bus->number, device, where, *data, offset); | ||
161 | |||
162 | /* Check master abort */ | ||
163 | status = au_readl(Au1500_PCI_STATCMD); | ||
164 | |||
165 | if (status & (1 << 29)) { | ||
166 | *data = 0xffffffff; | ||
167 | error = -1; | ||
168 | DBG("Au1x Master Abort\n"); | ||
169 | } else if ((status >> 28) & 0xf) { | ||
170 | DBG("PCI ERR detected: device %u, status %lx\n", | ||
171 | device, (status >> 28) & 0xf); | ||
172 | |||
173 | /* Clear errors */ | ||
174 | au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD); | ||
175 | |||
176 | *data = 0xffffffff; | ||
177 | error = -1; | ||
178 | } | ||
179 | |||
180 | /* Take away the IDSEL. */ | ||
181 | if (board_pci_idsel) | ||
182 | (void)board_pci_idsel(device, 0); | ||
183 | |||
184 | local_irq_restore(flags); | ||
185 | return error; | ||
186 | #endif | ||
187 | } | ||
188 | |||
189 | static int read_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
190 | int where, u8 *val) | ||
191 | { | ||
192 | u32 data; | ||
193 | int ret; | ||
194 | |||
195 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
196 | if (where & 1) | ||
197 | data >>= 8; | ||
198 | if (where & 2) | ||
199 | data >>= 16; | ||
200 | *val = data & 0xff; | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | static int read_config_word(struct pci_bus *bus, unsigned int devfn, | ||
205 | int where, u16 *val) | ||
206 | { | ||
207 | u32 data; | ||
208 | int ret; | ||
209 | |||
210 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
211 | if (where & 2) | ||
212 | data >>= 16; | ||
213 | *val = data & 0xffff; | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int read_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
218 | int where, u32 *val) | ||
219 | { | ||
220 | int ret; | ||
221 | |||
222 | ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int write_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
227 | int where, u8 val) | ||
228 | { | ||
229 | u32 data = 0; | ||
230 | |||
231 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
232 | return -1; | ||
233 | |||
234 | data = (data & ~(0xff << ((where & 3) << 3))) | | ||
235 | (val << ((where & 3) << 3)); | ||
236 | |||
237 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
238 | return -1; | ||
239 | |||
240 | return PCIBIOS_SUCCESSFUL; | ||
241 | } | ||
242 | |||
243 | static int write_config_word(struct pci_bus *bus, unsigned int devfn, | ||
244 | int where, u16 val) | ||
245 | { | ||
246 | u32 data = 0; | ||
247 | |||
248 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
249 | return -1; | ||
250 | |||
251 | data = (data & ~(0xffff << ((where & 3) << 3))) | | ||
252 | (val << ((where & 3) << 3)); | ||
253 | |||
254 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
255 | return -1; | ||
256 | |||
257 | return PCIBIOS_SUCCESSFUL; | ||
258 | } | ||
259 | |||
260 | static int write_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
261 | int where, u32 val) | ||
262 | { | ||
263 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val)) | ||
264 | return -1; | ||
265 | |||
266 | return PCIBIOS_SUCCESSFUL; | ||
267 | } | ||
268 | |||
269 | static int config_read(struct pci_bus *bus, unsigned int devfn, | ||
270 | int where, int size, u32 *val) | ||
271 | { | ||
272 | switch (size) { | ||
273 | case 1: { | ||
274 | u8 _val; | ||
275 | int rc = read_config_byte(bus, devfn, where, &_val); | ||
276 | |||
277 | *val = _val; | ||
278 | return rc; | ||
279 | } | ||
280 | case 2: { | ||
281 | u16 _val; | ||
282 | int rc = read_config_word(bus, devfn, where, &_val); | ||
283 | |||
284 | *val = _val; | ||
285 | return rc; | ||
286 | } | ||
287 | default: | ||
288 | return read_config_dword(bus, devfn, where, val); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | static int config_write(struct pci_bus *bus, unsigned int devfn, | ||
293 | int where, int size, u32 val) | ||
294 | { | ||
295 | switch (size) { | ||
296 | case 1: | ||
297 | return write_config_byte(bus, devfn, where, (u8) val); | ||
298 | case 2: | ||
299 | return write_config_word(bus, devfn, where, (u16) val); | ||
300 | default: | ||
301 | return write_config_dword(bus, devfn, where, val); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | struct pci_ops au1x_pci_ops = { | ||
306 | config_read, | ||
307 | config_write | ||
308 | }; | ||
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c new file mode 100644 index 000000000000..4ee57104e47b --- /dev/null +++ b/arch/mips/pci/pci-alchemy.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * Alchemy PCI host mode support. | ||
3 | * | ||
4 | * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. | ||
5 | * Author: MontaVista Software, Inc. <source@mvista.com> | ||
6 | * | ||
7 | * Support for all devices (greater than 16) added by David Gathright. | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/vmalloc.h> | ||
16 | |||
17 | #include <asm/mach-au1x00/au1000.h> | ||
18 | |||
19 | #ifdef CONFIG_DEBUG_PCI | ||
20 | #define DBG(x...) printk(KERN_DEBUG x) | ||
21 | #else | ||
22 | #define DBG(x...) do {} while (0) | ||
23 | #endif | ||
24 | |||
25 | #define PCI_ACCESS_READ 0 | ||
26 | #define PCI_ACCESS_WRITE 1 | ||
27 | |||
28 | struct alchemy_pci_context { | ||
29 | struct pci_controller alchemy_pci_ctrl; /* leave as first member! */ | ||
30 | void __iomem *regs; /* ctrl base */ | ||
31 | /* tools for wired entry for config space access */ | ||
32 | unsigned long last_elo0; | ||
33 | unsigned long last_elo1; | ||
34 | int wired_entry; | ||
35 | struct vm_struct *pci_cfg_vm; | ||
36 | |||
37 | unsigned long pm[12]; | ||
38 | |||
39 | int (*board_map_irq)(const struct pci_dev *d, u8 slot, u8 pin); | ||
40 | int (*board_pci_idsel)(unsigned int devsel, int assert); | ||
41 | }; | ||
42 | |||
43 | /* IO/MEM resources for PCI. Keep the memres in sync with __fixup_bigphys_addr | ||
44 | * in arch/mips/alchemy/common/setup.c | ||
45 | */ | ||
46 | static struct resource alchemy_pci_def_memres = { | ||
47 | .start = ALCHEMY_PCI_MEMWIN_START, | ||
48 | .end = ALCHEMY_PCI_MEMWIN_END, | ||
49 | .name = "PCI memory space", | ||
50 | .flags = IORESOURCE_MEM | ||
51 | }; | ||
52 | |||
53 | static struct resource alchemy_pci_def_iores = { | ||
54 | .start = ALCHEMY_PCI_IOWIN_START, | ||
55 | .end = ALCHEMY_PCI_IOWIN_END, | ||
56 | .name = "PCI IO space", | ||
57 | .flags = IORESOURCE_IO | ||
58 | }; | ||
59 | |||
60 | static void mod_wired_entry(int entry, unsigned long entrylo0, | ||
61 | unsigned long entrylo1, unsigned long entryhi, | ||
62 | unsigned long pagemask) | ||
63 | { | ||
64 | unsigned long old_pagemask; | ||
65 | unsigned long old_ctx; | ||
66 | |||
67 | /* Save old context and create impossible VPN2 value */ | ||
68 | old_ctx = read_c0_entryhi() & 0xff; | ||
69 | old_pagemask = read_c0_pagemask(); | ||
70 | write_c0_index(entry); | ||
71 | write_c0_pagemask(pagemask); | ||
72 | write_c0_entryhi(entryhi); | ||
73 | write_c0_entrylo0(entrylo0); | ||
74 | write_c0_entrylo1(entrylo1); | ||
75 | tlb_write_indexed(); | ||
76 | write_c0_entryhi(old_ctx); | ||
77 | write_c0_pagemask(old_pagemask); | ||
78 | } | ||
79 | |||
80 | static void alchemy_pci_wired_entry(struct alchemy_pci_context *ctx) | ||
81 | { | ||
82 | ctx->wired_entry = read_c0_wired(); | ||
83 | add_wired_entry(0, 0, (unsigned long)ctx->pci_cfg_vm->addr, PM_4K); | ||
84 | ctx->last_elo0 = ctx->last_elo1 = ~0; | ||
85 | } | ||
86 | |||
87 | static int config_access(unsigned char access_type, struct pci_bus *bus, | ||
88 | unsigned int dev_fn, unsigned char where, u32 *data) | ||
89 | { | ||
90 | struct alchemy_pci_context *ctx = bus->sysdata; | ||
91 | unsigned int device = PCI_SLOT(dev_fn); | ||
92 | unsigned int function = PCI_FUNC(dev_fn); | ||
93 | unsigned long offset, status, cfg_base, flags, entryLo0, entryLo1, r; | ||
94 | int error = PCIBIOS_SUCCESSFUL; | ||
95 | |||
96 | if (device > 19) { | ||
97 | *data = 0xffffffff; | ||
98 | return -1; | ||
99 | } | ||
100 | |||
101 | /* YAMON on all db1xxx boards wipes the TLB and writes zero to C0_wired | ||
102 | * on resume, clearing our wired entry. Unfortunately the ->resume() | ||
103 | * callback is called way way way too late (and ->suspend() too early) | ||
104 | * to have them destroy and recreate it. Instead just test if c0_wired | ||
105 | * is now lower than the index we retrieved before suspending and then | ||
106 | * recreate the entry if necessary. Of course this is totally bonkers | ||
107 | * and breaks as soon as someone else adds another wired entry somewhere | ||
108 | * else. Anyone have any ideas how to handle this better? | ||
109 | */ | ||
110 | if (unlikely(read_c0_wired() < ctx->wired_entry)) | ||
111 | alchemy_pci_wired_entry(ctx); | ||
112 | |||
113 | local_irq_save(flags); | ||
114 | r = __raw_readl(ctx->regs + PCI_REG_STATCMD) & 0x0000ffff; | ||
115 | r |= PCI_STATCMD_STATUS(0x2000); | ||
116 | __raw_writel(r, ctx->regs + PCI_REG_STATCMD); | ||
117 | wmb(); | ||
118 | |||
119 | /* Allow board vendors to implement their own off-chip IDSEL. | ||
120 | * If it doesn't succeed, may as well bail out at this point. | ||
121 | */ | ||
122 | if (ctx->board_pci_idsel(device, 1) == 0) { | ||
123 | *data = 0xffffffff; | ||
124 | local_irq_restore(flags); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | /* Setup the config window */ | ||
129 | if (bus->number == 0) | ||
130 | cfg_base = (1 << device) << 11; | ||
131 | else | ||
132 | cfg_base = 0x80000000 | (bus->number << 16) | (device << 11); | ||
133 | |||
134 | /* Setup the lower bits of the 36-bit address */ | ||
135 | offset = (function << 8) | (where & ~0x3); | ||
136 | /* Pick up any address that falls below the page mask */ | ||
137 | offset |= cfg_base & ~PAGE_MASK; | ||
138 | |||
139 | /* Page boundary */ | ||
140 | cfg_base = cfg_base & PAGE_MASK; | ||
141 | |||
142 | /* To improve performance, if the current device is the same as | ||
143 | * the last device accessed, we don't touch the TLB. | ||
144 | */ | ||
145 | entryLo0 = (6 << 26) | (cfg_base >> 6) | (2 << 3) | 7; | ||
146 | entryLo1 = (6 << 26) | (cfg_base >> 6) | (0x1000 >> 6) | (2 << 3) | 7; | ||
147 | if ((entryLo0 != ctx->last_elo0) || (entryLo1 != ctx->last_elo1)) { | ||
148 | mod_wired_entry(ctx->wired_entry, entryLo0, entryLo1, | ||
149 | (unsigned long)ctx->pci_cfg_vm->addr, PM_4K); | ||
150 | ctx->last_elo0 = entryLo0; | ||
151 | ctx->last_elo1 = entryLo1; | ||
152 | } | ||
153 | |||
154 | if (access_type == PCI_ACCESS_WRITE) | ||
155 | __raw_writel(*data, ctx->pci_cfg_vm->addr + offset); | ||
156 | else | ||
157 | *data = __raw_readl(ctx->pci_cfg_vm->addr + offset); | ||
158 | wmb(); | ||
159 | |||
160 | DBG("alchemy-pci: cfg access %d bus %u dev %u at %x dat %x conf %lx\n", | ||
161 | access_type, bus->number, device, where, *data, offset); | ||
162 | |||
163 | /* check for errors, master abort */ | ||
164 | status = __raw_readl(ctx->regs + PCI_REG_STATCMD); | ||
165 | if (status & (1 << 29)) { | ||
166 | *data = 0xffffffff; | ||
167 | error = -1; | ||
168 | DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d", | ||
169 | access_type, bus->number, device); | ||
170 | } else if ((status >> 28) & 0xf) { | ||
171 | DBG("alchemy-pci: PCI ERR detected: dev %d, status %lx\n", | ||
172 | device, (status >> 28) & 0xf); | ||
173 | |||
174 | /* clear errors */ | ||
175 | __raw_writel(status & 0xf000ffff, ctx->regs + PCI_REG_STATCMD); | ||
176 | |||
177 | *data = 0xffffffff; | ||
178 | error = -1; | ||
179 | } | ||
180 | |||
181 | /* Take away the IDSEL. */ | ||
182 | (void)ctx->board_pci_idsel(device, 0); | ||
183 | |||
184 | local_irq_restore(flags); | ||
185 | return error; | ||
186 | } | ||
187 | |||
188 | static int read_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
189 | int where, u8 *val) | ||
190 | { | ||
191 | u32 data; | ||
192 | int ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
193 | |||
194 | if (where & 1) | ||
195 | data >>= 8; | ||
196 | if (where & 2) | ||
197 | data >>= 16; | ||
198 | *val = data & 0xff; | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int read_config_word(struct pci_bus *bus, unsigned int devfn, | ||
203 | int where, u16 *val) | ||
204 | { | ||
205 | u32 data; | ||
206 | int ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data); | ||
207 | |||
208 | if (where & 2) | ||
209 | data >>= 16; | ||
210 | *val = data & 0xffff; | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | static int read_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
215 | int where, u32 *val) | ||
216 | { | ||
217 | return config_access(PCI_ACCESS_READ, bus, devfn, where, val); | ||
218 | } | ||
219 | |||
220 | static int write_config_byte(struct pci_bus *bus, unsigned int devfn, | ||
221 | int where, u8 val) | ||
222 | { | ||
223 | u32 data = 0; | ||
224 | |||
225 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
226 | return -1; | ||
227 | |||
228 | data = (data & ~(0xff << ((where & 3) << 3))) | | ||
229 | (val << ((where & 3) << 3)); | ||
230 | |||
231 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
232 | return -1; | ||
233 | |||
234 | return PCIBIOS_SUCCESSFUL; | ||
235 | } | ||
236 | |||
237 | static int write_config_word(struct pci_bus *bus, unsigned int devfn, | ||
238 | int where, u16 val) | ||
239 | { | ||
240 | u32 data = 0; | ||
241 | |||
242 | if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) | ||
243 | return -1; | ||
244 | |||
245 | data = (data & ~(0xffff << ((where & 3) << 3))) | | ||
246 | (val << ((where & 3) << 3)); | ||
247 | |||
248 | if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) | ||
249 | return -1; | ||
250 | |||
251 | return PCIBIOS_SUCCESSFUL; | ||
252 | } | ||
253 | |||
254 | static int write_config_dword(struct pci_bus *bus, unsigned int devfn, | ||
255 | int where, u32 val) | ||
256 | { | ||
257 | return config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val); | ||
258 | } | ||
259 | |||
260 | static int alchemy_pci_read(struct pci_bus *bus, unsigned int devfn, | ||
261 | int where, int size, u32 *val) | ||
262 | { | ||
263 | switch (size) { | ||
264 | case 1: { | ||
265 | u8 _val; | ||
266 | int rc = read_config_byte(bus, devfn, where, &_val); | ||
267 | |||
268 | *val = _val; | ||
269 | return rc; | ||
270 | } | ||
271 | case 2: { | ||
272 | u16 _val; | ||
273 | int rc = read_config_word(bus, devfn, where, &_val); | ||
274 | |||
275 | *val = _val; | ||
276 | return rc; | ||
277 | } | ||
278 | default: | ||
279 | return read_config_dword(bus, devfn, where, val); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static int alchemy_pci_write(struct pci_bus *bus, unsigned int devfn, | ||
284 | int where, int size, u32 val) | ||
285 | { | ||
286 | switch (size) { | ||
287 | case 1: | ||
288 | return write_config_byte(bus, devfn, where, (u8) val); | ||
289 | case 2: | ||
290 | return write_config_word(bus, devfn, where, (u16) val); | ||
291 | default: | ||
292 | return write_config_dword(bus, devfn, where, val); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static struct pci_ops alchemy_pci_ops = { | ||
297 | .read = alchemy_pci_read, | ||
298 | .write = alchemy_pci_write, | ||
299 | }; | ||
300 | |||
301 | static int alchemy_pci_def_idsel(unsigned int devsel, int assert) | ||
302 | { | ||
303 | return 1; /* success */ | ||
304 | } | ||
305 | |||
306 | static int __devinit alchemy_pci_probe(struct platform_device *pdev) | ||
307 | { | ||
308 | struct alchemy_pci_platdata *pd = pdev->dev.platform_data; | ||
309 | struct alchemy_pci_context *ctx; | ||
310 | void __iomem *virt_io; | ||
311 | unsigned long val; | ||
312 | struct resource *r; | ||
313 | int ret; | ||
314 | |||
315 | /* need at least PCI IRQ mapping table */ | ||
316 | if (!pd) { | ||
317 | dev_err(&pdev->dev, "need platform data for PCI setup\n"); | ||
318 | ret = -ENODEV; | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
323 | if (!ctx) { | ||
324 | dev_err(&pdev->dev, "no memory for pcictl context\n"); | ||
325 | ret = -ENOMEM; | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
330 | if (!r) { | ||
331 | dev_err(&pdev->dev, "no pcictl ctrl regs resource\n"); | ||
332 | ret = -ENODEV; | ||
333 | goto out1; | ||
334 | } | ||
335 | |||
336 | if (!request_mem_region(r->start, resource_size(r), pdev->name)) { | ||
337 | dev_err(&pdev->dev, "cannot claim pci regs\n"); | ||
338 | ret = -ENODEV; | ||
339 | goto out1; | ||
340 | } | ||
341 | |||
342 | ctx->regs = ioremap_nocache(r->start, resource_size(r)); | ||
343 | if (!ctx->regs) { | ||
344 | dev_err(&pdev->dev, "cannot map pci regs\n"); | ||
345 | ret = -ENODEV; | ||
346 | goto out2; | ||
347 | } | ||
348 | |||
349 | /* map parts of the PCI IO area */ | ||
350 | /* REVISIT: if this changes with a newer variant (doubt it) make this | ||
351 | * a platform resource. | ||
352 | */ | ||
353 | virt_io = ioremap(AU1500_PCI_IO_PHYS_ADDR, 0x00100000); | ||
354 | if (!virt_io) { | ||
355 | dev_err(&pdev->dev, "cannot remap pci io space\n"); | ||
356 | ret = -ENODEV; | ||
357 | goto out3; | ||
358 | } | ||
359 | ctx->alchemy_pci_ctrl.io_map_base = (unsigned long)virt_io; | ||
360 | |||
361 | #ifdef CONFIG_DMA_NONCOHERENT | ||
362 | /* Au1500 revisions older than AD have borked coherent PCI */ | ||
363 | if ((alchemy_get_cputype() == ALCHEMY_CPU_AU1500) && | ||
364 | (read_c0_prid() < 0x01030202)) { | ||
365 | val = __raw_readl(ctx->regs + PCI_REG_CONFIG); | ||
366 | val |= PCI_CONFIG_NC; | ||
367 | __raw_writel(val, ctx->regs + PCI_REG_CONFIG); | ||
368 | wmb(); | ||
369 | dev_info(&pdev->dev, "non-coherent PCI on Au1500 AA/AB/AC\n"); | ||
370 | } | ||
371 | #endif | ||
372 | |||
373 | if (pd->board_map_irq) | ||
374 | ctx->board_map_irq = pd->board_map_irq; | ||
375 | |||
376 | if (pd->board_pci_idsel) | ||
377 | ctx->board_pci_idsel = pd->board_pci_idsel; | ||
378 | else | ||
379 | ctx->board_pci_idsel = alchemy_pci_def_idsel; | ||
380 | |||
381 | /* fill in relevant pci_controller members */ | ||
382 | ctx->alchemy_pci_ctrl.pci_ops = &alchemy_pci_ops; | ||
383 | ctx->alchemy_pci_ctrl.mem_resource = &alchemy_pci_def_memres; | ||
384 | ctx->alchemy_pci_ctrl.io_resource = &alchemy_pci_def_iores; | ||
385 | |||
386 | /* we can't ioremap the entire pci config space because it's too large, | ||
387 | * nor can we dynamically ioremap it because some drivers use the | ||
388 | * PCI config routines from within atomic contex and that becomes a | ||
389 | * problem in get_vm_area(). Instead we use one wired TLB entry to | ||
390 | * handle all config accesses for all busses. | ||
391 | */ | ||
392 | ctx->pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); | ||
393 | if (!ctx->pci_cfg_vm) { | ||
394 | dev_err(&pdev->dev, "unable to get vm area\n"); | ||
395 | ret = -ENOMEM; | ||
396 | goto out4; | ||
397 | } | ||
398 | ctx->wired_entry = 8192; /* impossibly high value */ | ||
399 | |||
400 | set_io_port_base((unsigned long)ctx->alchemy_pci_ctrl.io_map_base); | ||
401 | |||
402 | /* board may want to modify bits in the config register, do it now */ | ||
403 | val = __raw_readl(ctx->regs + PCI_REG_CONFIG); | ||
404 | val &= ~pd->pci_cfg_clr; | ||
405 | val |= pd->pci_cfg_set; | ||
406 | val &= ~PCI_CONFIG_PD; /* clear disable bit */ | ||
407 | __raw_writel(val, ctx->regs + PCI_REG_CONFIG); | ||
408 | wmb(); | ||
409 | |||
410 | platform_set_drvdata(pdev, ctx); | ||
411 | register_pci_controller(&ctx->alchemy_pci_ctrl); | ||
412 | |||
413 | return 0; | ||
414 | |||
415 | out4: | ||
416 | iounmap(virt_io); | ||
417 | out3: | ||
418 | iounmap(ctx->regs); | ||
419 | out2: | ||
420 | release_mem_region(r->start, resource_size(r)); | ||
421 | out1: | ||
422 | kfree(ctx); | ||
423 | out: | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | |||
428 | #ifdef CONFIG_PM | ||
429 | /* save PCI controller register contents. */ | ||
430 | static int alchemy_pci_suspend(struct device *dev) | ||
431 | { | ||
432 | struct alchemy_pci_context *ctx = dev_get_drvdata(dev); | ||
433 | |||
434 | ctx->pm[0] = __raw_readl(ctx->regs + PCI_REG_CMEM); | ||
435 | ctx->pm[1] = __raw_readl(ctx->regs + PCI_REG_CONFIG) & 0x0009ffff; | ||
436 | ctx->pm[2] = __raw_readl(ctx->regs + PCI_REG_B2BMASK_CCH); | ||
437 | ctx->pm[3] = __raw_readl(ctx->regs + PCI_REG_B2BBASE0_VID); | ||
438 | ctx->pm[4] = __raw_readl(ctx->regs + PCI_REG_B2BBASE1_SID); | ||
439 | ctx->pm[5] = __raw_readl(ctx->regs + PCI_REG_MWMASK_DEV); | ||
440 | ctx->pm[6] = __raw_readl(ctx->regs + PCI_REG_MWBASE_REV_CCL); | ||
441 | ctx->pm[7] = __raw_readl(ctx->regs + PCI_REG_ID); | ||
442 | ctx->pm[8] = __raw_readl(ctx->regs + PCI_REG_CLASSREV); | ||
443 | ctx->pm[9] = __raw_readl(ctx->regs + PCI_REG_PARAM); | ||
444 | ctx->pm[10] = __raw_readl(ctx->regs + PCI_REG_MBAR); | ||
445 | ctx->pm[11] = __raw_readl(ctx->regs + PCI_REG_TIMEOUT); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int alchemy_pci_resume(struct device *dev) | ||
451 | { | ||
452 | struct alchemy_pci_context *ctx = dev_get_drvdata(dev); | ||
453 | |||
454 | __raw_writel(ctx->pm[0], ctx->regs + PCI_REG_CMEM); | ||
455 | __raw_writel(ctx->pm[2], ctx->regs + PCI_REG_B2BMASK_CCH); | ||
456 | __raw_writel(ctx->pm[3], ctx->regs + PCI_REG_B2BBASE0_VID); | ||
457 | __raw_writel(ctx->pm[4], ctx->regs + PCI_REG_B2BBASE1_SID); | ||
458 | __raw_writel(ctx->pm[5], ctx->regs + PCI_REG_MWMASK_DEV); | ||
459 | __raw_writel(ctx->pm[6], ctx->regs + PCI_REG_MWBASE_REV_CCL); | ||
460 | __raw_writel(ctx->pm[7], ctx->regs + PCI_REG_ID); | ||
461 | __raw_writel(ctx->pm[8], ctx->regs + PCI_REG_CLASSREV); | ||
462 | __raw_writel(ctx->pm[9], ctx->regs + PCI_REG_PARAM); | ||
463 | __raw_writel(ctx->pm[10], ctx->regs + PCI_REG_MBAR); | ||
464 | __raw_writel(ctx->pm[11], ctx->regs + PCI_REG_TIMEOUT); | ||
465 | wmb(); | ||
466 | __raw_writel(ctx->pm[1], ctx->regs + PCI_REG_CONFIG); | ||
467 | wmb(); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static const struct dev_pm_ops alchemy_pci_pmops = { | ||
473 | .suspend = alchemy_pci_suspend, | ||
474 | .resume = alchemy_pci_resume, | ||
475 | }; | ||
476 | |||
477 | #define ALCHEMY_PCICTL_PM (&alchemy_pci_pmops) | ||
478 | |||
479 | #else | ||
480 | #define ALCHEMY_PCICTL_PM NULL | ||
481 | #endif | ||
482 | |||
483 | static struct platform_driver alchemy_pcictl_driver = { | ||
484 | .probe = alchemy_pci_probe, | ||
485 | .driver = { | ||
486 | .name = "alchemy-pci", | ||
487 | .owner = THIS_MODULE, | ||
488 | .pm = ALCHEMY_PCICTL_PM, | ||
489 | }, | ||
490 | }; | ||
491 | |||
492 | static int __init alchemy_pci_init(void) | ||
493 | { | ||
494 | /* Au1500/Au1550 have PCI */ | ||
495 | switch (alchemy_get_cputype()) { | ||
496 | case ALCHEMY_CPU_AU1500: | ||
497 | case ALCHEMY_CPU_AU1550: | ||
498 | return platform_driver_register(&alchemy_pcictl_driver); | ||
499 | } | ||
500 | return 0; | ||
501 | } | ||
502 | arch_initcall(alchemy_pci_init); | ||
503 | |||
504 | |||
505 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
506 | { | ||
507 | struct alchemy_pci_context *ctx = dev->sysdata; | ||
508 | if (ctx && ctx->board_map_irq) | ||
509 | return ctx->board_map_irq(dev, slot, pin); | ||
510 | return -1; | ||
511 | } | ||
512 | |||
513 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
514 | { | ||
515 | return 0; | ||
516 | } | ||