1 /* $NetBSD: ixp425_pci.c,v 1.6 2009/10/21 14:15:50 rmind Exp $ */ 2 3 /* 4 * Copyright (c) 2003 5 * Ichiro FUKUHARA <ichiro@ichiro.org>. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: ixp425_pci.c,v 1.6 2009/10/21 14:15:50 rmind Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/device.h> 36 #include <sys/extent.h> 37 #include <sys/malloc.h> 38 39 #include <uvm/uvm_extern.h> 40 41 #include <machine/bus.h> 42 43 #include <arm/xscale/ixp425reg.h> 44 #include <arm/xscale/ixp425var.h> 45 46 #include <evbarm/ixdp425/ixdp425reg.h> 47 48 #include <dev/pci/pcireg.h> 49 #include <dev/pci/pcivar.h> 50 #include <dev/pci/pciconf.h> 51 52 #include "opt_pci.h" 53 #include "pci.h" 54 55 void ixp425_pci_attach_hook(struct device *, struct device *, 56 struct pcibus_attach_args *); 57 int ixp425_pci_bus_maxdevs(void *, int); 58 void ixp425_pci_decompose_tag(void *, pcitag_t, int *, int *, int *); 59 void ixp425_pci_conf_setup(void *, struct ixp425_softc *, pcitag_t, int); 60 void ixp425_pci_conf_write(void *, pcitag_t, int, pcireg_t); 61 pcitag_t ixp425_pci_make_tag(void *, int, int, int); 62 pcireg_t ixp425_pci_conf_read(void *, pcitag_t, int); 63 64 #define MAX_PCI_DEVICES 32 65 66 void 67 ixp425_pci_init(struct ixp425_softc *sc) 68 { 69 pci_chipset_tag_t pc = &sc->ia_pci_chipset; 70 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE) 71 struct extent *ioext, *memext; 72 #endif 73 /* 74 * Initialise the PCI chipset tag 75 */ 76 pc->pc_conf_v = sc; 77 pc->pc_attach_hook = ixp425_pci_attach_hook; 78 pc->pc_bus_maxdevs = ixp425_pci_bus_maxdevs; 79 pc->pc_make_tag = ixp425_pci_make_tag; 80 pc->pc_decompose_tag = ixp425_pci_decompose_tag; 81 pc->pc_conf_read = ixp425_pci_conf_read; 82 pc->pc_conf_write = ixp425_pci_conf_write; 83 84 /* 85 * Initialize the bus space tags. 86 */ 87 ixp425_io_bs_init(&sc->sc_pci_iot, sc); 88 ixp425_mem_bs_init(&sc->sc_pci_memt, sc); 89 90 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE) 91 ioext = extent_create("pciio", 0, IXP425_PCI_IO_SIZE - 1, 92 M_DEVBUF, NULL, 0, EX_NOWAIT); 93 /* PCI MEM space is mapped same address as real memory */ 94 memext = extent_create("pcimem", IXP425_PCI_MEM_HWBASE, 95 IXP425_PCI_MEM_HWBASE + 96 IXP425_PCI_MEM_SIZE - 1, 97 M_DEVBUF, NULL, 0, EX_NOWAIT); 98 printf("%s: configuring PCI bus\n", sc->sc_dev.dv_xname); 99 pci_configure_bus(pc, ioext, memext, NULL, 0 /* XXX bus = 0 */, 100 arm_dcache_align); 101 102 extent_destroy(ioext); 103 extent_destroy(memext); 104 #endif 105 } 106 107 void 108 pci_conf_interrupt(pci_chipset_tag_t pc, int a, int b, int c, int d, int *p) 109 { 110 } 111 112 void 113 ixp425_pci_attach_hook(struct device *parent, struct device *self, 114 struct pcibus_attach_args *pba) 115 { 116 /* Nothing to do. */ 117 } 118 119 int 120 ixp425_pci_bus_maxdevs(void *v, int busno) 121 { 122 return(MAX_PCI_DEVICES); 123 } 124 125 pcitag_t 126 ixp425_pci_make_tag(void *v, int bus, int device, int function) 127 { 128 #ifdef PCI_DEBUG 129 printf("ixp425_pci_make_tag(v=%p, bus=%d, device=%d, function=%d)\n", 130 v, bus, device, function); 131 #endif 132 return ((bus << 16) | (device << 11) | (function << 8)); 133 } 134 135 void 136 ixp425_pci_decompose_tag(void *v, pcitag_t tag, int *busp, int *devicep, 137 int *functionp) 138 { 139 #ifdef PCI_DEBUG 140 printf("ixp425_pci_decompose_tag(v=%p, tag=0x%08lx, bp=%x, dp=%x, fp=%x)\n", 141 v, tag, (int)busp, (int)devicep, (int)functionp); 142 #endif 143 if (busp != NULL) 144 *busp = (tag >> 16) & 0xff; 145 if (devicep != NULL) 146 *devicep = (tag >> 11) & 0x1f; 147 if (functionp != NULL) 148 *functionp = (tag >> 8) & 0x7; 149 } 150 151 void 152 ixp425_pci_conf_setup(void *v, struct ixp425_softc *sc, pcitag_t tag, int offset) 153 { 154 int bus, device, function; 155 156 ixp425_pci_decompose_tag(v, tag, &bus, &device, &function); 157 158 if (bus == 0) { 159 if (device == 0 && function == 0) { 160 PCI_CSR_WRITE_4(sc, PCI_NP_AD, (offset & ~3)); 161 } else { 162 /* configuration type 0 */ 163 PCI_CSR_WRITE_4(sc, PCI_NP_AD, (1U << (32 - device)) | 164 (function << 8) | (offset & ~3)); 165 } 166 } else { 167 /* configuration type 1 */ 168 PCI_CSR_WRITE_4(sc, PCI_NP_AD, 169 (bus << 16) | (device << 11) | 170 (function << 8) | (offset & ~3) | 1); 171 } 172 } 173 174 /* read/write PCI Non-Pre-fetch Data */ 175 176 pcireg_t 177 ixp425_pci_conf_read(void *v, pcitag_t tag, int offset) 178 { 179 struct ixp425_softc *sc = v; 180 u_int32_t data; 181 pcireg_t rv; 182 int s; 183 #define PCI_NP_HAVE_BUG 184 #ifdef PCI_NP_HAVE_BUG 185 int i; 186 #endif 187 188 PCI_CONF_LOCK(s); 189 ixp425_pci_conf_setup(v, sc, tag, offset); 190 191 #ifdef PCI_DEBUG 192 printf("ixp425_pci_conf_read: tag=%lx,offset=%x\n", 193 tag, offset); 194 #endif 195 196 #ifdef PCI_NP_HAVE_BUG 197 /* PCI NP Bug workaround */ 198 for (i = 0; i < 8; i++) { 199 PCI_CSR_WRITE_4(sc, PCI_NP_CBE, COMMAND_NP_CONF_READ); 200 rv = PCI_CSR_READ_4(sc, PCI_NP_RDATA); 201 rv = PCI_CSR_READ_4(sc, PCI_NP_RDATA); 202 } 203 #else 204 PCI_CSR_WRITE_4(sc, PCI_NP_CBE, COMMAND_NP_CONF_READ); 205 rv = PCI_CSR_READ_4(sc, PCI_NP_RDATA); 206 #endif 207 208 /* check&clear PCI abort */ 209 data = PCI_CSR_READ_4(sc, PCI_ISR); 210 if (data & ISR_PFE) { 211 PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_PFE); 212 PCI_CONF_UNLOCK(s); 213 return -1; 214 } else { 215 PCI_CONF_UNLOCK(s); 216 return rv; 217 } 218 } 219 220 void 221 ixp425_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val) 222 { 223 struct ixp425_softc *sc = v; 224 u_int32_t data; 225 int s; 226 227 PCI_CONF_LOCK(s); 228 229 ixp425_pci_conf_setup(v, sc, tag, offset); 230 #ifdef PCI_DEBUG 231 printf("ixp425_pci_conf_write: tag=%lx offset=%x <- val=%x\n", 232 tag, offset, val); 233 #endif 234 PCI_CSR_WRITE_4(sc, PCI_NP_CBE, COMMAND_NP_CONF_WRITE); 235 PCI_CSR_WRITE_4(sc, PCI_NP_WDATA, val); 236 237 /* check&clear PCI abort */ 238 data = PCI_CSR_READ_4(sc, PCI_ISR); 239 if (data & ISR_PFE) 240 PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_PFE); 241 242 PCI_CONF_UNLOCK(s); 243 } 244 245 /* read/write pci configuration data */ 246 247 uint32_t 248 ixp425_pci_conf_reg_read(struct ixp425_softc *sc, uint32_t reg) 249 { 250 uint32_t data; 251 252 bus_space_write_4(sc->sc_iot, sc->sc_pci_ioh, 253 PCI_CRP_AD_CBE, ((reg & ~3) | COMMAND_CRP_READ)); 254 data = bus_space_read_4(sc->sc_iot, sc->sc_pci_ioh, 255 PCI_CRP_AD_RDATA); 256 257 return data; 258 } 259 260 void 261 ixp425_pci_conf_reg_write(struct ixp425_softc *sc, uint32_t reg, 262 uint32_t data) 263 { 264 bus_space_write_4(sc->sc_iot, sc->sc_pci_ioh, 265 PCI_CRP_AD_CBE, ((reg & ~3) | COMMAND_CRP_WRITE)); 266 bus_space_write_4(sc->sc_iot, sc->sc_pci_ioh, 267 PCI_CRP_AD_WDATA, data); 268 } 269