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
21 static DEFINE_SPINLOCK(ath724x_pci_lock);
22 static struct ath724x_pci_data *pci_data;
23 static int pci_data_size;
24
ath724x_pci_read(struct pci_bus * bus,unsigned int devfn,int where,int size,uint32_t * value)25 static 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
ath724x_pci_write(struct pci_bus * bus,unsigned int devfn,int where,int size,uint32_t value)67 static 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
111 static struct pci_ops ath724x_pci_ops = {
112 .read = ath724x_pci_read,
113 .write = ath724x_pci_write,
114 };
115
116 static struct resource ath724x_io_resource = {
117 .name = "PCI IO space",
118 .start = 0,
119 .end = 0,
120 .flags = IORESOURCE_IO,
121 };
122
123 static 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
130 static 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
ath724x_pci_add_data(struct ath724x_pci_data * data,int size)136 void ath724x_pci_add_data(struct ath724x_pci_data *data, int size)
137 {
138 pci_data = data;
139 pci_data_size = size;
140 }
141
pcibios_map_irq(const struct pci_dev * dev,uint8_t slot,uint8_t pin)142 int __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
pcibios_plat_dev_init(struct pci_dev * dev)155 int 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
ath724x_pcibios_init(void)167 static int __init ath724x_pcibios_init(void)
168 {
169 register_pci_controller(&ath724x_pci_controller);
170
171 return PCIBIOS_SUCCESSFUL;
172 }
173
174 arch_initcall(ath724x_pcibios_init);
175