aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/pci-ath724x.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/pci-ath724x.c')
-rw-r--r--arch/mips/pci/pci-ath724x.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/arch/mips/pci/pci-ath724x.c b/arch/mips/pci/pci-ath724x.c
new file mode 100644
index 00000000000..a4dd24a4130
--- /dev/null
+++ b/arch/mips/pci/pci-ath724x.c
@@ -0,0 +1,174 @@
1/*
2 * Atheros 724x PCI support
3 *
4 * Copyright (C) 2011 René Bolldorf <xsecute@googlemail.com>
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 version 2 as published
8 * by the Free Software Foundation.
9 */
10
11#include <linux/pci.h>
12#include <asm/mach-ath79/pci-ath724x.h>
13
14#define reg_read(_phys) (*(unsigned int *) KSEG1ADDR(_phys))
15#define reg_write(_phys, _val) ((*(unsigned int *) KSEG1ADDR(_phys)) = (_val))
16
17#define ATH724X_PCI_DEV_BASE 0x14000000
18#define ATH724X_PCI_MEM_BASE 0x10000000
19#define ATH724X_PCI_MEM_SIZE 0x08000000
20
21static DEFINE_SPINLOCK(ath724x_pci_lock);
22static struct ath724x_pci_data *pci_data;
23static int pci_data_size;
24
25static int ath724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
26 int size, uint32_t *value)
27{
28 unsigned long flags, addr, tval, mask;
29
30 if (devfn)
31 return PCIBIOS_DEVICE_NOT_FOUND;
32
33 if (where & (size - 1))
34 return PCIBIOS_BAD_REGISTER_NUMBER;
35
36 spin_lock_irqsave(&ath724x_pci_lock, flags);
37
38 switch (size) {
39 case 1:
40 addr = where & ~3;
41 mask = 0xff000000 >> ((where % 4) * 8);
42 tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
43 tval = tval & ~mask;
44 *value = (tval >> ((4 - (where % 4))*8));
45 break;
46 case 2:
47 addr = where & ~3;
48 mask = 0xffff0000 >> ((where % 4)*8);
49 tval = reg_read(ATH724X_PCI_DEV_BASE + addr);
50 tval = tval & ~mask;
51 *value = (tval >> ((4 - (where % 4))*8));
52 break;
53 case 4:
54 *value = reg_read(ATH724X_PCI_DEV_BASE + where);
55 break;
56 default:
57 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
58
59 return PCIBIOS_BAD_REGISTER_NUMBER;
60 }
61
62 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
63
64 return PCIBIOS_SUCCESSFUL;
65}
66
67static int ath724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
68 int size, uint32_t value)
69{
70 unsigned long flags, tval, addr, mask;
71
72 if (devfn)
73 return PCIBIOS_DEVICE_NOT_FOUND;
74
75 if (where & (size - 1))
76 return PCIBIOS_BAD_REGISTER_NUMBER;
77
78 spin_lock_irqsave(&ath724x_pci_lock, flags);
79
80 switch (size) {
81 case 1:
82 addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
83 mask = 0xff000000 >> ((where % 4)*8);
84 tval = reg_read(addr);
85 tval = tval & ~mask;
86 tval |= (value << ((4 - (where % 4))*8)) & mask;
87 reg_write(addr, tval);
88 break;
89 case 2:
90 addr = (ATH724X_PCI_DEV_BASE + where) & ~3;
91 mask = 0xffff0000 >> ((where % 4)*8);
92 tval = reg_read(addr);
93 tval = tval & ~mask;
94 tval |= (value << ((4 - (where % 4))*8)) & mask;
95 reg_write(addr, tval);
96 break;
97 case 4:
98 reg_write((ATH724X_PCI_DEV_BASE + where), value);
99 break;
100 default:
101 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
102
103 return PCIBIOS_BAD_REGISTER_NUMBER;
104 }
105
106 spin_unlock_irqrestore(&ath724x_pci_lock, flags);
107
108 return PCIBIOS_SUCCESSFUL;
109}
110
111static struct pci_ops ath724x_pci_ops = {
112 .read = ath724x_pci_read,
113 .write = ath724x_pci_write,
114};
115
116static struct resource ath724x_io_resource = {
117 .name = "PCI IO space",
118 .start = 0,
119 .end = 0,
120 .flags = IORESOURCE_IO,
121};
122
123static struct resource ath724x_mem_resource = {
124 .name = "PCI memory space",
125 .start = ATH724X_PCI_MEM_BASE,
126 .end = ATH724X_PCI_MEM_BASE + ATH724X_PCI_MEM_SIZE - 1,
127 .flags = IORESOURCE_MEM,
128};
129
130static struct pci_controller ath724x_pci_controller = {
131 .pci_ops = &ath724x_pci_ops,
132 .io_resource = &ath724x_io_resource,
133 .mem_resource = &ath724x_mem_resource,
134};
135
136void ath724x_pci_add_data(struct ath724x_pci_data *data, int size)
137{
138 pci_data = data;
139 pci_data_size = size;
140}
141
142int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
143{
144 unsigned int devfn = dev->devfn;
145 int irq = -1;
146
147 if (devfn > pci_data_size - 1)
148 return irq;
149
150 irq = pci_data[devfn].irq;
151
152 return irq;
153}
154
155int pcibios_plat_dev_init(struct pci_dev *dev)
156{
157 unsigned int devfn = dev->devfn;
158
159 if (devfn > pci_data_size - 1)
160 return PCIBIOS_DEVICE_NOT_FOUND;
161
162 dev->dev.platform_data = pci_data[devfn].pdata;
163
164 return PCIBIOS_SUCCESSFUL;
165}
166
167static int __init ath724x_pcibios_init(void)
168{
169 register_pci_controller(&ath724x_pci_controller);
170
171 return PCIBIOS_SUCCESSFUL;
172}
173
174arch_initcall(ath724x_pcibios_init);