ahc_pci.c revision 76634
1250079Scarl/* 2250079Scarl * FreeBSD, PCI product support functions 3289542Scem * 4250079Scarl * Copyright (c) 1995-2001 Justin T. Gibbs 5250079Scarl * All rights reserved. 6250079Scarl * 7250079Scarl * Redistribution and use in source and binary forms, with or without 8250079Scarl * modification, are permitted provided that the following conditions 9250079Scarl * are met: 10250079Scarl * 1. Redistributions of source code must retain the above copyright 11250079Scarl * notice, this list of conditions, and the following disclaimer, 12250079Scarl * without modification, immediately at the beginning of the file. 13250079Scarl * 2. The name of the author may not be used to endorse or promote products 14250079Scarl * derived from this software without specific prior written permission. 15250079Scarl * 16250079Scarl * Alternatively, this software may be distributed under the terms of the 17250079Scarl * GNU Public License ("GPL"). 18250079Scarl * 19250079Scarl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20250079Scarl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21250079Scarl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22250079Scarl * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23250079Scarl * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24250079Scarl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25250079Scarl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26250079Scarl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27250079Scarl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28250079Scarl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29250079Scarl * SUCH DAMAGE. 30250079Scarl * 31250079Scarl * $Id$ 32250079Scarl * 33250079Scarl * $FreeBSD: head/sys/dev/aic7xxx/ahc_pci.c 76634 2001-05-15 19:41:12Z gibbs $ 34250079Scarl */ 35250079Scarl 36250079Scarl#include <dev/aic7xxx/aic7xxx_freebsd.h> 37250079Scarl 38250079Scarl#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ 39289207Scem#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ 40250079Scarl 41250079Scarlstatic int ahc_pci_probe(device_t dev); 42250079Scarlstatic int ahc_pci_attach(device_t dev); 43250079Scarl 44250079Scarlstatic device_method_t ahc_pci_methods[] = { 45250079Scarl /* Device interface */ 46250079Scarl DEVMETHOD(device_probe, ahc_pci_probe), 47250079Scarl DEVMETHOD(device_attach, ahc_pci_attach), 48250079Scarl DEVMETHOD(device_detach, ahc_detach), 49250079Scarl { 0, 0 } 50250079Scarl}; 51250079Scarl 52250079Scarlstatic driver_t ahc_pci_driver = { 53250079Scarl "ahc", 54250079Scarl ahc_pci_methods, 55250079Scarl sizeof(struct ahc_softc) 56250079Scarl}; 57250079Scarl 58250079Scarlstatic devclass_t ahc_devclass; 59250079Scarl 60250079ScarlDRIVER_MODULE(ahc, pci, ahc_pci_driver, ahc_devclass, 0, 0); 61250079ScarlDRIVER_MODULE(ahc, cardbus, ahc_pci_driver, ahc_devclass, 0, 0); 62250079ScarlMODULE_DEPEND(ahc_pci, ahc, 1, 1, 1); 63289648ScemMODULE_VERSION(ahc_pci, 1); 64250079Scarl 65289539Scemstatic int 66289648Scemahc_pci_probe(device_t dev) 67250079Scarl{ 68250079Scarl struct ahc_pci_identity *entry; 69250079Scarl 70250079Scarl entry = ahc_find_pci_device(dev); 71250079Scarl if (entry != NULL) { 72289648Scem device_set_desc(dev, entry->name); 73250079Scarl return (0); 74250079Scarl } 75289610Scem return (ENXIO); 76289610Scem} 77289610Scem 78289610Scemstatic int 79289610Scemahc_pci_attach(device_t dev) 80289610Scem{ 81289610Scem struct ahc_pci_identity *entry; 82289610Scem struct ahc_softc *ahc; 83289610Scem char *name; 84289610Scem int error; 85289610Scem 86289610Scem entry = ahc_find_pci_device(dev); 87289539Scem if (entry == NULL) 88289539Scem return (ENXIO); 89289539Scem 90289539Scem /* 91289539Scem * Allocate a softc for this card and 92289539Scem * set it up for attachment by our 93289539Scem * common detect routine. 94289539Scem */ 95255274Scarl name = malloc(strlen(device_get_nameunit(dev)) + 1, M_DEVBUF, M_NOWAIT); 96255274Scarl if (name == NULL) 97255274Scarl return (ENOMEM); 98255274Scarl strcpy(name, device_get_nameunit(dev)); 99250079Scarl ahc = ahc_alloc(dev, name); 100250079Scarl if (ahc == NULL) 101255274Scarl return (ENOMEM); 102250079Scarl 103289397Scem ahc_set_unit(ahc, device_get_unit(dev)); 104250079Scarl 105250079Scarl /* Allocate a dmatag for our SCB DMA maps */ 106250079Scarl /* XXX Should be a child of the PCI bus dma tag */ 107250079Scarl error = bus_dma_tag_create(/*parent*/NULL, /*alignment*/1, 108250079Scarl /*boundary*/0, 109250079Scarl /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 110250079Scarl /*highaddr*/BUS_SPACE_MAXADDR, 111250079Scarl /*filter*/NULL, /*filterarg*/NULL, 112250079Scarl /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, 113250079Scarl /*maxsegsz*/AHC_MAXTRANSFER_SIZE, 114289543Scem /*flags*/BUS_DMA_ALLOCNOW, 115289543Scem &ahc->parent_dmat); 116289543Scem 117289543Scem if (error != 0) { 118289543Scem printf("ahc_pci_attach: Could not allocate DMA tag " 119250079Scarl "- error %d\n", error); 120250079Scarl ahc_free(ahc); 121250079Scarl return (ENOMEM); 122250079Scarl } 123250079Scarl ahc->dev_softc = dev; 124250079Scarl error = ahc_pci_config(ahc, entry); 125250079Scarl if (error != 0) { 126250079Scarl ahc_free(ahc); 127289546Scem return (error); 128250079Scarl } 129289546Scem 130250079Scarl ahc_attach(ahc); 131250079Scarl return (0); 132289542Scem} 133289542Scem 134289542Scemint 135289542Scemahc_pci_map_registers(struct ahc_softc *ahc) 136289542Scem{ 137289542Scem struct resource *regs; 138289542Scem u_int command; 139289542Scem int regs_type; 140289542Scem int regs_id; 141289542Scem 142289542Scem command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); 143289542Scem regs = NULL; 144289542Scem regs_type = 0; 145289542Scem regs_id = 0; 146289546Scem#ifdef AHC_ALLOW_MEMIO 147289546Scem if ((command & PCIM_CMD_MEMEN) != 0) { 148289546Scem 149289546Scem regs_type = SYS_RES_MEMORY; 150289546Scem regs_id = AHC_PCI_MEMADDR; 151289546Scem regs = bus_alloc_resource(ahc->dev_softc, regs_type, 152289546Scem ®s_id, 0, ~0, 1, RF_ACTIVE); 153289546Scem if (regs != NULL) { 154289546Scem ahc->tag = rman_get_bustag(regs); 155289546Scem ahc->bsh = rman_get_bushandle(regs); 156289546Scem 157289546Scem /* 158289542Scem * Do a quick test to see if memory mapped 159289542Scem * I/O is functioning correctly. 160289542Scem */ 161289542Scem if (ahc_inb(ahc, HCNTRL) == 0xFF) { 162289542Scem device_printf(ahc->dev_softc, 163289542Scem "PCI Device %d:%d:%d failed memory " 164289542Scem "mapped test. Using PIO.\n", 165289542Scem ahc_get_pci_bus(ahc->dev_softc), 166289542Scem ahc_get_pci_slot(ahc->dev_softc), 167289542Scem ahc_get_pci_function(ahc->dev_softc)); 168250079Scarl bus_release_resource(ahc->dev_softc, regs_type, 169250079Scarl regs_id, regs); 170250079Scarl regs = NULL; 171255274Scarl } else { 172250079Scarl command &= ~PCIM_CMD_PORTEN; 173250079Scarl ahc_pci_write_config(ahc->dev_softc, 174250079Scarl PCIR_COMMAND, 175250079Scarl command, /*bytes*/1); 176250079Scarl } 177250079Scarl } 178250079Scarl } 179250079Scarl#endif 180289546Scem if (regs == NULL && (command & PCIM_CMD_PORTEN) != 0) { 181289546Scem regs_type = SYS_RES_IOPORT; 182289546Scem regs_id = AHC_PCI_IOADDR; 183289546Scem regs = bus_alloc_resource(ahc->dev_softc, regs_type, 184289546Scem ®s_id, 0, ~0, 1, RF_ACTIVE); 185289546Scem ahc->tag = rman_get_bustag(regs); 186289546Scem ahc->bsh = rman_get_bushandle(regs); 187250079Scarl command &= ~PCIM_CMD_MEMEN; 188289610Scem ahc_pci_write_config(ahc->dev_softc, 189289610Scem PCIR_COMMAND, 190289610Scem command, /*bytes*/1); 191289539Scem } 192289542Scem ahc->platform_data->regs_res_type = regs_type; 193289542Scem ahc->platform_data->regs_res_id = regs_id; 194289542Scem ahc->platform_data->regs = regs; 195289543Scem 196289542Scem if (regs == NULL) { 197289542Scem device_printf(ahc->dev_softc, 198289539Scem "can't allocate register resources\n"); 199289539Scem return (ENOMEM); 200289539Scem } 201289539Scem return (0); 202289539Scem} 203289542Scem 204289546Scemint 205289546Scemahc_pci_map_int(struct ahc_softc *ahc) 206289546Scem{ 207289546Scem int zero; 208289542Scem 209289542Scem zero = 0; 210289546Scem ahc->platform_data->irq = 211289546Scem bus_alloc_resource(ahc->dev_softc, SYS_RES_IRQ, &zero, 212289542Scem 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 213289542Scem if (ahc->platform_data->irq == NULL) 214289542Scem return (ENOMEM); 215289546Scem ahc->platform_data->irq_res_type = SYS_RES_IRQ; 216289542Scem return (0); 217289542Scem} 218289542Scem 219289542Scemvoid 220289542Scemahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) 221289542Scem{ 222289542Scem uint32_t cap; 223250079Scarl u_int cap_offset; 224250079Scarl 225289234Scem /* 226289234Scem * Traverse the capability list looking for 227289234Scem * the power management capability. 228289234Scem */ 229289234Scem cap = 0; 230289234Scem cap_offset = ahc_pci_read_config(ahc->dev_softc, 231289234Scem PCIR_CAP_PTR, /*bytes*/1); 232289234Scem while (cap_offset != 0) { 233289234Scem 234289234Scem cap = ahc_pci_read_config(ahc->dev_softc, 235289234Scem cap_offset, /*bytes*/4); 236289234Scem if ((cap & 0xFF) == 1 237289234Scem && ((cap >> 16) & 0x3) > 0) { 238289234Scem uint32_t pm_control; 239289234Scem 240289234Scem pm_control = ahc_pci_read_config(ahc->dev_softc, 241289234Scem cap_offset + 4, 242289234Scem /*bytes*/4); 243289234Scem pm_control &= ~0x3; 244289234Scem pm_control |= new_state; 245255279Scarl ahc_pci_write_config(ahc->dev_softc, 246255279Scarl cap_offset + 4, 247255279Scarl pm_control, /*bytes*/2); 248255279Scarl break; 249255279Scarl } 250255279Scarl cap_offset = (cap >> 8) & 0xFF; 251255279Scarl } 252250079Scarl} 253255279Scarl