1/* 2 * Copyright 2010 Andreas Färber <andreas.faerber@web.de> 3 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6/*- 7 * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33#include <KernelExport.h> 34 35#include <platform/openfirmware/devices.h> 36#include <platform/openfirmware/openfirmware.h> 37#include <platform/openfirmware/pci.h> 38 39#include "pci_controller.h" 40#include "pci_io.h" 41#include "pci_openfirmware_priv.h" 42 43 44//#define TRACE_GRACKLE 45 46#ifdef TRACE_GRACKLE 47#define TRACE(fmt...) dprintf(fmt) 48#else 49#define TRACE(fmt...) ; 50#endif 51 52 53struct grackle_range { 54 uint32_t pci_hi; 55 uint32_t pci_mid; 56 uint32_t pci_lo; 57 uint32_t host; 58 uint32_t size_hi; 59 uint32_t size_lo; 60}; 61 62 63struct grackle_host_bridge { 64 int device_node; 65 addr_t address_registers; 66 addr_t data_registers; 67 uint32 bus; 68 struct grackle_range ranges[6]; 69 int range_count; 70}; 71 72 73#define out8rb(address, value) ppc_out8((vuint8*)(address), value) 74#define out16rb(address, value) ppc_out16_reverse((vuint16*)(address), value) 75#define out32rb(address, value) ppc_out32_reverse((vuint32*)(address), value) 76#define in8rb(address) ppc_in8((const vuint8*)(address)) 77#define in16rb(address) ppc_in16_reverse((const vuint16*)(address)) 78#define in32rb(address) ppc_in32_reverse((const vuint32*)(address)) 79 80 81static status_t 82grackle_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, 83 uint8 offset, uint8 size, uint32 *value) 84{ 85 grackle_host_bridge *bridge = (grackle_host_bridge*)cookie; 86 TRACE("grackle_read_pci_config(bus=%u, dev=%u, func=%u, offset=%u, " 87 "size=%u)\n", (int)bus, (int)device, (int)function, (int)offset, 88 (int)size); 89 90 out32rb(bridge->address_registers, (1 << 31) 91 | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8) 92 | (offset & 0xfc)); 93 94 addr_t dataAddress = bridge->data_registers + (offset & 0x3); 95 switch (size) { 96 case 1: 97 *value = in8rb(dataAddress); 98 break; 99 case 2: 100 *value = in16rb(dataAddress); 101 break; 102 case 4: 103 *value = in32rb(dataAddress); 104 break; 105 default: 106 *value = 0xffffffff; 107 break; 108 } 109 110 out32rb(bridge->address_registers, 0); 111 112 return B_OK; 113} 114 115 116static status_t 117grackle_write_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function, 118 uint8 offset, uint8 size, uint32 value) 119{ 120 grackle_host_bridge *bridge = (grackle_host_bridge*)cookie; 121 TRACE("grackle_write_pci_config(bus=%u, dev=%u, func=%u, offset=%u, " 122 "size=%u, value=%lu)\n", (int)bus, (int)device, (int)function, 123 (int)offset, (int)size, value); 124 125 out32rb(bridge->address_registers, (1 << 31) 126 | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x7) << 8) 127 | (offset & 0xfc)); 128 129 addr_t dataAddress = bridge->data_registers + (offset & 0x3); 130 switch (size) { 131 case 1: 132 out8rb(dataAddress, (uint8)value); 133 break; 134 case 2: 135 out16rb(dataAddress, (uint16)value); 136 break; 137 case 4: 138 out32rb(dataAddress, value); 139 break; 140 } 141 142 out32rb(bridge->address_registers, 0); 143 144 return B_OK; 145} 146 147 148static status_t 149grackle_get_max_bus_devices(void *cookie, int32 *count) 150{ 151 *count = 32; 152 return B_OK; 153} 154 155 156static status_t 157grackle_read_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, 158 uint8 pin, uint8 *irq) 159{ 160 return B_ERROR; 161} 162 163 164static status_t 165grackle_write_pci_irq(void *cookie, uint8 bus, uint8 device, uint8 function, 166 uint8 pin, uint8 irq) 167{ 168 return B_ERROR; 169} 170 171 172static pci_controller sGracklePCIController = { 173 grackle_read_pci_config, 174 grackle_write_pci_config, 175 grackle_get_max_bus_devices, 176 grackle_read_pci_irq, 177 grackle_write_pci_irq, 178}; 179 180 181status_t 182ppc_openfirmware_probe_grackle(int deviceNode, 183 const StringArrayPropertyValue &compatibleValue) 184{ 185 if (!compatibleValue.ContainsElement("grackle")) 186 return B_ERROR; 187 188 uint32_t busrange[2]; 189 if (of_getprop(deviceNode, "bus-range", busrange, sizeof(busrange)) != 8) 190 return B_ERROR; 191 192 grackle_host_bridge *bridge = 193 (grackle_host_bridge*)malloc(sizeof(grackle_host_bridge)); 194 if (bridge == NULL) 195 return B_NO_MEMORY; 196 197 bridge->device_node = deviceNode; 198 bridge->address_registers = 0xfec00000; 199 bridge->data_registers = 0xfee00000; 200 bridge->bus = busrange[0]; 201 202 memset(bridge->ranges, 0, sizeof(bridge->ranges)); 203 int bytesRead = of_getprop(deviceNode, "ranges", bridge->ranges, 204 sizeof(bridge->ranges)); 205 if (bytesRead < 0) { 206 dprintf("ppc_openfirmware_probe_grackle: Could not get ranges.\n"); 207 free(bridge); 208 return B_ERROR; 209 } 210 bridge->range_count = bytesRead / sizeof(grackle_range); 211 212 grackle_range *ioRange = NULL; 213 grackle_range *memoryRanges[2]; 214 int memoryRangeCount = 0; 215 216 for (int i = 0; i < bridge->range_count; i++) { 217 grackle_range *range = bridge->ranges + i; 218 switch (range->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { 219 case OFW_PCI_PHYS_HI_SPACE_CONFIG: 220 break; 221 case OFW_PCI_PHYS_HI_SPACE_IO: 222 ioRange = range; 223 break; 224 case OFW_PCI_PHYS_HI_SPACE_MEM32: 225 memoryRanges[memoryRangeCount++] = range; 226 break; 227 case OFW_PCI_PHYS_HI_SPACE_MEM64: 228 break; 229 } 230 } 231 232 if (ioRange == NULL) { 233 dprintf("ppc_openfirmware_probe_grackle: Can't find io range.\n"); 234 free(bridge); 235 return B_ERROR; 236 } 237 238 if (memoryRangeCount == 0) { 239 dprintf("ppc_openfirmware_probe_grackle: Can't find mem ranges.\n"); 240 free(bridge); 241 return B_ERROR; 242 } 243 244 status_t error = pci_controller_add(&sGracklePCIController, bridge); 245 if (error != B_OK) 246 free(bridge); 247 return error; 248} 249