1/* $NetBSD: pci_machdep.c,v 1.31 2011/07/01 20:37:08 dyoung Exp $ */ 2 3/* 4 * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.31 2011/07/01 20:37:08 dyoung Exp $"); 30 31#define _COBALT_BUS_DMA_PRIVATE 32 33#include <sys/param.h> 34#include <sys/bus.h> 35#include <sys/errno.h> 36#include <sys/device.h> 37#include <sys/extent.h> 38#include <sys/intr.h> 39#include <sys/systm.h> 40#include <sys/time.h> 41 42#include <dev/pci/pcivar.h> 43#include <dev/pci/pcireg.h> 44#include <dev/pci/pcidevs.h> 45#include <dev/pci/pciconf.h> 46#include <dev/pci/pciide_apollo_reg.h> 47 48#include <cobalt/dev/gtreg.h> 49 50/* 51 * PCI doesn't have any special needs; just use 52 * the generic versions of these functions. 53 */ 54struct cobalt_bus_dma_tag pci_bus_dma_tag = { 55 _bus_dmamap_create, 56 _bus_dmamap_destroy, 57 _bus_dmamap_load, 58 _bus_dmamap_load_mbuf, 59 _bus_dmamap_load_uio, 60 _bus_dmamap_load_raw, 61 _bus_dmamap_unload, 62 _bus_dmamap_sync, 63 _bus_dmamem_alloc, 64 _bus_dmamem_free, 65 _bus_dmamem_map, 66 _bus_dmamem_unmap, 67 _bus_dmamem_mmap, 68}; 69 70void 71pci_attach_hook(struct device *parent, struct device *self, 72 struct pcibus_attach_args *pba) 73{ 74 /* XXX */ 75 76 return; 77} 78 79int 80pci_bus_maxdevs(pci_chipset_tag_t pc, int busno) 81{ 82 83 return 32; 84} 85 86pcitag_t 87pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function) 88{ 89 90 return (bus << 16) | (device << 11) | (function << 8); 91} 92 93void 94pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp) 95{ 96 97 if (bp != NULL) 98 *bp = (tag >> 16) & 0xff; 99 if (dp != NULL) 100 *dp = (tag >> 11) & 0x1f; 101 if (fp != NULL) 102 *fp = (tag >> 8) & 0x07; 103} 104 105pcireg_t 106pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 107{ 108 pcireg_t data; 109 int bus, dev, func; 110 111 KASSERT(pc != NULL); 112 113 pci_decompose_tag(pc, tag, &bus, &dev, &func); 114 115 /* 116 * 2700 hardware wedges on accesses to device 6. 117 */ 118 if (bus == 0 && dev == 6) 119 return 0; 120 /* 121 * 2800 hardware wedges on accesses to device 31. 122 */ 123 if (bus == 0 && dev == 31) 124 return 0; 125 126 bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 127 PCICFG_ENABLE | tag | reg); 128 data = bus_space_read_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA); 129 bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0); 130 131 return data; 132} 133 134void 135pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 136{ 137 138 bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 139 PCICFG_ENABLE | tag | reg); 140 bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_DATA, data); 141 bus_space_write_4(pc->pc_bst, pc->pc_bsh, GT_PCICFG_ADDR, 0); 142} 143 144int 145pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 146{ 147 pci_chipset_tag_t pc = pa->pa_pc; 148 pcitag_t intrtag = pa->pa_intrtag; 149 int pin = pa->pa_intrpin; 150 int line = pa->pa_intrline; 151 int bus, dev, func; 152 153 pci_decompose_tag(pc, intrtag, &bus, &dev, &func); 154 155 /* 156 * The interrupt lines of the internal Tulips are connected 157 * directly to the CPU. 158 */ 159 if (cobalt_id == COBALT_ID_QUBE2700) { 160 if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A) { 161 /* tulip is connected to CPU INT2 on Qube2700 */ 162 *ihp = NICU_INT + 2; 163 return 0; 164 } 165 } else { 166 if (bus == 0 && dev == 7 && pin == PCI_INTERRUPT_PIN_A) { 167 /* the primary tulip is connected to CPU INT1 */ 168 *ihp = NICU_INT + 1; 169 return 0; 170 } 171 if (bus == 0 && dev == 12 && pin == PCI_INTERRUPT_PIN_A) { 172 /* the secondary tulip is connected to CPU INT2 */ 173 *ihp = NICU_INT + 2; 174 return 0; 175 } 176 } 177 178 /* sanity check */ 179 if (line == 0 || line >= NICU_INT) 180 return -1; 181 182 *ihp = line; 183 return 0; 184} 185 186const char * 187pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih) 188{ 189 static char irqstr[8]; 190 191 if (ih >= NICU_INT) 192 sprintf(irqstr, "level %d", ih - NICU_INT); 193 else 194 sprintf(irqstr, "irq %d", ih); 195 196 return irqstr; 197} 198 199const struct evcnt * 200pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih) 201{ 202 203 /* XXX for now, no evcnt parent reported */ 204 return NULL; 205} 206 207int 208pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih, 209 int attr, uint64_t data) 210{ 211 212 switch (attr) { 213 case PCI_INTR_MPSAFE: 214 return 0; 215 default: 216 return ENODEV; 217 } 218} 219 220void * 221pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level, 222 int (*func)(void *), void *arg) 223{ 224 225 if (ih >= NICU_INT) 226 return cpu_intr_establish(ih - NICU_INT, level, func, arg); 227 else 228 return icu_intr_establish(ih, IST_LEVEL, level, func, arg); 229} 230 231void 232pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie) 233{ 234 235 /* Try both, only the valid one will disestablish. */ 236 cpu_intr_disestablish(cookie); 237 icu_intr_disestablish(cookie); 238} 239 240void 241pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int pin, int swiz, 242 int *iline) 243{ 244 245 /* 246 * Use irq 9 on all devices on the Qube's PCI slot. 247 * XXX doesn't handle devices over PCI-PCI bridges 248 */ 249 if (bus == 0 && dev == 10 && pin != PCI_INTERRUPT_PIN_NONE) 250 *iline = 9; 251} 252 253int 254pci_conf_hook(pci_chipset_tag_t pc, int bus, int dev, int func, pcireg_t id) 255{ 256 257 /* ignore bogus IDs */ 258 if (PCI_VENDOR(id) == 0) 259 return 0; 260 261 /* 2700 hardware wedges on accesses to device 6. */ 262 if (bus == 0 && dev == 6) 263 return 0; 264 265 /* 2800 hardware wedges on accesses to device 31. */ 266 if (bus == 0 && dev == 31) 267 return 0; 268 269 /* Don't configure the bridge and PCI probe. */ 270 if (PCI_VENDOR(id) == PCI_VENDOR_MARVELL && 271 PCI_PRODUCT(id) == PCI_PRODUCT_MARVELL_GT64011) 272 return 0; 273 274 /* Don't configure on-board VIA VT82C586 (pcib, uhci) */ 275 if (bus == 0 && dev == 9 && (func == 0 || func == 2)) 276 return 0; 277 278 /* Enable viaide secondary port. Some firmware doesn't enable it. */ 279 if (bus == 0 && dev == 9 && func == 1) { 280 pcitag_t tag; 281 pcireg_t csr; 282 283#define APO_VIAIDECONF (APO_VIA_REGBASE + 0x00) 284 285 tag = pci_make_tag(pc, bus, dev, func); 286 csr = pci_conf_read(pc, tag, APO_VIAIDECONF); 287 pci_conf_write(pc, tag, APO_VIAIDECONF, 288 csr | APO_IDECONF_EN(1)); 289 } 290 return PCI_CONF_DEFAULT & ~(PCI_COMMAND_SERR_ENABLE | 291 PCI_COMMAND_PARITY_ENABLE); 292} 293