2 * Support for indirect PCI bridges.
4 * Copyright (C) 1998 Gabriel Paubert.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <linux/pci.h>
14 #include <linux/delay.h>
15 #include <linux/string.h>
16 #include <linux/init.h>
20 #include <asm/pci-bridge.h>
21 #include <asm/machdep.h>
23 #ifdef CONFIG_PPC_INDIRECT_PCI_BE
24 #define PCI_CFG_OUT out_be32
26 #define PCI_CFG_OUT out_le32
30 indirect_read_config(struct pci_bus
*bus
, unsigned int devfn
, int offset
,
33 struct pci_controller
*hose
= bus
->sysdata
;
34 volatile void __iomem
*cfg_data
;
37 if (ppc_md
.pci_exclude_device
)
38 if (ppc_md
.pci_exclude_device(bus
->number
, devfn
))
39 return PCIBIOS_DEVICE_NOT_FOUND
;
41 if (hose
->set_cfg_type
)
42 if (bus
->number
!= hose
->first_busno
)
45 PCI_CFG_OUT(hose
->cfg_addr
,
46 (0x80000000 | ((bus
->number
- hose
->bus_offset
) << 16)
47 | (devfn
<< 8) | ((offset
& 0xfc) | cfg_type
)));
50 * Note: the caller has already checked that offset is
51 * suitably aligned and that len is 1, 2 or 4.
53 cfg_data
= hose
->cfg_data
+ (offset
& 3);
56 *val
= in_8(cfg_data
);
59 *val
= in_le16(cfg_data
);
62 *val
= in_le32(cfg_data
);
65 return PCIBIOS_SUCCESSFUL
;
69 indirect_write_config(struct pci_bus
*bus
, unsigned int devfn
, int offset
,
72 struct pci_controller
*hose
= bus
->sysdata
;
73 volatile void __iomem
*cfg_data
;
76 if (ppc_md
.pci_exclude_device
)
77 if (ppc_md
.pci_exclude_device(bus
->number
, devfn
))
78 return PCIBIOS_DEVICE_NOT_FOUND
;
80 if (hose
->set_cfg_type
)
81 if (bus
->number
!= hose
->first_busno
)
84 PCI_CFG_OUT(hose
->cfg_addr
,
85 (0x80000000 | ((bus
->number
- hose
->bus_offset
) << 16)
86 | (devfn
<< 8) | ((offset
& 0xfc) | cfg_type
)));
89 * Note: the caller has already checked that offset is
90 * suitably aligned and that len is 1, 2 or 4.
92 cfg_data
= hose
->cfg_data
+ (offset
& 3);
98 out_le16(cfg_data
, val
);
101 out_le32(cfg_data
, val
);
104 return PCIBIOS_SUCCESSFUL
;
107 static struct pci_ops indirect_pci_ops
=
109 indirect_read_config
,
110 indirect_write_config
114 setup_indirect_pci_nomap(struct pci_controller
* hose
, void __iomem
* cfg_addr
,
115 void __iomem
* cfg_data
)
117 hose
->cfg_addr
= cfg_addr
;
118 hose
->cfg_data
= cfg_data
;
119 hose
->ops
= &indirect_pci_ops
;
123 setup_indirect_pci(struct pci_controller
* hose
, u32 cfg_addr
, u32 cfg_data
)
125 unsigned long base
= cfg_addr
& PAGE_MASK
;
126 void __iomem
*mbase
, *addr
, *data
;
128 mbase
= ioremap(base
, PAGE_SIZE
);
129 addr
= mbase
+ (cfg_addr
& ~PAGE_MASK
);
130 if ((cfg_data
& PAGE_MASK
) != base
)
131 mbase
= ioremap(cfg_data
& PAGE_MASK
, PAGE_SIZE
);
132 data
= mbase
+ (cfg_data
& ~PAGE_MASK
);
133 setup_indirect_pci_nomap(hose
, addr
, data
);