9
9
#include <linux/of_pci.h>
10
10
#include <linux/pci.h>
11
11
#include <linux/pci_ids.h>
12
+ #include <linux/pci-acpi.h>
13
+ #include <linux/pci-ecam.h>
12
14
13
15
#include "../pci.h"
14
16
18
20
#define DEV_PCIE_PORT_2 0x7a29
19
21
20
22
#define DEV_LS2K_APB 0x7a02
21
- #define DEV_LS7A_CONF 0x7a10
23
+ #define DEV_LS7A_GMAC 0x7a03
24
+ #define DEV_LS7A_DC1 0x7a06
22
25
#define DEV_LS7A_LPC 0x7a0c
26
+ #define DEV_LS7A_AHCI 0x7a08
27
+ #define DEV_LS7A_CONF 0x7a10
28
+ #define DEV_LS7A_GNET 0x7a13
29
+ #define DEV_LS7A_EHCI 0x7a14
30
+ #define DEV_LS7A_DC2 0x7a36
31
+ #define DEV_LS7A_HDMI 0x7a37
23
32
24
33
#define FLAG_CFG0 BIT(0)
25
34
#define FLAG_CFG1 BIT(1)
26
35
#define FLAG_DEV_FIX BIT(2)
36
+ #define FLAG_DEV_HIDDEN BIT(3)
37
+
38
+ struct loongson_pci_data {
39
+ u32 flags ;
40
+ struct pci_ops * ops ;
41
+ };
27
42
28
43
struct loongson_pci {
29
44
void __iomem * cfg0_base ;
30
45
void __iomem * cfg1_base ;
31
46
struct platform_device * pdev ;
32
- u32 flags ;
47
+ const struct loongson_pci_data * data ;
33
48
};
34
49
35
50
/* Fixup wrong class code in PCIe bridges */
@@ -92,55 +107,106 @@ static void loongson_mrrs_quirk(struct pci_dev *dev)
92
107
}
93
108
DECLARE_PCI_FIXUP_ENABLE (PCI_ANY_ID , PCI_ANY_ID , loongson_mrrs_quirk );
94
109
95
- static void __iomem * cfg1_map (struct loongson_pci * priv , int bus ,
96
- unsigned int devfn , int where )
110
+ static void loongson_pci_pin_quirk (struct pci_dev * pdev )
97
111
{
98
- unsigned long addroff = 0x0 ;
112
+ pdev -> pin = 1 + (PCI_FUNC (pdev -> devfn ) & 3 );
113
+ }
114
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
115
+ DEV_LS7A_DC1 , loongson_pci_pin_quirk );
116
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
117
+ DEV_LS7A_DC2 , loongson_pci_pin_quirk );
118
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
119
+ DEV_LS7A_GMAC , loongson_pci_pin_quirk );
120
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
121
+ DEV_LS7A_AHCI , loongson_pci_pin_quirk );
122
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
123
+ DEV_LS7A_EHCI , loongson_pci_pin_quirk );
124
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
125
+ DEV_LS7A_GNET , loongson_pci_pin_quirk );
126
+ DECLARE_PCI_FIXUP_FINAL (PCI_VENDOR_ID_LOONGSON ,
127
+ DEV_LS7A_HDMI , loongson_pci_pin_quirk );
128
+
129
+ static struct loongson_pci * pci_bus_to_loongson_pci (struct pci_bus * bus )
130
+ {
131
+ struct pci_config_window * cfg ;
99
132
100
- if (bus != 0 )
101
- addroff |= BIT ( 28 ); /* Type 1 Access */
102
- addroff |= ( where & 0xff ) | (( where & 0xf00 ) << 16 );
103
- addroff |= ( bus << 16 ) | ( devfn << 8 ) ;
104
- return priv -> cfg1_base + addroff ;
133
+ if (acpi_disabled )
134
+ return ( struct loongson_pci * )( bus -> sysdata );
135
+
136
+ cfg = bus -> sysdata ;
137
+ return ( struct loongson_pci * )( cfg -> priv ) ;
105
138
}
106
139
107
- static void __iomem * cfg0_map (struct loongson_pci * priv , int bus ,
108
- unsigned int devfn , int where )
140
+ static void __iomem * cfg0_map (struct loongson_pci * priv , struct pci_bus * bus ,
141
+ unsigned int devfn , int where )
109
142
{
110
143
unsigned long addroff = 0x0 ;
144
+ unsigned char busnum = bus -> number ;
111
145
112
- if (bus != 0 )
146
+ if (! pci_is_root_bus ( bus )) {
113
147
addroff |= BIT (24 ); /* Type 1 Access */
114
- addroff |= (bus << 16 ) | (devfn << 8 ) | where ;
148
+ addroff |= (busnum << 16 );
149
+ }
150
+ addroff |= (devfn << 8 ) | where ;
115
151
return priv -> cfg0_base + addroff ;
116
152
}
117
153
118
- static void __iomem * pci_loongson_map_bus (struct pci_bus * bus , unsigned int devfn ,
119
- int where )
154
+ static void __iomem * cfg1_map (struct loongson_pci * priv , struct pci_bus * bus ,
155
+ unsigned int devfn , int where )
120
156
{
157
+ unsigned long addroff = 0x0 ;
121
158
unsigned char busnum = bus -> number ;
122
- struct pci_host_bridge * bridge = pci_find_host_bridge (bus );
123
- struct loongson_pci * priv = pci_host_bridge_priv (bridge );
159
+
160
+ if (!pci_is_root_bus (bus )) {
161
+ addroff |= BIT (28 ); /* Type 1 Access */
162
+ addroff |= (busnum << 16 );
163
+ }
164
+ addroff |= (devfn << 8 ) | (where & 0xff ) | ((where & 0xf00 ) << 16 );
165
+ return priv -> cfg1_base + addroff ;
166
+ }
167
+
168
+ static bool pdev_may_exist (struct pci_bus * bus , unsigned int device ,
169
+ unsigned int function )
170
+ {
171
+ return !(pci_is_root_bus (bus ) &&
172
+ (device >= 9 && device <= 20 ) && (function > 0 ));
173
+ }
174
+
175
+ static void __iomem * pci_loongson_map_bus (struct pci_bus * bus ,
176
+ unsigned int devfn , int where )
177
+ {
178
+ unsigned int device = PCI_SLOT (devfn );
179
+ unsigned int function = PCI_FUNC (devfn );
180
+ struct loongson_pci * priv = pci_bus_to_loongson_pci (bus );
124
181
125
182
/*
126
183
* Do not read more than one device on the bus other than
127
- * the host bus. For our hardware the root bus is always bus 0.
184
+ * the host bus.
128
185
*/
129
- if (priv -> flags & FLAG_DEV_FIX && busnum != 0 &&
130
- PCI_SLOT (devfn ) > 0 )
131
- return NULL ;
186
+ if ((priv -> data -> flags & FLAG_DEV_FIX ) && bus -> self ) {
187
+ if (!pci_is_root_bus (bus ) && (device > 0 ))
188
+ return NULL ;
189
+ }
190
+
191
+ /* Don't access non-existent devices */
192
+ if (priv -> data -> flags & FLAG_DEV_HIDDEN ) {
193
+ if (!pdev_may_exist (bus , device , function ))
194
+ return NULL ;
195
+ }
132
196
133
197
/* CFG0 can only access standard space */
134
198
if (where < PCI_CFG_SPACE_SIZE && priv -> cfg0_base )
135
- return cfg0_map (priv , busnum , devfn , where );
199
+ return cfg0_map (priv , bus , devfn , where );
136
200
137
201
/* CFG1 can access extended space */
138
202
if (where < PCI_CFG_SPACE_EXP_SIZE && priv -> cfg1_base )
139
- return cfg1_map (priv , busnum , devfn , where );
203
+ return cfg1_map (priv , bus , devfn , where );
140
204
141
205
return NULL ;
142
206
}
143
207
208
+ #ifdef CONFIG_OF
209
+
144
210
static int loongson_map_irq (const struct pci_dev * dev , u8 slot , u8 pin )
145
211
{
146
212
int irq ;
@@ -159,20 +225,42 @@ static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
159
225
return val ;
160
226
}
161
227
162
- /* H/w only accept 32-bit PCI operations */
228
+ /* LS2K/LS7A accept 8/16/ 32-bit PCI config operations */
163
229
static struct pci_ops loongson_pci_ops = {
230
+ .map_bus = pci_loongson_map_bus ,
231
+ .read = pci_generic_config_read ,
232
+ .write = pci_generic_config_write ,
233
+ };
234
+
235
+ /* RS780/SR5690 only accept 32-bit PCI config operations */
236
+ static struct pci_ops loongson_pci_ops32 = {
164
237
.map_bus = pci_loongson_map_bus ,
165
238
.read = pci_generic_config_read32 ,
166
239
.write = pci_generic_config_write32 ,
167
240
};
168
241
242
+ static const struct loongson_pci_data ls2k_pci_data = {
243
+ .flags = FLAG_CFG1 | FLAG_DEV_FIX | FLAG_DEV_HIDDEN ,
244
+ .ops = & loongson_pci_ops ,
245
+ };
246
+
247
+ static const struct loongson_pci_data ls7a_pci_data = {
248
+ .flags = FLAG_CFG1 | FLAG_DEV_FIX | FLAG_DEV_HIDDEN ,
249
+ .ops = & loongson_pci_ops ,
250
+ };
251
+
252
+ static const struct loongson_pci_data rs780e_pci_data = {
253
+ .flags = FLAG_CFG0 ,
254
+ .ops = & loongson_pci_ops32 ,
255
+ };
256
+
169
257
static const struct of_device_id loongson_pci_of_match [] = {
170
258
{ .compatible = "loongson,ls2k-pci" ,
171
- .data = ( void * )( FLAG_CFG0 | FLAG_CFG1 | FLAG_DEV_FIX ) , },
259
+ .data = & ls2k_pci_data , },
172
260
{ .compatible = "loongson,ls7a-pci" ,
173
- .data = ( void * )( FLAG_CFG0 | FLAG_CFG1 | FLAG_DEV_FIX ) , },
261
+ .data = & ls7a_pci_data , },
174
262
{ .compatible = "loongson,rs780e-pci" ,
175
- .data = ( void * )( FLAG_CFG0 ) , },
263
+ .data = & rs780e_pci_data , },
176
264
{}
177
265
};
178
266
@@ -193,20 +281,20 @@ static int loongson_pci_probe(struct platform_device *pdev)
193
281
194
282
priv = pci_host_bridge_priv (bridge );
195
283
priv -> pdev = pdev ;
196
- priv -> flags = ( unsigned long ) of_device_get_match_data (dev );
284
+ priv -> data = of_device_get_match_data (dev );
197
285
198
- regs = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
199
- if (!regs ) {
200
- dev_err (dev , "missing mem resources for cfg0\n" );
201
- return - EINVAL ;
286
+ if (priv -> data -> flags & FLAG_CFG0 ) {
287
+ regs = platform_get_resource (pdev , IORESOURCE_MEM , 0 );
288
+ if (!regs )
289
+ dev_err (dev , "missing mem resources for cfg0\n" );
290
+ else {
291
+ priv -> cfg0_base = devm_pci_remap_cfg_resource (dev , regs );
292
+ if (IS_ERR (priv -> cfg0_base ))
293
+ return PTR_ERR (priv -> cfg0_base );
294
+ }
202
295
}
203
296
204
- priv -> cfg0_base = devm_pci_remap_cfg_resource (dev , regs );
205
- if (IS_ERR (priv -> cfg0_base ))
206
- return PTR_ERR (priv -> cfg0_base );
207
-
208
- /* CFG1 is optional */
209
- if (priv -> flags & FLAG_CFG1 ) {
297
+ if (priv -> data -> flags & FLAG_CFG1 ) {
210
298
regs = platform_get_resource (pdev , IORESOURCE_MEM , 1 );
211
299
if (!regs )
212
300
dev_info (dev , "missing mem resource for cfg1\n" );
@@ -218,7 +306,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
218
306
}
219
307
220
308
bridge -> sysdata = priv ;
221
- bridge -> ops = & loongson_pci_ops ;
309
+ bridge -> ops = priv -> data -> ops ;
222
310
bridge -> map_irq = loongson_map_irq ;
223
311
224
312
return pci_host_probe (bridge );
@@ -232,3 +320,41 @@ static struct platform_driver loongson_pci_driver = {
232
320
.probe = loongson_pci_probe ,
233
321
};
234
322
builtin_platform_driver (loongson_pci_driver );
323
+
324
+ #endif
325
+
326
+ #ifdef CONFIG_ACPI
327
+
328
+ static int loongson_pci_ecam_init (struct pci_config_window * cfg )
329
+ {
330
+ struct device * dev = cfg -> parent ;
331
+ struct loongson_pci * priv ;
332
+ struct loongson_pci_data * data ;
333
+
334
+ priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
335
+ if (!priv )
336
+ return - ENOMEM ;
337
+
338
+ data = devm_kzalloc (dev , sizeof (* data ), GFP_KERNEL );
339
+ if (!data )
340
+ return - ENOMEM ;
341
+
342
+ cfg -> priv = priv ;
343
+ data -> flags = FLAG_CFG1 | FLAG_DEV_HIDDEN ;
344
+ priv -> data = data ;
345
+ priv -> cfg1_base = cfg -> win - (cfg -> busr .start << 16 );
346
+
347
+ return 0 ;
348
+ }
349
+
350
+ const struct pci_ecam_ops loongson_pci_ecam_ops = {
351
+ .bus_shift = 16 ,
352
+ .init = loongson_pci_ecam_init ,
353
+ .pci_ops = {
354
+ .map_bus = pci_loongson_map_bus ,
355
+ .read = pci_generic_config_read ,
356
+ .write = pci_generic_config_write ,
357
+ }
358
+ };
359
+
360
+ #endif
0 commit comments