aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/platforms/apus_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/platforms/apus_pci.c')
-rw-r--r--arch/ppc/platforms/apus_pci.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c
new file mode 100644
index 000000000000..33dad6db8243
--- /dev/null
+++ b/arch/ppc/platforms/apus_pci.c
@@ -0,0 +1,208 @@
1/*
2 * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
3 *
4 * APUS PCI routines.
5 *
6 * Currently, only B/CVisionPPC cards (Permedia2) are supported.
7 *
8 * Thanks to Geert Uytterhoeven for the idea:
9 * Read values from given config space(s) for the first devices, -1 otherwise
10 *
11 */
12
13#include <linux/config.h>
14#ifdef CONFIG_AMIGA
15
16#include <linux/kernel.h>
17#include <linux/pci.h>
18#include <linux/delay.h>
19#include <linux/string.h>
20#include <linux/init.h>
21
22#include <asm/io.h>
23#include <asm/pci-bridge.h>
24#include <asm/machdep.h>
25
26#include "apus_pci.h"
27
28
29/* These definitions are mostly adapted from pm2fb.c */
30
31#undef APUS_PCI_MASTER_DEBUG
32#ifdef APUS_PCI_MASTER_DEBUG
33#define DPRINTK(a,b...) printk(KERN_DEBUG "apus_pci: %s: " a, __FUNCTION__ , ## b)
34#else
35#define DPRINTK(a,b...)
36#endif
37
38/*
39 * The _DEFINITIVE_ memory mapping/unmapping functions.
40 * This is due to the fact that they're changing soooo often...
41 */
42#define DEFW() wmb()
43#define DEFR() rmb()
44#define DEFRW() mb()
45
46#define DEVNO(d) ((d)>>3)
47#define FNNO(d) ((d)&7)
48
49
50extern unsigned long powerup_PCI_present;
51
52static struct pci_controller *apus_hose;
53
54
55void *pci_io_base(unsigned int bus)
56{
57 return 0;
58}
59
60
61int
62apus_pcibios_read_config(struct pci_bus *bus, int devfn, int offset,
63 int len, u32 *val)
64{
65 int fnno = FNNO(devfn);
66 int devno = DEVNO(devfn);
67 volatile unsigned char *cfg_data;
68
69 if (bus->number > 0 || devno != 1) {
70 *val = ~0;
71 return PCIBIOS_DEVICE_NOT_FOUND;
72 }
73 /* base address + function offset + offset ^ endianness conversion */
74 /* XXX the fnno<<5 bit seems wacky -- paulus */
75 cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1));
76 switch (len) {
77 case 1:
78 *val = readb(cfg_data);
79 break;
80 case 2:
81 *val = readw(cfg_data);
82 break;
83 default:
84 *val = readl(cfg_data);
85 break;
86 }
87
88 DPRINTK("read b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n",
89 bus->number, devfn>>3, devfn&7, offset, len, *val);
90 return PCIBIOS_SUCCESSFUL;
91}
92
93int
94apus_pcibios_write_config(struct pci_bus *bus, int devfn, int offset,
95 int len, u32 *val)
96{
97 int fnno = FNNO(devfn);
98 int devno = DEVNO(devfn);
99 volatile unsigned char *cfg_data;
100
101 if (bus->number > 0 || devno != 1) {
102 return PCIBIOS_DEVICE_NOT_FOUND;
103 }
104 /* base address + function offset + offset ^ endianness conversion */
105 /* XXX the fnno<<5 bit seems wacky -- paulus */
106 cfg_data = apus_hose->cfg_data + (fnno<<5) + (offset ^ (len - 1));
107 switch (len) {
108 case 1:
109 writeb(val, cfg_data); DEFW();
110 break;
111 case 2:
112 writew(val, cfg_data); DEFW();
113 break;
114 default:
115 writel(val, cfg_data); DEFW();
116 break;
117 }
118
119 DPRINTK("write b: 0x%x, d: 0x%x, f: 0x%x, o: 0x%x, l: %d, v: 0x%x\n",
120 bus->number, devfn>>3, devfn&7, offset, len, val);
121 return PCIBIOS_SUCCESSFUL;
122}
123
124static struct pci_ops apus_pci_ops = {
125 apus_pcibios_read_config,
126 apus_pcibios_write_config
127};
128
129static struct resource pci_mem = { "B/CVisionPPC PCI mem", CVPPC_FB_APERTURE_ONE, CVPPC_PCI_CONFIG, IORESOURCE_MEM };
130
131void __init
132apus_pcibios_fixup(void)
133{
134/* struct pci_dev *dev = pci_find_slot(0, 1<<3);
135 unsigned int reg, val, offset;*/
136
137 /* FIXME: interrupt? */
138 /*dev->interrupt = xxx;*/
139
140 request_resource(&iomem_resource, &pci_mem);
141 printk("%s: PCI mem resource requested\n", __FUNCTION__);
142}
143
144static void __init apus_pcibios_fixup_bus(struct pci_bus *bus)
145{
146 bus->resource[1] = &pci_mem;
147}
148
149
150/*
151 * This is from pm2fb.c again
152 *
153 * Check if PCI (B/CVisionPPC) is available, initialize it and set up
154 * the pcibios_* pointers
155 */
156
157
158void __init
159apus_setup_pci_ptrs(void)
160{
161 if (!powerup_PCI_present) {
162 DPRINTK("no PCI bridge detected\n");
163 return;
164 }
165 DPRINTK("Phase5 B/CVisionPPC PCI bridge detected.\n");
166
167 apus_hose = pcibios_alloc_controller();
168 if (!apus_hose) {
169 printk("apus_pci: Can't allocate PCI controller structure\n");
170 return;
171 }
172
173 if (!(apus_hose->cfg_data = ioremap(CVPPC_PCI_CONFIG, 256))) {
174 printk("apus_pci: unable to map PCI config region\n");
175 return;
176 }
177
178 if (!(apus_hose->cfg_addr = ioremap(CSPPC_PCI_BRIDGE, 256))) {
179 printk("apus_pci: unable to map PCI bridge\n");
180 return;
181 }
182
183 writel(CSPPCF_BRIDGE_BIG_ENDIAN, apus_hose->cfg_addr + CSPPC_BRIDGE_ENDIAN);
184 DEFW();
185
186 writel(CVPPC_REGS_REGION, apus_hose->cfg_data+ PCI_BASE_ADDRESS_0);
187 DEFW();
188 writel(CVPPC_FB_APERTURE_ONE, apus_hose->cfg_data + PCI_BASE_ADDRESS_1);
189 DEFW();
190 writel(CVPPC_FB_APERTURE_TWO, apus_hose->cfg_data + PCI_BASE_ADDRESS_2);
191 DEFW();
192 writel(CVPPC_ROM_ADDRESS, apus_hose->cfg_data + PCI_ROM_ADDRESS);
193 DEFW();
194
195 writel(0xef000000 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
196 PCI_COMMAND_MASTER, apus_hose->cfg_data + PCI_COMMAND);
197 DEFW();
198
199 apus_hose->first_busno = 0;
200 apus_hose->last_busno = 0;
201 apus_hose->ops = &apus_pci_ops;
202 ppc_md.pcibios_fixup = apus_pcibios_fixup;
203 ppc_md.pcibios_fixup_bus = apus_pcibios_fixup_bus;
204
205 return;
206}
207
208#endif /* CONFIG_AMIGA */