OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * ADM5120 PCI Host Controller driver |
||
3 | * |
||
4 | * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> |
||
5 | * |
||
6 | * This code was based on the ADM5120 specific port of the Linux 2.6.10 kernel |
||
7 | * done by Jeroen Vreeken |
||
8 | * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) |
||
9 | * |
||
10 | * Jeroen's code was based on the Linux 2.4.xx source codes found in various |
||
11 | * tarballs released by Edimax for it's ADM5120 based devices |
||
12 | * Copyright (C) ADMtek Incorporated |
||
13 | * |
||
14 | * This program is free software; you can redistribute it and/or modify it |
||
15 | * under the terms of the GNU General Public License version 2 as published |
||
16 | * by the Free Software Foundation. |
||
17 | * |
||
18 | */ |
||
19 | #include <linux/types.h> |
||
20 | #include <linux/kernel.h> |
||
21 | #include <linux/init.h> |
||
22 | #include <linux/spinlock.h> |
||
23 | #include <linux/io.h> |
||
24 | #include <linux/delay.h> |
||
25 | |||
26 | #include <linux/pci.h> |
||
27 | #include <linux/pci_ids.h> |
||
28 | #include <linux/pci_regs.h> |
||
29 | |||
30 | #include <asm/bootinfo.h> |
||
31 | |||
32 | #include <asm/mach-adm5120/adm5120_defs.h> |
||
33 | #include <asm/mach-adm5120/adm5120_info.h> |
||
34 | #include <asm/mach-adm5120/adm5120_defs.h> |
||
35 | #include <asm/mach-adm5120/adm5120_platform.h> |
||
36 | |||
37 | #undef DEBUG |
||
38 | |||
39 | #ifdef DEBUG |
||
40 | #define DBG(f, a...) printk(KERN_DEBUG f, ## a) |
||
41 | #else |
||
42 | #define DBG(f, a...) do {} while (0) |
||
43 | #endif |
||
44 | |||
45 | #define PCI_ENABLE 0x80000000 |
||
46 | |||
47 | /* -------------------------------------------------------------------------*/ |
||
48 | |||
49 | static unsigned int adm5120_pci_nr_irqs __initdata; |
||
50 | static struct adm5120_pci_irq *adm5120_pci_irq_map __initdata; |
||
51 | |||
52 | static DEFINE_SPINLOCK(pci_lock); |
||
53 | |||
54 | /* -------------------------------------------------------------------------*/ |
||
55 | |||
56 | static inline void write_cfgaddr(u32 addr) |
||
57 | { |
||
58 | __raw_writel((addr | PCI_ENABLE), |
||
59 | (void __iomem *)(KSEG1ADDR(ADM5120_PCICFG_ADDR))); |
||
60 | } |
||
61 | |||
62 | static inline void write_cfgdata(u32 data) |
||
63 | { |
||
64 | __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM5120_PCICFG_DATA)); |
||
65 | } |
||
66 | |||
67 | static inline u32 read_cfgdata(void) |
||
68 | { |
||
69 | return __raw_readl((void __iomem *)KSEG1ADDR(ADM5120_PCICFG_DATA)); |
||
70 | } |
||
71 | |||
72 | static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where) |
||
73 | { |
||
74 | return ((bus->number & 0xFF) << 16) | ((devfn & 0xFF) << 8) | \ |
||
75 | (where & 0xFC); |
||
76 | } |
||
77 | |||
78 | /* -------------------------------------------------------------------------*/ |
||
79 | |||
80 | static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, |
||
81 | int size, u32 *val) |
||
82 | { |
||
83 | unsigned long flags; |
||
84 | u32 data; |
||
85 | |||
86 | spin_lock_irqsave(&pci_lock, flags); |
||
87 | |||
88 | write_cfgaddr(mkaddr(bus, devfn, where)); |
||
89 | data = read_cfgdata(); |
||
90 | |||
91 | DBG("PCI: cfg_read %02u.%02u.%01u/%02X:%01d, cfg:0x%08X", |
||
92 | bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), |
||
93 | where, size, data); |
||
94 | |||
95 | switch (size) { |
||
96 | case 1: |
||
97 | if (where & 1) |
||
98 | data >>= 8; |
||
99 | if (where & 2) |
||
100 | data >>= 16; |
||
101 | data &= 0xFF; |
||
102 | break; |
||
103 | case 2: |
||
104 | if (where & 2) |
||
105 | data >>= 16; |
||
106 | data &= 0xFFFF; |
||
107 | break; |
||
108 | } |
||
109 | |||
110 | *val = data; |
||
111 | DBG(", 0x%08X returned\n", data); |
||
112 | |||
113 | spin_unlock_irqrestore(&pci_lock, flags); |
||
114 | |||
115 | return PCIBIOS_SUCCESSFUL; |
||
116 | } |
||
117 | |||
118 | static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, |
||
119 | int size, u32 val) |
||
120 | { |
||
121 | unsigned long flags; |
||
122 | u32 data; |
||
123 | int s; |
||
124 | |||
125 | spin_lock_irqsave(&pci_lock, flags); |
||
126 | |||
127 | write_cfgaddr(mkaddr(bus, devfn, where)); |
||
128 | data = read_cfgdata(); |
||
129 | |||
130 | DBG("PCI: cfg_write %02u.%02u.%01u/%02X:%01d, cfg:0x%08X", |
||
131 | bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), |
||
132 | where, size, data); |
||
133 | |||
134 | switch (size) { |
||
135 | case 1: |
||
136 | s = ((where & 3) << 3); |
||
137 | data &= ~(0xFF << s); |
||
138 | data |= ((val & 0xFF) << s); |
||
139 | break; |
||
140 | case 2: |
||
141 | s = ((where & 2) << 4); |
||
142 | data &= ~(0xFFFF << s); |
||
143 | data |= ((val & 0xFFFF) << s); |
||
144 | break; |
||
145 | case 4: |
||
146 | data = val; |
||
147 | break; |
||
148 | } |
||
149 | |||
150 | write_cfgdata(data); |
||
151 | DBG(", 0x%08X written\n", data); |
||
152 | |||
153 | spin_unlock_irqrestore(&pci_lock, flags); |
||
154 | |||
155 | return PCIBIOS_SUCCESSFUL; |
||
156 | } |
||
157 | |||
158 | struct pci_ops adm5120_pci_ops = { |
||
159 | .read = pci_config_read, |
||
160 | .write = pci_config_write, |
||
161 | }; |
||
162 | |||
163 | /* -------------------------------------------------------------------------*/ |
||
164 | |||
165 | static void adm5120_pci_fixup(struct pci_dev *dev) |
||
166 | { |
||
167 | if (dev->devfn != 0) |
||
168 | return; |
||
169 | |||
170 | /* setup COMMAND register */ |
||
171 | pci_write_config_word(dev, PCI_COMMAND, |
||
172 | (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)); |
||
173 | |||
174 | /* setup CACHE_LINE_SIZE register */ |
||
175 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); |
||
176 | |||
177 | /* setup BARS */ |
||
178 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); |
||
179 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); |
||
180 | } |
||
181 | |||
182 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADMTEK, PCI_DEVICE_ID_ADMTEK_ADM5120, |
||
183 | adm5120_pci_fixup); |
||
184 | |||
185 | /* -------------------------------------------------------------------------*/ |
||
186 | |||
187 | void __init adm5120_pci_set_irq_map(unsigned int nr_irqs, |
||
188 | struct adm5120_pci_irq *map) |
||
189 | { |
||
190 | adm5120_pci_nr_irqs = nr_irqs; |
||
191 | adm5120_pci_irq_map = map; |
||
192 | } |
||
193 | |||
194 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
||
195 | { |
||
196 | int irq = -1; |
||
197 | int i; |
||
198 | |||
199 | if ((!adm5120_pci_nr_irqs) || (!adm5120_pci_irq_map)) { |
||
200 | printk(KERN_ALERT "PCI: pci_irq_map is not initialized\n"); |
||
201 | goto out; |
||
202 | } |
||
203 | |||
204 | if (slot < 1 || slot > 4) { |
||
205 | printk(KERN_ALERT "PCI: slot number %u is not supported\n", |
||
206 | slot); |
||
207 | goto out; |
||
208 | } |
||
209 | |||
210 | for (i = 0; i < adm5120_pci_nr_irqs; i++) { |
||
211 | if ((adm5120_pci_irq_map[i].slot == slot) |
||
212 | && (adm5120_pci_irq_map[i].func == PCI_FUNC(dev->devfn)) |
||
213 | && (adm5120_pci_irq_map[i].pin == pin)) { |
||
214 | irq = adm5120_pci_irq_map[i].irq; |
||
215 | break; |
||
216 | } |
||
217 | } |
||
218 | |||
219 | if (irq < 0) { |
||
220 | printk(KERN_ALERT "PCI: no irq found for %s pin:%u\n", |
||
221 | pci_name((struct pci_dev *)dev), pin); |
||
222 | } else { |
||
223 | printk(KERN_INFO "PCI: mapping irq for %s pin:%u, irq:%d\n", |
||
224 | pci_name((struct pci_dev *)dev), pin, irq); |
||
225 | } |
||
226 | |||
227 | out: |
||
228 | return irq; |
||
229 | } |
||
230 | |||
231 | int pcibios_plat_dev_init(struct pci_dev *dev) |
||
232 | { |
||
233 | return 0; |
||
234 | } |
||
235 | |||
236 | /* -------------------------------------------------------------------------*/ |
||
237 | |||
238 | static struct resource pci_io_resource = { |
||
239 | .name = "ADM5120 PCI I/O", |
||
240 | .start = ADM5120_PCIIO_BASE, |
||
241 | .end = ADM5120_PCICFG_ADDR-1, |
||
242 | .flags = IORESOURCE_IO |
||
243 | }; |
||
244 | |||
245 | static struct resource pci_mem_resource = { |
||
246 | .name = "ADM5120 PCI MEM", |
||
247 | .start = ADM5120_PCIMEM_BASE, |
||
248 | .end = ADM5120_PCIIO_BASE-1, |
||
249 | .flags = IORESOURCE_MEM |
||
250 | }; |
||
251 | |||
252 | static struct pci_controller adm5120_controller = { |
||
253 | .pci_ops = &adm5120_pci_ops, |
||
254 | .io_resource = &pci_io_resource, |
||
255 | .mem_resource = &pci_mem_resource, |
||
256 | }; |
||
257 | |||
258 | static int __init adm5120_pci_setup(void) |
||
259 | { |
||
260 | if (adm5120_package_pqfp()) { |
||
261 | printk(KERN_INFO "PCI: not available on ADM5120P\n"); |
||
262 | return -1; |
||
263 | } |
||
264 | |||
265 | /* Avoid ISA compat ranges. */ |
||
266 | PCIBIOS_MIN_IO = 0x00000000; |
||
267 | PCIBIOS_MIN_MEM = 0x00000000; |
||
268 | |||
269 | /* Set I/O resource limits. */ |
||
270 | ioport_resource.end = 0x1fffffff; |
||
271 | iomem_resource.end = 0xffffffff; |
||
272 | |||
273 | register_pci_controller(&adm5120_controller); |
||
274 | return 0; |
||
275 | } |
||
276 | |||
277 | arch_initcall(adm5120_pci_setup); |