2 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 * Copyright (C) 2002 Benno Rice.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <KernelExport.h>
37 #include <platform/openfirmware/devices.h>
38 #include <platform/openfirmware/openfirmware.h>
39 #include <platform/openfirmware/pci.h>
41 #include "pci_controller.h"
43 #include "pci_openfirmware_priv.h"
46 struct uninorth_range
{
55 struct uninorth_host_bridge
{
57 addr_t address_registers
;
58 addr_t data_registers
;
60 struct uninorth_range ranges
[6];
65 #define out8rb(address, value) ppc_out8((vuint8*)(address), value)
66 #define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value)
67 #define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value)
68 #define in8rb(address) ppc_in8((const vuint8*)(address))
69 #define in16rb(address) ppc_in16_reverse((const vuint16*)(address))
70 #define in32rb(address) ppc_in32_reverse((const vuint32*)(address))
73 static int uninorth_enable_config(struct uninorth_host_bridge
*bridge
,
74 uint8 bus
, uint8 slot
, uint8 function
, uint8 offset
);
76 static status_t
uninorth_read_pci_config(void *cookie
, uint8 bus
, uint8 device
,
77 uint8 function
, uint16 offset
, uint8 size
, uint32
*value
);
78 static status_t
uninorth_write_pci_config(void *cookie
, uint8 bus
,
79 uint8 device
, uint8 function
, uint16 offset
, uint8 size
,
81 static status_t
uninorth_get_max_bus_devices(void *cookie
, int32
*count
);
82 static status_t
uninorth_read_pci_irq(void *cookie
, uint8 bus
, uint8 device
,
83 uint8 function
, uint8 pin
, uint8
*irq
);
84 static status_t
uninorth_write_pci_irq(void *cookie
, uint8 bus
, uint8 device
,
85 uint8 function
, uint8 pin
, uint8 irq
);
87 static pci_controller sUniNorthPCIController
= {
88 uninorth_read_pci_config
,
89 uninorth_write_pci_config
,
90 uninorth_get_max_bus_devices
,
91 uninorth_read_pci_irq
,
92 uninorth_write_pci_irq
,
97 uninorth_read_pci_config(void *cookie
, uint8 bus
, uint8 device
, uint8 function
,
98 uint16 offset
, uint8 size
, uint32
*value
)
100 uninorth_host_bridge
*bridge
= (uninorth_host_bridge
*)cookie
;
105 addr_t caoff
= bridge
->data_registers
+ (offset
& 0x07);
107 if (uninorth_enable_config(bridge
, bus
, device
, function
, offset
) != 0) {
110 *value
= in8rb(caoff
);
113 *value
= in16rb(caoff
);
116 *value
= in32rb(caoff
);
129 static status_t
uninorth_write_pci_config(void *cookie
, uint8 bus
, uint8 device
,
130 uint8 function
, uint16 offset
, uint8 size
, uint32 value
)
132 uninorth_host_bridge
*bridge
= (uninorth_host_bridge
*)cookie
;
137 addr_t caoff
= bridge
->data_registers
+ (offset
& 0x07);
139 if (uninorth_enable_config(bridge
, bus
, device
, function
, offset
)) {
142 out8rb(caoff
, (uint8
)value
);
146 out16rb(caoff
, (uint16
)value
);
150 out32rb(caoff
, value
);
160 static status_t
uninorth_get_max_bus_devices(void *cookie
, int32
*count
)
167 static status_t
uninorth_read_pci_irq(void *cookie
, uint8 bus
, uint8 device
,
168 uint8 function
, uint8 pin
, uint8
*irq
)
174 static status_t
uninorth_write_pci_irq(void *cookie
, uint8 bus
, uint8 device
,
175 uint8 function
, uint8 pin
, uint8 irq
)
185 uninorth_enable_config(struct uninorth_host_bridge
*bridge
, uint8 bus
,
186 uint8 slot
, uint8 function
, uint8 offset
)
189 // if (resource_int_value(device_get_name(sc->sc_dev),
190 // device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) {
196 if (bridge
->bus
== bus
) {
198 * No slots less than 11 on the primary bus
203 cfgval
= (1 << slot
) | (function
<< 8) | (offset
& 0xfc);
205 cfgval
= (bus
<< 16) | (slot
<< 11) | (function
<< 8) |
210 out32rb(bridge
->address_registers
, cfgval
);
211 } while (in32rb(bridge
->address_registers
) != cfgval
);
220 ppc_openfirmware_probe_uninorth(int deviceNode
,
221 const StringArrayPropertyValue
&compatibleValue
)
223 if (!compatibleValue
.ContainsElement("uni-north"))
227 if (of_getprop(deviceNode
, "reg", reg
, sizeof(reg
)) < 8)
231 if (of_getprop(deviceNode
, "bus-range", busrange
, sizeof(busrange
)) != 8)
234 uninorth_host_bridge
*bridge
235 = (uninorth_host_bridge
*)malloc(sizeof(uninorth_host_bridge
));
239 bridge
->device_node
= deviceNode
;
240 bridge
->address_registers
= reg
[0] + 0x800000;
241 bridge
->data_registers
= reg
[0] + 0xc00000;
242 bridge
->bus
= busrange
[0];
243 // TODO: Check whether address and data registers have already been mapped by
244 // the Open Firmware. If not, map them ourselves.
246 memset(bridge
->ranges
, 0, sizeof(bridge
->ranges
));
247 int bytesRead
= of_getprop(deviceNode
, "ranges", bridge
->ranges
,
248 sizeof(bridge
->ranges
));
251 dprintf("ppc_openfirmware_probe_uninorth: Could not get ranges.\n");
255 bridge
->range_count
= bytesRead
/ sizeof(uninorth_range
);
257 uninorth_range
*ioRange
= NULL
;
258 uninorth_range
*memoryRanges
[2];
259 int memoryRangeCount
= 0;
261 for (int i
= 0; i
< bridge
->range_count
; i
++) {
262 uninorth_range
*range
= bridge
->ranges
+ i
;
263 switch (range
->pci_hi
& OFW_PCI_PHYS_HI_SPACEMASK
) {
264 case OFW_PCI_PHYS_HI_SPACE_CONFIG
:
266 case OFW_PCI_PHYS_HI_SPACE_IO
:
269 case OFW_PCI_PHYS_HI_SPACE_MEM32
:
270 memoryRanges
[memoryRangeCount
++] = range
;
272 case OFW_PCI_PHYS_HI_SPACE_MEM64
:
277 if (ioRange
== NULL
) {
278 dprintf("ppc_openfirmware_probe_uninorth: Can't find io range.\n");
283 if (memoryRangeCount
== 0) {
284 dprintf("ppc_openfirmware_probe_uninorth: Can't find mem ranges.\n");
289 status_t error
= pci_controller_add(&sUniNorthPCIController
, bridge
);