diff options
Diffstat (limited to 'arch/powerpc/platforms/86xx')
-rw-r--r-- | arch/powerpc/platforms/86xx/Kconfig | 36 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/Makefile | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc8641_hpcn.h | 54 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx.h | 28 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | 326 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx_pcie.c | 173 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/mpc86xx_smp.c | 117 | ||||
-rw-r--r-- | arch/powerpc/platforms/86xx/pci.c | 325 |
8 files changed, 1069 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig new file mode 100644 index 000000000000..3a87863d2876 --- /dev/null +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -0,0 +1,36 @@ | |||
1 | menu "Platform Support" | ||
2 | depends on PPC_86xx | ||
3 | |||
4 | choice | ||
5 | prompt "Machine Type" | ||
6 | default MPC8641_HPCN | ||
7 | |||
8 | config MPC8641_HPCN | ||
9 | bool "Freescale MPC8641 HPCN" | ||
10 | help | ||
11 | This option enables support for the MPC8641 HPCN board. | ||
12 | |||
13 | endchoice | ||
14 | |||
15 | |||
16 | config MPC8641 | ||
17 | bool | ||
18 | select PPC_INDIRECT_PCI | ||
19 | select PPC_UDBG_16550 | ||
20 | default y if MPC8641_HPCN | ||
21 | |||
22 | config MPIC | ||
23 | bool | ||
24 | default y | ||
25 | |||
26 | config PPC_INDIRECT_PCI_BE | ||
27 | bool | ||
28 | depends on PPC_86xx | ||
29 | default y | ||
30 | |||
31 | config PPC_STD_MMU | ||
32 | bool | ||
33 | depends on PPC_86xx | ||
34 | default y | ||
35 | |||
36 | endmenu | ||
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile new file mode 100644 index 000000000000..7be796c5d5c9 --- /dev/null +++ b/arch/powerpc/platforms/86xx/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the PowerPC 86xx linux kernel. | ||
3 | # | ||
4 | |||
5 | |||
6 | ifeq ($(CONFIG_PPC_86xx),y) | ||
7 | obj-$(CONFIG_SMP) += mpc86xx_smp.o | ||
8 | endif | ||
9 | obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o | ||
10 | obj-$(CONFIG_PCI) += pci.o mpc86xx_pcie.o | ||
diff --git a/arch/powerpc/platforms/86xx/mpc8641_hpcn.h b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h new file mode 100644 index 000000000000..5042253758b7 --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc8641_hpcn.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * MPC8641 HPCN board definitions | ||
3 | * | ||
4 | * Copyright 2006 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * Author: Xianghua Xiao <x.xiao@freescale.com> | ||
12 | */ | ||
13 | |||
14 | #ifndef __MPC8641_HPCN_H__ | ||
15 | #define __MPC8641_HPCN_H__ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/init.h> | ||
19 | |||
20 | /* PCI interrupt controller */ | ||
21 | #define PIRQA 3 | ||
22 | #define PIRQB 4 | ||
23 | #define PIRQC 5 | ||
24 | #define PIRQD 6 | ||
25 | #define PIRQ7 7 | ||
26 | #define PIRQE 9 | ||
27 | #define PIRQF 10 | ||
28 | #define PIRQG 11 | ||
29 | #define PIRQH 12 | ||
30 | |||
31 | /* PCI-Express memory map */ | ||
32 | #define MPC86XX_PCIE_LOWER_IO 0x00000000 | ||
33 | #define MPC86XX_PCIE_UPPER_IO 0x00ffffff | ||
34 | |||
35 | #define MPC86XX_PCIE_LOWER_MEM 0x80000000 | ||
36 | #define MPC86XX_PCIE_UPPER_MEM 0x9fffffff | ||
37 | |||
38 | #define MPC86XX_PCIE_IO_BASE 0xe2000000 | ||
39 | #define MPC86XX_PCIE_MEM_OFFSET 0x00000000 | ||
40 | |||
41 | #define MPC86XX_PCIE_IO_SIZE 0x01000000 | ||
42 | |||
43 | #define PCIE1_CFG_ADDR_OFFSET (0x8000) | ||
44 | #define PCIE1_CFG_DATA_OFFSET (0x8004) | ||
45 | |||
46 | #define PCIE2_CFG_ADDR_OFFSET (0x9000) | ||
47 | #define PCIE2_CFG_DATA_OFFSET (0x9004) | ||
48 | |||
49 | #define MPC86xx_PCIE_OFFSET PCIE1_CFG_ADDR_OFFSET | ||
50 | #define MPC86xx_PCIE_SIZE (0x1000) | ||
51 | |||
52 | #define MPC86XX_RSTCR_OFFSET (0xe00b0) /* Reset Control Register */ | ||
53 | |||
54 | #endif /* __MPC8641_HPCN_H__ */ | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h new file mode 100644 index 000000000000..e3c9e4f417d3 --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc86xx.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright 2006 Freescale Semiconductor Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | */ | ||
9 | |||
10 | #ifndef __MPC86XX_H__ | ||
11 | #define __MPC86XX_H__ | ||
12 | |||
13 | /* | ||
14 | * Declaration for the various functions exported by the | ||
15 | * mpc86xx_* files. Mostly for use by mpc86xx_setup(). | ||
16 | */ | ||
17 | |||
18 | extern int __init add_bridge(struct device_node *dev); | ||
19 | |||
20 | extern void __init setup_indirect_pcie(struct pci_controller *hose, | ||
21 | u32 cfg_addr, u32 cfg_data); | ||
22 | extern void __init setup_indirect_pcie_nomap(struct pci_controller *hose, | ||
23 | void __iomem *cfg_addr, | ||
24 | void __iomem *cfg_data); | ||
25 | |||
26 | extern void __init mpc86xx_smp_init(void); | ||
27 | |||
28 | #endif /* __MPC86XX_H__ */ | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c new file mode 100644 index 000000000000..483c21df181e --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * MPC86xx HPCN board specific routines | ||
3 | * | ||
4 | * Recode: ZHANG WEI <wei.zhang@freescale.com> | ||
5 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> | ||
6 | * | ||
7 | * Copyright 2006 Freescale Semiconductor Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/kdev_t.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/root_dev.h> | ||
23 | |||
24 | #include <asm/system.h> | ||
25 | #include <asm/time.h> | ||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/pci-bridge.h> | ||
28 | #include <asm/mpc86xx.h> | ||
29 | #include <asm/prom.h> | ||
30 | #include <mm/mmu_decl.h> | ||
31 | #include <asm/udbg.h> | ||
32 | #include <asm/i8259.h> | ||
33 | |||
34 | #include <asm/mpic.h> | ||
35 | |||
36 | #include <sysdev/fsl_soc.h> | ||
37 | |||
38 | #include "mpc86xx.h" | ||
39 | |||
40 | #ifndef CONFIG_PCI | ||
41 | unsigned long isa_io_base = 0; | ||
42 | unsigned long isa_mem_base = 0; | ||
43 | unsigned long pci_dram_offset = 0; | ||
44 | #endif | ||
45 | |||
46 | |||
47 | /* | ||
48 | * Internal interrupts are all Level Sensitive, and Positive Polarity | ||
49 | */ | ||
50 | |||
51 | static u_char mpc86xx_hpcn_openpic_initsenses[] __initdata = { | ||
52 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 0: Reserved */ | ||
53 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 1: MCM */ | ||
54 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 2: DDR DRAM */ | ||
55 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 3: LBIU */ | ||
56 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 4: DMA 0 */ | ||
57 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 5: DMA 1 */ | ||
58 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 6: DMA 2 */ | ||
59 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 7: DMA 3 */ | ||
60 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 8: PCIE1 */ | ||
61 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 9: PCIE2 */ | ||
62 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 10: Reserved */ | ||
63 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 11: Reserved */ | ||
64 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 12: DUART2 */ | ||
65 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 13: TSEC 1 Transmit */ | ||
66 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 14: TSEC 1 Receive */ | ||
67 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 15: TSEC 3 transmit */ | ||
68 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 16: TSEC 3 receive */ | ||
69 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 17: TSEC 3 error */ | ||
70 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 18: TSEC 1 Receive/Transmit Error */ | ||
71 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 19: TSEC 2 Transmit */ | ||
72 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 20: TSEC 2 Receive */ | ||
73 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 21: TSEC 4 transmit */ | ||
74 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 22: TSEC 4 receive */ | ||
75 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 23: TSEC 4 error */ | ||
76 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 24: TSEC 2 Receive/Transmit Error */ | ||
77 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 25: Unused */ | ||
78 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 26: DUART1 */ | ||
79 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 27: I2C */ | ||
80 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 28: Performance Monitor */ | ||
81 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 29: Unused */ | ||
82 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 30: Unused */ | ||
83 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 31: Unused */ | ||
84 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 32: SRIO error/write-port unit */ | ||
85 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 33: SRIO outbound doorbell */ | ||
86 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 34: SRIO inbound doorbell */ | ||
87 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 35: Unused */ | ||
88 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 36: Unused */ | ||
89 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 37: SRIO outbound message unit 1 */ | ||
90 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 38: SRIO inbound message unit 1 */ | ||
91 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 39: SRIO outbound message unit 2 */ | ||
92 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 40: SRIO inbound message unit 2 */ | ||
93 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 41: Unused */ | ||
94 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 42: Unused */ | ||
95 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 43: Unused */ | ||
96 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 44: Unused */ | ||
97 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 45: Unused */ | ||
98 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 46: Unused */ | ||
99 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* Internal 47: Unused */ | ||
100 | 0x0, /* External 0: */ | ||
101 | 0x0, /* External 1: */ | ||
102 | 0x0, /* External 2: */ | ||
103 | 0x0, /* External 3: */ | ||
104 | 0x0, /* External 4: */ | ||
105 | 0x0, /* External 5: */ | ||
106 | 0x0, /* External 6: */ | ||
107 | 0x0, /* External 7: */ | ||
108 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 8: Pixis FPGA */ | ||
109 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* External 9: ULI 8259 INTR Cascade */ | ||
110 | (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* External 10: Quad ETH PHY */ | ||
111 | 0x0, /* External 11: */ | ||
112 | 0x0, | ||
113 | 0x0, | ||
114 | 0x0, | ||
115 | 0x0, | ||
116 | }; | ||
117 | |||
118 | |||
119 | void __init | ||
120 | mpc86xx_hpcn_init_irq(void) | ||
121 | { | ||
122 | struct mpic *mpic1; | ||
123 | phys_addr_t openpic_paddr; | ||
124 | |||
125 | /* Determine the Physical Address of the OpenPIC regs */ | ||
126 | openpic_paddr = get_immrbase() + MPC86xx_OPENPIC_OFFSET; | ||
127 | |||
128 | /* Alloc mpic structure and per isu has 16 INT entries. */ | ||
129 | mpic1 = mpic_alloc(openpic_paddr, | ||
130 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
131 | 16, MPC86xx_OPENPIC_IRQ_OFFSET, 0, 250, | ||
132 | mpc86xx_hpcn_openpic_initsenses, | ||
133 | sizeof(mpc86xx_hpcn_openpic_initsenses), | ||
134 | " MPIC "); | ||
135 | BUG_ON(mpic1 == NULL); | ||
136 | |||
137 | /* 48 Internal Interrupts */ | ||
138 | mpic_assign_isu(mpic1, 0, openpic_paddr + 0x10200); | ||
139 | mpic_assign_isu(mpic1, 1, openpic_paddr + 0x10400); | ||
140 | mpic_assign_isu(mpic1, 2, openpic_paddr + 0x10600); | ||
141 | |||
142 | /* 16 External interrupts */ | ||
143 | mpic_assign_isu(mpic1, 3, openpic_paddr + 0x10000); | ||
144 | |||
145 | mpic_init(mpic1); | ||
146 | |||
147 | #ifdef CONFIG_PCI | ||
148 | mpic_setup_cascade(MPC86xx_IRQ_EXT9, i8259_irq_cascade, NULL); | ||
149 | i8259_init(0, I8259_OFFSET); | ||
150 | #endif | ||
151 | } | ||
152 | |||
153 | |||
154 | |||
155 | #ifdef CONFIG_PCI | ||
156 | /* | ||
157 | * interrupt routing | ||
158 | */ | ||
159 | |||
160 | int | ||
161 | mpc86xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) | ||
162 | { | ||
163 | static char pci_irq_table[][4] = { | ||
164 | /* | ||
165 | * PCI IDSEL/INTPIN->INTLINE | ||
166 | * A B C D | ||
167 | */ | ||
168 | {PIRQA, PIRQB, PIRQC, PIRQD}, /* IDSEL 17 -- PCI Slot 1 */ | ||
169 | {PIRQB, PIRQC, PIRQD, PIRQA}, /* IDSEL 18 -- PCI Slot 2 */ | ||
170 | {0, 0, 0, 0}, /* IDSEL 19 */ | ||
171 | {0, 0, 0, 0}, /* IDSEL 20 */ | ||
172 | {0, 0, 0, 0}, /* IDSEL 21 */ | ||
173 | {0, 0, 0, 0}, /* IDSEL 22 */ | ||
174 | {0, 0, 0, 0}, /* IDSEL 23 */ | ||
175 | {0, 0, 0, 0}, /* IDSEL 24 */ | ||
176 | {0, 0, 0, 0}, /* IDSEL 25 */ | ||
177 | {PIRQD, PIRQA, PIRQB, PIRQC}, /* IDSEL 26 -- PCI Bridge*/ | ||
178 | {PIRQC, 0, 0, 0}, /* IDSEL 27 -- LAN */ | ||
179 | {PIRQE, PIRQF, PIRQH, PIRQ7}, /* IDSEL 28 -- USB 1.1 */ | ||
180 | {PIRQE, PIRQF, PIRQG, 0}, /* IDSEL 29 -- Audio & Modem */ | ||
181 | {PIRQH, 0, 0, 0}, /* IDSEL 30 -- LPC & PMU*/ | ||
182 | {PIRQD, 0, 0, 0}, /* IDSEL 31 -- ATA */ | ||
183 | }; | ||
184 | |||
185 | const long min_idsel = 17, max_idsel = 31, irqs_per_slot = 4; | ||
186 | return PCI_IRQ_TABLE_LOOKUP + I8259_OFFSET; | ||
187 | } | ||
188 | |||
189 | |||
190 | int | ||
191 | mpc86xx_exclude_device(u_char bus, u_char devfn) | ||
192 | { | ||
193 | #if !defined(CONFIG_PCI) | ||
194 | if (bus == 0 && PCI_SLOT(devfn) == 0) | ||
195 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
196 | #endif | ||
197 | |||
198 | return PCIBIOS_SUCCESSFUL; | ||
199 | } | ||
200 | #endif /* CONFIG_PCI */ | ||
201 | |||
202 | |||
203 | static void __init | ||
204 | mpc86xx_hpcn_setup_arch(void) | ||
205 | { | ||
206 | struct device_node *np; | ||
207 | |||
208 | if (ppc_md.progress) | ||
209 | ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0); | ||
210 | |||
211 | np = of_find_node_by_type(NULL, "cpu"); | ||
212 | if (np != 0) { | ||
213 | unsigned int *fp; | ||
214 | |||
215 | fp = (int *)get_property(np, "clock-frequency", NULL); | ||
216 | if (fp != 0) | ||
217 | loops_per_jiffy = *fp / HZ; | ||
218 | else | ||
219 | loops_per_jiffy = 50000000 / HZ; | ||
220 | of_node_put(np); | ||
221 | } | ||
222 | |||
223 | #ifdef CONFIG_PCI | ||
224 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | ||
225 | add_bridge(np); | ||
226 | |||
227 | ppc_md.pci_swizzle = common_swizzle; | ||
228 | ppc_md.pci_map_irq = mpc86xx_map_irq; | ||
229 | ppc_md.pci_exclude_device = mpc86xx_exclude_device; | ||
230 | #endif | ||
231 | |||
232 | printk("MPC86xx HPCN board from Freescale Semiconductor\n"); | ||
233 | |||
234 | #ifdef CONFIG_ROOT_NFS | ||
235 | ROOT_DEV = Root_NFS; | ||
236 | #else | ||
237 | ROOT_DEV = Root_HDA1; | ||
238 | #endif | ||
239 | |||
240 | #ifdef CONFIG_SMP | ||
241 | mpc86xx_smp_init(); | ||
242 | #endif | ||
243 | } | ||
244 | |||
245 | |||
246 | void | ||
247 | mpc86xx_hpcn_show_cpuinfo(struct seq_file *m) | ||
248 | { | ||
249 | struct device_node *root; | ||
250 | uint memsize = total_memory; | ||
251 | const char *model = ""; | ||
252 | uint svid = mfspr(SPRN_SVR); | ||
253 | |||
254 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); | ||
255 | |||
256 | root = of_find_node_by_path("/"); | ||
257 | if (root) | ||
258 | model = get_property(root, "model", NULL); | ||
259 | seq_printf(m, "Machine\t\t: %s\n", model); | ||
260 | of_node_put(root); | ||
261 | |||
262 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
263 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
264 | } | ||
265 | |||
266 | |||
267 | /* | ||
268 | * Called very early, device-tree isn't unflattened | ||
269 | */ | ||
270 | static int __init mpc86xx_hpcn_probe(void) | ||
271 | { | ||
272 | unsigned long root = of_get_flat_dt_root(); | ||
273 | |||
274 | if (of_flat_dt_is_compatible(root, "mpc86xx")) | ||
275 | return 1; /* Looks good */ | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | |||
281 | void | ||
282 | mpc86xx_restart(char *cmd) | ||
283 | { | ||
284 | void __iomem *rstcr; | ||
285 | |||
286 | rstcr = ioremap(get_immrbase() + MPC86XX_RSTCR_OFFSET, 0x100); | ||
287 | |||
288 | local_irq_disable(); | ||
289 | |||
290 | /* Assert reset request to Reset Control Register */ | ||
291 | out_be32(rstcr, 0x2); | ||
292 | |||
293 | /* not reached */ | ||
294 | } | ||
295 | |||
296 | |||
297 | long __init | ||
298 | mpc86xx_time_init(void) | ||
299 | { | ||
300 | unsigned int temp; | ||
301 | |||
302 | /* Set the time base to zero */ | ||
303 | mtspr(SPRN_TBWL, 0); | ||
304 | mtspr(SPRN_TBWU, 0); | ||
305 | |||
306 | temp = mfspr(SPRN_HID0); | ||
307 | temp |= HID0_TBEN; | ||
308 | mtspr(SPRN_HID0, temp); | ||
309 | asm volatile("isync"); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | |||
315 | define_machine(mpc86xx_hpcn) { | ||
316 | .name = "MPC86xx HPCN", | ||
317 | .probe = mpc86xx_hpcn_probe, | ||
318 | .setup_arch = mpc86xx_hpcn_setup_arch, | ||
319 | .init_IRQ = mpc86xx_hpcn_init_irq, | ||
320 | .show_cpuinfo = mpc86xx_hpcn_show_cpuinfo, | ||
321 | .get_irq = mpic_get_irq, | ||
322 | .restart = mpc86xx_restart, | ||
323 | .time_init = mpc86xx_time_init, | ||
324 | .calibrate_decr = generic_calibrate_decr, | ||
325 | .progress = udbg_progress, | ||
326 | }; | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c b/arch/powerpc/platforms/86xx/mpc86xx_pcie.c new file mode 100644 index 000000000000..a2f4f730213e --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc86xx_pcie.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Support for indirect PCI bridges. | ||
3 | * | ||
4 | * Copyright (C) 1998 Gabriel Paubert. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * "Temporary" MPC8548 Errata file - | ||
12 | * The standard indirect_pci code should work with future silicon versions. | ||
13 | */ | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/bootmem.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include <asm/prom.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | #include <asm/machdep.h> | ||
26 | |||
27 | #include "mpc86xx.h" | ||
28 | |||
29 | #define PCI_CFG_OUT out_be32 | ||
30 | |||
31 | /* ERRATA PCI-Ex 14 PCIE Controller timeout */ | ||
32 | #define PCIE_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff) | ||
33 | |||
34 | |||
35 | static int | ||
36 | indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, | ||
37 | int len, u32 *val) | ||
38 | { | ||
39 | struct pci_controller *hose = bus->sysdata; | ||
40 | volatile void __iomem *cfg_data; | ||
41 | u32 temp; | ||
42 | |||
43 | if (ppc_md.pci_exclude_device) | ||
44 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | ||
45 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
46 | |||
47 | /* Possible artifact of CDCpp50937 needs further investigation */ | ||
48 | if (devfn != 0x0 && bus->number == 0xff) | ||
49 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
50 | |||
51 | PCIE_FIX; | ||
52 | if (bus->number == 0xff) { | ||
53 | PCI_CFG_OUT(hose->cfg_addr, | ||
54 | (0x80000000 | ((offset & 0xf00) << 16) | | ||
55 | ((bus->number - hose->bus_offset) << 16) | ||
56 | | (devfn << 8) | ((offset & 0xfc) ))); | ||
57 | } else { | ||
58 | PCI_CFG_OUT(hose->cfg_addr, | ||
59 | (0x80000001 | ((offset & 0xf00) << 16) | | ||
60 | ((bus->number - hose->bus_offset) << 16) | ||
61 | | (devfn << 8) | ((offset & 0xfc) ))); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * Note: the caller has already checked that offset is | ||
66 | * suitably aligned and that len is 1, 2 or 4. | ||
67 | */ | ||
68 | /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ | ||
69 | cfg_data = hose->cfg_data; | ||
70 | PCIE_FIX; | ||
71 | temp = in_le32(cfg_data); | ||
72 | switch (len) { | ||
73 | case 1: | ||
74 | *val = (temp >> (((offset & 3))*8)) & 0xff; | ||
75 | break; | ||
76 | case 2: | ||
77 | *val = (temp >> (((offset & 3))*8)) & 0xffff; | ||
78 | break; | ||
79 | default: | ||
80 | *val = temp; | ||
81 | break; | ||
82 | } | ||
83 | return PCIBIOS_SUCCESSFUL; | ||
84 | } | ||
85 | |||
86 | static int | ||
87 | indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, | ||
88 | int len, u32 val) | ||
89 | { | ||
90 | struct pci_controller *hose = bus->sysdata; | ||
91 | volatile void __iomem *cfg_data; | ||
92 | u32 temp; | ||
93 | |||
94 | if (ppc_md.pci_exclude_device) | ||
95 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | ||
96 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
97 | |||
98 | /* Possible artifact of CDCpp50937 needs further investigation */ | ||
99 | if (devfn != 0x0 && bus->number == 0xff) | ||
100 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
101 | |||
102 | PCIE_FIX; | ||
103 | if (bus->number == 0xff) { | ||
104 | PCI_CFG_OUT(hose->cfg_addr, | ||
105 | (0x80000000 | ((offset & 0xf00) << 16) | | ||
106 | ((bus->number - hose->bus_offset) << 16) | ||
107 | | (devfn << 8) | ((offset & 0xfc) ))); | ||
108 | } else { | ||
109 | PCI_CFG_OUT(hose->cfg_addr, | ||
110 | (0x80000001 | ((offset & 0xf00) << 16) | | ||
111 | ((bus->number - hose->bus_offset) << 16) | ||
112 | | (devfn << 8) | ((offset & 0xfc) ))); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Note: the caller has already checked that offset is | ||
117 | * suitably aligned and that len is 1, 2 or 4. | ||
118 | */ | ||
119 | /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ | ||
120 | cfg_data = hose->cfg_data; | ||
121 | switch (len) { | ||
122 | case 1: | ||
123 | PCIE_FIX; | ||
124 | temp = in_le32(cfg_data); | ||
125 | temp = (temp & ~(0xff << ((offset & 3) * 8))) | | ||
126 | (val << ((offset & 3) * 8)); | ||
127 | PCIE_FIX; | ||
128 | out_le32(cfg_data, temp); | ||
129 | break; | ||
130 | case 2: | ||
131 | PCIE_FIX; | ||
132 | temp = in_le32(cfg_data); | ||
133 | temp = (temp & ~(0xffff << ((offset & 3) * 8))); | ||
134 | temp |= (val << ((offset & 3) * 8)) ; | ||
135 | PCIE_FIX; | ||
136 | out_le32(cfg_data, temp); | ||
137 | break; | ||
138 | default: | ||
139 | PCIE_FIX; | ||
140 | out_le32(cfg_data, val); | ||
141 | break; | ||
142 | } | ||
143 | PCIE_FIX; | ||
144 | return PCIBIOS_SUCCESSFUL; | ||
145 | } | ||
146 | |||
147 | static struct pci_ops indirect_pcie_ops = { | ||
148 | indirect_read_config_pcie, | ||
149 | indirect_write_config_pcie | ||
150 | }; | ||
151 | |||
152 | void __init | ||
153 | setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr, | ||
154 | void __iomem * cfg_data) | ||
155 | { | ||
156 | hose->cfg_addr = cfg_addr; | ||
157 | hose->cfg_data = cfg_data; | ||
158 | hose->ops = &indirect_pcie_ops; | ||
159 | } | ||
160 | |||
161 | void __init | ||
162 | setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) | ||
163 | { | ||
164 | unsigned long base = cfg_addr & PAGE_MASK; | ||
165 | void __iomem *mbase, *addr, *data; | ||
166 | |||
167 | mbase = ioremap(base, PAGE_SIZE); | ||
168 | addr = mbase + (cfg_addr & ~PAGE_MASK); | ||
169 | if ((cfg_data & PAGE_MASK) != base) | ||
170 | mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); | ||
171 | data = mbase + (cfg_data & ~PAGE_MASK); | ||
172 | setup_indirect_pcie_nomap(hose, addr, data); | ||
173 | } | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c new file mode 100644 index 000000000000..944ec4b71416 --- /dev/null +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Author: Xianghua Xiao <x.xiao@freescale.com> | ||
3 | * Zhang Wei <wei.zhang@freescale.com> | ||
4 | * | ||
5 | * Copyright 2006 Freescale Semiconductor Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/stddef.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | |||
19 | #include <asm/pgtable.h> | ||
20 | #include <asm/page.h> | ||
21 | #include <asm/pci-bridge.h> | ||
22 | #include <asm-powerpc/mpic.h> | ||
23 | #include <asm/mpc86xx.h> | ||
24 | #include <asm/cacheflush.h> | ||
25 | |||
26 | #include <sysdev/fsl_soc.h> | ||
27 | |||
28 | #include "mpc86xx.h" | ||
29 | |||
30 | extern void __secondary_start_mpc86xx(void); | ||
31 | extern unsigned long __secondary_hold_acknowledge; | ||
32 | |||
33 | |||
34 | static void __init | ||
35 | smp_86xx_release_core(int nr) | ||
36 | { | ||
37 | void *mcm_vaddr; | ||
38 | unsigned long vaddr, pcr; | ||
39 | |||
40 | if (nr < 0 || nr >= NR_CPUS) | ||
41 | return; | ||
42 | |||
43 | /* | ||
44 | * Startup Core #nr. | ||
45 | */ | ||
46 | mcm_vaddr = ioremap(get_immrbase() + MPC86xx_MCM_OFFSET, | ||
47 | MPC86xx_MCM_SIZE); | ||
48 | vaddr = (unsigned long)mcm_vaddr + MCM_PORT_CONFIG_OFFSET; | ||
49 | pcr = in_be32((volatile unsigned *)vaddr); | ||
50 | pcr |= 1 << (nr + 24); | ||
51 | out_be32((volatile unsigned *)vaddr, pcr); | ||
52 | } | ||
53 | |||
54 | |||
55 | static void __init | ||
56 | smp_86xx_kick_cpu(int nr) | ||
57 | { | ||
58 | unsigned int save_vector; | ||
59 | unsigned long target, flags; | ||
60 | int n = 0; | ||
61 | volatile unsigned int *vector | ||
62 | = (volatile unsigned int *)(KERNELBASE + 0x100); | ||
63 | |||
64 | if (nr < 0 || nr >= NR_CPUS) | ||
65 | return; | ||
66 | |||
67 | pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); | ||
68 | |||
69 | local_irq_save(flags); | ||
70 | local_irq_disable(); | ||
71 | |||
72 | /* Save reset vector */ | ||
73 | save_vector = *vector; | ||
74 | |||
75 | /* Setup fake reset vector to call __secondary_start_mpc86xx. */ | ||
76 | target = (unsigned long) __secondary_start_mpc86xx; | ||
77 | create_branch((unsigned long)vector, target, BRANCH_SET_LINK); | ||
78 | |||
79 | /* Kick that CPU */ | ||
80 | smp_86xx_release_core(nr); | ||
81 | |||
82 | /* Wait a bit for the CPU to take the exception. */ | ||
83 | while ((__secondary_hold_acknowledge != nr) && (n++, n < 1000)) | ||
84 | mdelay(1); | ||
85 | |||
86 | /* Restore the exception vector */ | ||
87 | *vector = save_vector; | ||
88 | flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); | ||
89 | |||
90 | local_irq_restore(flags); | ||
91 | |||
92 | pr_debug("wait CPU #%d for %d msecs.\n", nr, n); | ||
93 | } | ||
94 | |||
95 | |||
96 | static void __init | ||
97 | smp_86xx_setup_cpu(int cpu_nr) | ||
98 | { | ||
99 | mpic_setup_this_cpu(); | ||
100 | } | ||
101 | |||
102 | |||
103 | struct smp_ops_t smp_86xx_ops = { | ||
104 | .message_pass = smp_mpic_message_pass, | ||
105 | .probe = smp_mpic_probe, | ||
106 | .kick_cpu = smp_86xx_kick_cpu, | ||
107 | .setup_cpu = smp_86xx_setup_cpu, | ||
108 | .take_timebase = smp_generic_take_timebase, | ||
109 | .give_timebase = smp_generic_give_timebase, | ||
110 | }; | ||
111 | |||
112 | |||
113 | void __init | ||
114 | mpc86xx_smp_init(void) | ||
115 | { | ||
116 | smp_ops = &smp_86xx_ops; | ||
117 | } | ||
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c new file mode 100644 index 000000000000..5180df7c75bc --- /dev/null +++ b/arch/powerpc/platforms/86xx/pci.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * MPC86XX pci setup code | ||
3 | * | ||
4 | * Recode: ZHANG WEI <wei.zhang@freescale.com> | ||
5 | * Initial author: Xianghua Xiao <x.xiao@freescale.com> | ||
6 | * | ||
7 | * Copyright 2006 Freescale Semiconductor Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/serial.h> | ||
21 | |||
22 | #include <asm/system.h> | ||
23 | #include <asm/atomic.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/immap_86xx.h> | ||
27 | #include <asm/pci-bridge.h> | ||
28 | #include <sysdev/fsl_soc.h> | ||
29 | |||
30 | #include "mpc86xx.h" | ||
31 | |||
32 | #undef DEBUG | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | #define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) | ||
36 | #else | ||
37 | #define DBG(fmt, args...) | ||
38 | #endif | ||
39 | |||
40 | struct pcie_outbound_window_regs { | ||
41 | uint pexotar; /* 0x.0 - PCI Express outbound translation address register */ | ||
42 | uint pexotear; /* 0x.4 - PCI Express outbound translation extended address register */ | ||
43 | uint pexowbar; /* 0x.8 - PCI Express outbound window base address register */ | ||
44 | char res1[4]; | ||
45 | uint pexowar; /* 0x.10 - PCI Express outbound window attributes register */ | ||
46 | char res2[12]; | ||
47 | }; | ||
48 | |||
49 | struct pcie_inbound_window_regs { | ||
50 | uint pexitar; /* 0x.0 - PCI Express inbound translation address register */ | ||
51 | char res1[4]; | ||
52 | uint pexiwbar; /* 0x.8 - PCI Express inbound window base address register */ | ||
53 | uint pexiwbear; /* 0x.c - PCI Express inbound window base extended address register */ | ||
54 | uint pexiwar; /* 0x.10 - PCI Express inbound window attributes register */ | ||
55 | char res2[12]; | ||
56 | }; | ||
57 | |||
58 | static void __init setup_pcie_atmu(struct pci_controller *hose, struct resource *rsrc) | ||
59 | { | ||
60 | volatile struct ccsr_pex *pcie; | ||
61 | volatile struct pcie_outbound_window_regs *pcieow; | ||
62 | volatile struct pcie_inbound_window_regs *pcieiw; | ||
63 | int i = 0; | ||
64 | |||
65 | DBG("PCIE memory map start 0x%x, size 0x%x\n", rsrc->start, | ||
66 | rsrc->end - rsrc->start + 1); | ||
67 | pcie = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); | ||
68 | |||
69 | /* Disable all windows (except pexowar0 since its ignored) */ | ||
70 | pcie->pexowar1 = 0; | ||
71 | pcie->pexowar2 = 0; | ||
72 | pcie->pexowar3 = 0; | ||
73 | pcie->pexowar4 = 0; | ||
74 | pcie->pexiwar1 = 0; | ||
75 | pcie->pexiwar2 = 0; | ||
76 | pcie->pexiwar3 = 0; | ||
77 | |||
78 | pcieow = (struct pcie_outbound_window_regs *)&pcie->pexotar1; | ||
79 | pcieiw = (struct pcie_inbound_window_regs *)&pcie->pexitar1; | ||
80 | |||
81 | /* Setup outbound MEM window */ | ||
82 | for(i = 0; i < 3; i++) | ||
83 | if (hose->mem_resources[i].flags & IORESOURCE_MEM){ | ||
84 | DBG("PCIE MEM resource start 0x%08x, size 0x%08x.\n", | ||
85 | hose->mem_resources[i].start, | ||
86 | hose->mem_resources[i].end | ||
87 | - hose->mem_resources[i].start + 1); | ||
88 | pcieow->pexotar = (hose->mem_resources[i].start) >> 12 | ||
89 | & 0x000fffff; | ||
90 | pcieow->pexotear = 0; | ||
91 | pcieow->pexowbar = (hose->mem_resources[i].start) >> 12 | ||
92 | & 0x000fffff; | ||
93 | /* Enable, Mem R/W */ | ||
94 | pcieow->pexowar = 0x80044000 | | ||
95 | (__ilog2(hose->mem_resources[i].end | ||
96 | - hose->mem_resources[i].start + 1) | ||
97 | - 1); | ||
98 | pcieow++; | ||
99 | } | ||
100 | |||
101 | /* Setup outbound IO window */ | ||
102 | if (hose->io_resource.flags & IORESOURCE_IO){ | ||
103 | DBG("PCIE IO resource start 0x%08x, size 0x%08x, phy base 0x%08x.\n", | ||
104 | hose->io_resource.start, | ||
105 | hose->io_resource.end - hose->io_resource.start + 1, | ||
106 | hose->io_base_phys); | ||
107 | pcieow->pexotar = (hose->io_resource.start) >> 12 & 0x000fffff; | ||
108 | pcieow->pexotear = 0; | ||
109 | pcieow->pexowbar = (hose->io_base_phys) >> 12 & 0x000fffff; | ||
110 | /* Enable, IO R/W */ | ||
111 | pcieow->pexowar = 0x80088000 | (__ilog2(hose->io_resource.end | ||
112 | - hose->io_resource.start + 1) - 1); | ||
113 | } | ||
114 | |||
115 | /* Setup 2G inbound Memory Window @ 0 */ | ||
116 | pcieiw->pexitar = 0x00000000; | ||
117 | pcieiw->pexiwbar = 0x00000000; | ||
118 | /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */ | ||
119 | pcieiw->pexiwar = 0xa0f5501e; | ||
120 | } | ||
121 | |||
122 | static void __init | ||
123 | mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size) | ||
124 | { | ||
125 | volatile struct ccsr_pex *pcie; | ||
126 | u16 cmd; | ||
127 | unsigned int temps; | ||
128 | |||
129 | DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n", | ||
130 | pcie_offset, pcie_size); | ||
131 | |||
132 | pcie = ioremap(pcie_offset, pcie_size); | ||
133 | |||
134 | early_read_config_word(hose, 0, 0, PCI_COMMAND, &cmd); | ||
135 | cmd |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | ||
136 | | PCI_COMMAND_IO; | ||
137 | early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd); | ||
138 | |||
139 | early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); | ||
140 | |||
141 | /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */ | ||
142 | early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps); | ||
143 | temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); | ||
144 | early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps); | ||
145 | } | ||
146 | |||
147 | int __init add_bridge(struct device_node *dev) | ||
148 | { | ||
149 | int len; | ||
150 | struct pci_controller *hose; | ||
151 | struct resource rsrc; | ||
152 | int *bus_range; | ||
153 | int has_address = 0; | ||
154 | int primary = 0; | ||
155 | |||
156 | DBG("Adding PCIE host bridge %s\n", dev->full_name); | ||
157 | |||
158 | /* Fetch host bridge registers address */ | ||
159 | has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); | ||
160 | |||
161 | /* Get bus range if any */ | ||
162 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
163 | if (bus_range == NULL || len < 2 * sizeof(int)) | ||
164 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | ||
165 | " bus 0\n", dev->full_name); | ||
166 | |||
167 | hose = pcibios_alloc_controller(); | ||
168 | if (!hose) | ||
169 | return -ENOMEM; | ||
170 | hose->arch_data = dev; | ||
171 | hose->set_cfg_type = 1; | ||
172 | |||
173 | /* last_busno = 0xfe cause by MPC8641 PCIE bug */ | ||
174 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
175 | hose->last_busno = bus_range ? bus_range[1] : 0xfe; | ||
176 | |||
177 | setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4); | ||
178 | |||
179 | /* Setup the PCIE host controller. */ | ||
180 | mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1); | ||
181 | |||
182 | if ((rsrc.start & 0xfffff) == 0x8000) | ||
183 | primary = 1; | ||
184 | |||
185 | printk(KERN_INFO "Found MPC86xx PCIE host bridge at 0x%08lx. " | ||
186 | "Firmware bus number: %d->%d\n", | ||
187 | rsrc.start, hose->first_busno, hose->last_busno); | ||
188 | |||
189 | DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", | ||
190 | hose, hose->cfg_addr, hose->cfg_data); | ||
191 | |||
192 | /* Interpret the "ranges" property */ | ||
193 | /* This also maps the I/O region and sets isa_io/mem_base */ | ||
194 | pci_process_bridge_OF_ranges(hose, dev, primary); | ||
195 | |||
196 | /* Setup PEX window registers */ | ||
197 | setup_pcie_atmu(hose, &rsrc); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void __devinit quirk_ali1575(struct pci_dev *dev) | ||
203 | { | ||
204 | unsigned short temp; | ||
205 | |||
206 | /* | ||
207 | * ALI1575 interrupts route table setup: | ||
208 | * | ||
209 | * IRQ pin IRQ# | ||
210 | * PIRQA ---- 3 | ||
211 | * PIRQB ---- 4 | ||
212 | * PIRQC ---- 5 | ||
213 | * PIRQD ---- 6 | ||
214 | * PIRQE ---- 9 | ||
215 | * PIRQF ---- 10 | ||
216 | * PIRQG ---- 11 | ||
217 | * PIRQH ---- 12 | ||
218 | * | ||
219 | * interrupts for PCI slot0 -- PIRQA / PIRQB / PIRQC / PIRQD | ||
220 | * PCI slot1 -- PIRQB / PIRQC / PIRQD / PIRQA | ||
221 | */ | ||
222 | pci_write_config_dword(dev, 0x48, 0xb9317542); | ||
223 | |||
224 | /* USB 1.1 OHCI controller 1, interrupt: PIRQE */ | ||
225 | pci_write_config_byte(dev, 0x86, 0x0c); | ||
226 | |||
227 | /* USB 1.1 OHCI controller 2, interrupt: PIRQF */ | ||
228 | pci_write_config_byte(dev, 0x87, 0x0d); | ||
229 | |||
230 | /* USB 1.1 OHCI controller 3, interrupt: PIRQH */ | ||
231 | pci_write_config_byte(dev, 0x88, 0x0f); | ||
232 | |||
233 | /* USB 2.0 controller, interrupt: PIRQ7 */ | ||
234 | pci_write_config_byte(dev, 0x74, 0x06); | ||
235 | |||
236 | /* Audio controller, interrupt: PIRQE */ | ||
237 | pci_write_config_byte(dev, 0x8a, 0x0c); | ||
238 | |||
239 | /* Modem controller, interrupt: PIRQF */ | ||
240 | pci_write_config_byte(dev, 0x8b, 0x0d); | ||
241 | |||
242 | /* HD audio controller, interrupt: PIRQG */ | ||
243 | pci_write_config_byte(dev, 0x8c, 0x0e); | ||
244 | |||
245 | /* Serial ATA interrupt: PIRQD */ | ||
246 | pci_write_config_byte(dev, 0x8d, 0x0b); | ||
247 | |||
248 | /* SMB interrupt: PIRQH */ | ||
249 | pci_write_config_byte(dev, 0x8e, 0x0f); | ||
250 | |||
251 | /* PMU ACPI SCI interrupt: PIRQH */ | ||
252 | pci_write_config_byte(dev, 0x8f, 0x0f); | ||
253 | |||
254 | /* Primary PATA IDE IRQ: 14 | ||
255 | * Secondary PATA IDE IRQ: 15 | ||
256 | */ | ||
257 | pci_write_config_byte(dev, 0x44, 0x3d); | ||
258 | pci_write_config_byte(dev, 0x75, 0x0f); | ||
259 | |||
260 | /* Set IRQ14 and IRQ15 to legacy IRQs */ | ||
261 | pci_read_config_word(dev, 0x46, &temp); | ||
262 | temp |= 0xc000; | ||
263 | pci_write_config_word(dev, 0x46, temp); | ||
264 | |||
265 | /* Set i8259 interrupt trigger | ||
266 | * IRQ 3: Level | ||
267 | * IRQ 4: Level | ||
268 | * IRQ 5: Level | ||
269 | * IRQ 6: Level | ||
270 | * IRQ 7: Level | ||
271 | * IRQ 9: Level | ||
272 | * IRQ 10: Level | ||
273 | * IRQ 11: Level | ||
274 | * IRQ 12: Level | ||
275 | * IRQ 14: Edge | ||
276 | * IRQ 15: Edge | ||
277 | */ | ||
278 | outb(0xfa, 0x4d0); | ||
279 | outb(0x1e, 0x4d1); | ||
280 | } | ||
281 | |||
282 | static void __devinit quirk_uli5288(struct pci_dev *dev) | ||
283 | { | ||
284 | unsigned char c; | ||
285 | |||
286 | pci_read_config_byte(dev,0x83,&c); | ||
287 | c |= 0x80; | ||
288 | pci_write_config_byte(dev, 0x83, c); | ||
289 | |||
290 | pci_write_config_byte(dev, 0x09, 0x01); | ||
291 | pci_write_config_byte(dev, 0x0a, 0x06); | ||
292 | |||
293 | pci_read_config_byte(dev,0x83,&c); | ||
294 | c &= 0x7f; | ||
295 | pci_write_config_byte(dev, 0x83, c); | ||
296 | |||
297 | pci_read_config_byte(dev,0x84,&c); | ||
298 | c |= 0x01; | ||
299 | pci_write_config_byte(dev, 0x84, c); | ||
300 | } | ||
301 | |||
302 | static void __devinit quirk_uli5229(struct pci_dev *dev) | ||
303 | { | ||
304 | unsigned short temp; | ||
305 | pci_write_config_word(dev, 0x04, 0x0405); | ||
306 | pci_read_config_word(dev, 0x4a, &temp); | ||
307 | temp |= 0x1000; | ||
308 | pci_write_config_word(dev, 0x4a, temp); | ||
309 | } | ||
310 | |||
311 | static void __devinit early_uli5249(struct pci_dev *dev) | ||
312 | { | ||
313 | unsigned char temp; | ||
314 | pci_write_config_word(dev, 0x04, 0x0007); | ||
315 | pci_read_config_byte(dev, 0x7c, &temp); | ||
316 | pci_write_config_byte(dev, 0x7c, 0x80); | ||
317 | pci_write_config_byte(dev, 0x09, 0x01); | ||
318 | pci_write_config_byte(dev, 0x7c, temp); | ||
319 | dev->class |= 0x1; | ||
320 | } | ||
321 | |||
322 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x1575, quirk_ali1575); | ||
323 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5288, quirk_uli5288); | ||
324 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229); | ||
325 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AL, 0x5249, early_uli5249); | ||