ar71xx_pci.c revision 234217
1187706Sgonzo/*- 2187706Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3187706Sgonzo * All rights reserved. 4187706Sgonzo * 5187706Sgonzo * Redistribution and use in source and binary forms, with or without 6187706Sgonzo * modification, are permitted provided that the following conditions 7187706Sgonzo * are met: 8187706Sgonzo * 1. Redistributions of source code must retain the above copyright 9187706Sgonzo * notice unmodified, this list of conditions, and the following 10187706Sgonzo * disclaimer. 11187706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12187706Sgonzo * notice, this list of conditions and the following disclaimer in the 13187706Sgonzo * documentation and/or other materials provided with the distribution. 14187706Sgonzo * 15187706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16187706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17187706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18187706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19187706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20187706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21187706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22187706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23187706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24187706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25187706Sgonzo * SUCH DAMAGE. 26187706Sgonzo */ 27187706Sgonzo 28187706Sgonzo#include <sys/cdefs.h> 29187706Sgonzo__FBSDID("$FreeBSD: head/sys/mips/atheros/ar71xx_pci.c 234217 2012-04-13 08:45:50Z adrian $"); 30187706Sgonzo 31230195Sadrian#include "opt_ar71xx.h" 32230195Sadrian 33187706Sgonzo#include <sys/param.h> 34187706Sgonzo#include <sys/systm.h> 35187706Sgonzo 36187706Sgonzo#include <sys/bus.h> 37187706Sgonzo#include <sys/interrupt.h> 38187706Sgonzo#include <sys/malloc.h> 39187706Sgonzo#include <sys/kernel.h> 40187706Sgonzo#include <sys/module.h> 41187706Sgonzo#include <sys/rman.h> 42187706Sgonzo 43187706Sgonzo#include <vm/vm.h> 44187706Sgonzo#include <vm/pmap.h> 45187706Sgonzo#include <vm/vm_extern.h> 46187706Sgonzo 47187706Sgonzo#include <machine/bus.h> 48187706Sgonzo#include <machine/cpu.h> 49210900Sgonzo#include <machine/intr_machdep.h> 50187706Sgonzo#include <machine/pmap.h> 51187706Sgonzo 52187706Sgonzo#include <dev/pci/pcivar.h> 53187706Sgonzo#include <dev/pci/pcireg.h> 54187706Sgonzo 55187706Sgonzo#include <dev/pci/pcib_private.h> 56187706Sgonzo#include "pcib_if.h" 57187706Sgonzo 58192161Sgonzo#include <mips/atheros/ar71xxreg.h> 59192161Sgonzo#include <mips/atheros/ar71xx_pci_bus_space.h> 60187706Sgonzo 61211478Sadrian#include <mips/atheros/ar71xx_cpudef.h> 62211478Sadrian 63234217Sadrian#ifdef AR71XX_ATH_EEPROM 64234217Sadrian#include <sys/linker.h> 65234217Sadrian#include <sys/firmware.h> 66234217Sadrian#endif /* AR71XX_ATH_EEPROM */ 67234217Sadrian 68187706Sgonzo#undef AR71XX_PCI_DEBUG 69187706Sgonzo#ifdef AR71XX_PCI_DEBUG 70187706Sgonzo#define dprintf printf 71187706Sgonzo#else 72187706Sgonzo#define dprintf(x, arg...) 73187706Sgonzo#endif 74187706Sgonzo 75187706Sgonzostruct ar71xx_pci_softc { 76187706Sgonzo device_t sc_dev; 77187706Sgonzo 78187706Sgonzo int sc_busno; 79187706Sgonzo struct rman sc_mem_rman; 80187706Sgonzo struct rman sc_irq_rman; 81187706Sgonzo 82191872Sgonzo struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; 83210900Sgonzo mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; 84187706Sgonzo struct resource *sc_irq; 85187706Sgonzo void *sc_ih; 86187706Sgonzo}; 87187706Sgonzo 88191872Sgonzostatic int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, 89191872Sgonzo driver_filter_t *, driver_intr_t *, void *, void **); 90191872Sgonzostatic int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, 91191872Sgonzo void *); 92191872Sgonzostatic int ar71xx_pci_intr(void *); 93191872Sgonzo 94192822Sgonzostatic void 95192822Sgonzoar71xx_pci_mask_irq(void *source) 96191872Sgonzo{ 97191872Sgonzo uint32_t reg; 98192822Sgonzo unsigned int irq = (unsigned int)source; 99191872Sgonzo 100191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 101194273Sgonzo /* flush */ 102194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 103191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); 104191872Sgonzo} 105191872Sgonzo 106192822Sgonzostatic void 107192822Sgonzoar71xx_pci_unmask_irq(void *source) 108191872Sgonzo{ 109191872Sgonzo uint32_t reg; 110192822Sgonzo unsigned int irq = (unsigned int)source; 111191872Sgonzo 112191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 113191872Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); 114194273Sgonzo /* flush */ 115194273Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 116191872Sgonzo} 117191872Sgonzo 118187706Sgonzo/* 119187706Sgonzo * get bitmask for bytes of interest: 120187706Sgonzo * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte 121187706Sgonzo * from register 7. Bitmask would be: 0111 122187706Sgonzo */ 123187706Sgonzostatic uint32_t 124187706Sgonzoar71xx_get_bytes_to_read(int reg, int bytes) 125187706Sgonzo{ 126187706Sgonzo uint32_t bytes_to_read = 0; 127187706Sgonzo if ((bytes % 4) == 0) 128187706Sgonzo bytes_to_read = 0; 129187706Sgonzo else if ((bytes % 4) == 1) 130187706Sgonzo bytes_to_read = (~(1 << (reg % 4))) & 0xf; 131187706Sgonzo else if ((bytes % 4) == 2) 132187706Sgonzo bytes_to_read = (~(3 << (reg % 4))) & 0xf; 133187706Sgonzo else 134187706Sgonzo panic("%s: wrong combination", __func__); 135187706Sgonzo 136187706Sgonzo return (bytes_to_read); 137187706Sgonzo} 138187706Sgonzo 139187706Sgonzostatic int 140187706Sgonzoar71xx_pci_check_bus_error(void) 141187706Sgonzo{ 142187706Sgonzo uint32_t error, addr, has_errors = 0; 143187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; 144187706Sgonzo dprintf("%s: PCI error = %02x\n", __func__, error); 145187706Sgonzo if (error) { 146187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); 147187706Sgonzo 148187706Sgonzo /* Do not report it yet */ 149187706Sgonzo#if 0 150187706Sgonzo printf("PCI bus error %d at addr 0x%08x\n", error, addr); 151187706Sgonzo#endif 152187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_ERROR, error); 153187706Sgonzo has_errors = 1; 154187706Sgonzo } 155187706Sgonzo 156187706Sgonzo error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; 157187706Sgonzo dprintf("%s: AHB error = %02x\n", __func__, error); 158187706Sgonzo if (error) { 159187706Sgonzo addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); 160187706Sgonzo /* Do not report it yet */ 161187706Sgonzo#if 0 162187706Sgonzo printf("AHB bus error %d at addr 0x%08x\n", error, addr); 163187706Sgonzo#endif 164187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); 165187706Sgonzo has_errors = 1; 166187706Sgonzo } 167187706Sgonzo 168187706Sgonzo return (has_errors); 169187706Sgonzo} 170187706Sgonzo 171187706Sgonzostatic uint32_t 172187706Sgonzoar71xx_pci_make_addr(int bus, int slot, int func, int reg) 173187706Sgonzo{ 174187706Sgonzo if (bus == 0) { 175187706Sgonzo return ((1 << slot) | (func << 8) | (reg & ~3)); 176187706Sgonzo } else { 177187706Sgonzo return ((bus << 16) | (slot << 11) | (func << 8) 178187706Sgonzo | (reg & ~3) | 1); 179187706Sgonzo } 180187706Sgonzo} 181187706Sgonzo 182187706Sgonzostatic int 183187706Sgonzoar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, 184187706Sgonzo uint32_t cmd) 185187706Sgonzo{ 186187706Sgonzo uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); 187187706Sgonzo cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); 188187706Sgonzo 189187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); 190187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); 191187706Sgonzo 192187706Sgonzo dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, 193187706Sgonzo bus, slot, func, reg, bytes, addr, cmd); 194187706Sgonzo 195187706Sgonzo return ar71xx_pci_check_bus_error(); 196187706Sgonzo} 197187706Sgonzo 198187706Sgonzostatic uint32_t 199194059Sgonzoar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, 200194059Sgonzo u_int reg, int bytes) 201187706Sgonzo{ 202187706Sgonzo uint32_t data; 203234205Sadrian uint32_t shift, mask; 204187706Sgonzo 205187706Sgonzo /* register access is 32-bit aligned */ 206187706Sgonzo shift = (reg & 3) * 8; 207187706Sgonzo if (shift) 208187706Sgonzo mask = (1 << shift) - 1; 209187706Sgonzo else 210187706Sgonzo mask = 0xffffffff; 211187706Sgonzo 212187706Sgonzo dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 213187706Sgonzo func, reg, bytes); 214187706Sgonzo 215234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 216234204Sadrian PCI_CONF_CMD_READ) == 0) 217234204Sadrian data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); 218234204Sadrian else 219234204Sadrian data = -1; 220187706Sgonzo 221187706Sgonzo /* get request bytes from 32-bit word */ 222187706Sgonzo data = (data >> shift) & mask; 223187706Sgonzo 224187706Sgonzo dprintf("%s: read 0x%x\n", __func__, data); 225187706Sgonzo 226187706Sgonzo return (data); 227187706Sgonzo} 228187706Sgonzo 229187706Sgonzostatic void 230234204Sadrianar71xx_pci_local_write(device_t dev, uint32_t reg, uint32_t data, int bytes) 231187706Sgonzo{ 232187706Sgonzo uint32_t cmd; 233187706Sgonzo 234234204Sadrian dprintf("%s: local write reg %d(%d)\n", __func__, reg, bytes); 235234204Sadrian 236234204Sadrian data = data << (8*(reg % 4)); 237234204Sadrian 238234204Sadrian cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); 239234204Sadrian cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 20); 240234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); 241234204Sadrian ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); 242234204Sadrian} 243234204Sadrian 244234204Sadrianstatic void 245234204Sadrianar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, 246234204Sadrian u_int reg, uint32_t data, int bytes) 247234204Sadrian{ 248234204Sadrian 249234204Sadrian dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, 250187706Sgonzo func, reg, bytes); 251187706Sgonzo 252187706Sgonzo data = data << (8*(reg % 4)); 253187706Sgonzo 254234204Sadrian if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, 255234204Sadrian PCI_CONF_CMD_WRITE) == 0) 256234204Sadrian ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); 257187706Sgonzo} 258187706Sgonzo 259230148Sadrian#ifdef AR71XX_ATH_EEPROM 260230148Sadrian/* 261230148Sadrian * Some embedded boards (eg AP94) have the MAC attached via PCI but they 262230148Sadrian * don't have the MAC-attached EEPROM. The register initialisation 263230148Sadrian * values and calibration data are stored in the on-board flash. 264230148Sadrian * This routine initialises the NIC via the EEPROM register contents 265230148Sadrian * before the probe/attach routines get a go at things. 266230148Sadrian */ 267230148Sadrianstatic void 268230148Sadrianar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func, 269230148Sadrian long flash_addr) 270230148Sadrian{ 271230148Sadrian uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 272230148Sadrian uint32_t reg, val, bar0; 273230148Sadrian 274234217Sadrian if (bootverbose) 275234217Sadrian device_printf(dev, "%s: flash_addr=%lx, cal_data=%p\n", 276234217Sadrian __func__, flash_addr, cal_data); 277230148Sadrian 278230148Sadrian /* XXX check 0xa55a */ 279230148Sadrian /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ 280230148Sadrian bar0 = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_BAR(0), 4); 281230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), 282230148Sadrian AR71XX_PCI_MEM_BASE, 4); 283230148Sadrian 284230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 285230148Sadrian val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 286230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 287230148Sadrian 288230148Sadrian cal_data += 3; 289230148Sadrian while (*cal_data != 0xffff) { 290230148Sadrian reg = *cal_data++; 291230148Sadrian val = *cal_data++; 292230148Sadrian val |= (*cal_data++) << 16; 293234217Sadrian if (bootverbose) 294234217Sadrian printf(" reg: %x, val=%x\n", reg, val); 295230148Sadrian 296230148Sadrian /* Write eeprom fixup data to device memory */ 297230148Sadrian ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); 298230148Sadrian DELAY(100); 299230148Sadrian } 300230148Sadrian 301230148Sadrian val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); 302230148Sadrian val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); 303230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); 304230148Sadrian 305230148Sadrian /* Write the saved bar(0) address */ 306230148Sadrian ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4); 307230148Sadrian} 308230148Sadrian 309234217Sadrian/* 310234217Sadrian * Take a copy of the EEPROM contents and squirrel it away in a firmware. 311234217Sadrian * The SPI flash will eventually cease to be memory-mapped, so we need 312234217Sadrian * to take a copy of this before the SPI driver initialises. 313234217Sadrian */ 314230148Sadrianstatic void 315234217Sadrianar71xx_pci_slot_create_eeprom_firmware(device_t dev, u_int bus, u_int slot, 316234217Sadrian u_int func, long int flash_addr) 317234217Sadrian{ 318234217Sadrian char buf[64]; 319234217Sadrian uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); 320234217Sadrian void *eeprom = NULL; 321234217Sadrian const struct firmware *fw = NULL; 322234217Sadrian int len; 323234217Sadrian 324234217Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", 325234217Sadrian bus, slot, func); 326234217Sadrian 327234217Sadrian if (resource_int_value(device_get_name(dev), device_get_unit(dev), 328234217Sadrian buf, &len) != 0) { 329234217Sadrian device_printf(dev, "%s: missing hint '%s', aborting EEPROM\n", 330234217Sadrian __func__, buf); 331234217Sadrian return; 332234217Sadrian } 333234217Sadrian 334234217Sadrian device_printf(dev, "EEPROM firmware: 0x%lx @ %d bytes\n", 335234217Sadrian flash_addr, len); 336234217Sadrian 337234217Sadrian eeprom = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO); 338234217Sadrian if (! eeprom) { 339234217Sadrian device_printf(dev, 340234217Sadrian "%s: malloc failed for '%s', aborting EEPROM\n", 341234217Sadrian __func__, buf); 342234217Sadrian return; 343234217Sadrian } 344234217Sadrian 345234217Sadrian memcpy(eeprom, cal_data, len); 346234217Sadrian 347234217Sadrian /* 348234217Sadrian * Generate a flash EEPROM 'firmware' from the given memory 349234217Sadrian * region. Since the SPI controller will eventually 350234217Sadrian * go into port-IO mode instead of memory-mapped IO 351234217Sadrian * mode, a copy of the EEPROM contents is required. 352234217Sadrian */ 353234217Sadrian snprintf(buf, sizeof(buf), "%s.%d.bus.%d.%d.%d.eeprom_firmware", 354234217Sadrian device_get_name(dev), device_get_unit(dev), bus, slot, func); 355234217Sadrian fw = firmware_register(buf, eeprom, len, 1, NULL); 356234217Sadrian if (fw == NULL) { 357234217Sadrian device_printf(dev, "%s: firmware_register (%s) failed\n", 358234217Sadrian __func__, buf); 359234217Sadrian free(eeprom, M_DEVBUF); 360234217Sadrian return; 361234217Sadrian } 362234217Sadrian device_printf(dev, "device EEPROM '%s' registered\n", buf); 363234217Sadrian} 364234217Sadrian 365234217Sadrianstatic void 366230148Sadrianar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func) 367230148Sadrian{ 368230148Sadrian long int flash_addr; 369230148Sadrian char buf[32]; 370230148Sadrian 371230148Sadrian /* 372230148Sadrian * Check whether the given slot has a hint to poke. 373230148Sadrian */ 374234217Sadrian if (bootverbose) 375234217Sadrian device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", 376230148Sadrian __func__, device_get_nameunit(dev), bus, slot, func); 377230148Sadrian snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 378230148Sadrian bus, slot, func); 379230148Sadrian 380230148Sadrian if (resource_long_value(device_get_name(dev), device_get_unit(dev), 381230148Sadrian buf, &flash_addr) == 0) { 382234217Sadrian device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", 383234217Sadrian flash_addr, bus, slot, func); 384230148Sadrian ar71xx_pci_fixup(dev, bus, slot, func, flash_addr); 385234217Sadrian ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func, 386234217Sadrian flash_addr); 387230148Sadrian } 388230148Sadrian} 389230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 390230148Sadrian 391187706Sgonzostatic int 392187706Sgonzoar71xx_pci_probe(device_t dev) 393187706Sgonzo{ 394187706Sgonzo 395187706Sgonzo return (0); 396187706Sgonzo} 397187706Sgonzo 398187706Sgonzostatic int 399187706Sgonzoar71xx_pci_attach(device_t dev) 400187706Sgonzo{ 401187706Sgonzo int busno = 0; 402187706Sgonzo int rid = 0; 403187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 404187706Sgonzo 405187706Sgonzo sc->sc_mem_rman.rm_type = RMAN_ARRAY; 406187706Sgonzo sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; 407187706Sgonzo if (rman_init(&sc->sc_mem_rman) != 0 || 408187706Sgonzo rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, 409187706Sgonzo AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { 410187706Sgonzo panic("ar71xx_pci_attach: failed to set up I/O rman"); 411187706Sgonzo } 412187706Sgonzo 413187706Sgonzo sc->sc_irq_rman.rm_type = RMAN_ARRAY; 414187706Sgonzo sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; 415187706Sgonzo if (rman_init(&sc->sc_irq_rman) != 0 || 416187706Sgonzo rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, 417187706Sgonzo AR71XX_PCI_IRQ_END) != 0) 418187706Sgonzo panic("ar71xx_pci_attach: failed to set up IRQ rman"); 419187706Sgonzo 420187706Sgonzo 421187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); 422187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); 423187706Sgonzo 424187706Sgonzo /* Hook up our interrupt handler. */ 425187706Sgonzo if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 426187706Sgonzo RF_SHAREABLE | RF_ACTIVE)) == NULL) { 427187706Sgonzo device_printf(dev, "unable to allocate IRQ resource\n"); 428187706Sgonzo return ENXIO; 429187706Sgonzo } 430187706Sgonzo 431187706Sgonzo if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, 432191872Sgonzo ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { 433187706Sgonzo device_printf(dev, 434187706Sgonzo "WARNING: unable to register interrupt handler\n"); 435187706Sgonzo return ENXIO; 436187706Sgonzo } 437187706Sgonzo 438187706Sgonzo /* reset PCI core and PCI bus */ 439211478Sadrian ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 440203132Sgonzo DELAY(100000); 441187706Sgonzo 442211478Sadrian ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); 443203132Sgonzo DELAY(100000); 444187706Sgonzo 445187706Sgonzo /* Init PCI windows */ 446187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); 447187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); 448187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); 449187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); 450187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); 451187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); 452187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); 453187706Sgonzo ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); 454203132Sgonzo DELAY(100000); 455187706Sgonzo 456187706Sgonzo ar71xx_pci_check_bus_error(); 457187706Sgonzo 458187706Sgonzo /* Fixup internal PCI bridge */ 459234204Sadrian ar71xx_pci_local_write(dev, PCIR_COMMAND, 460234204Sadrian PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN 461187706Sgonzo | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK 462234204Sadrian | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 4); 463187706Sgonzo 464230148Sadrian#ifdef AR71XX_ATH_EEPROM 465230148Sadrian /* 466230148Sadrian * Hard-code a check for slot 17 and 18 - these are 467230148Sadrian * the two PCI slots which may have a PCI device that 468230148Sadrian * requires "fixing". 469230148Sadrian */ 470230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 17, 0); 471230148Sadrian ar71xx_pci_slot_fixup(dev, 0, 18, 0); 472230148Sadrian#endif /* AR71XX_ATH_EEPROM */ 473230148Sadrian 474187706Sgonzo device_add_child(dev, "pci", busno); 475187706Sgonzo return (bus_generic_attach(dev)); 476187706Sgonzo} 477187706Sgonzo 478187706Sgonzostatic int 479187706Sgonzoar71xx_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 480187706Sgonzo{ 481187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 482187706Sgonzo 483187706Sgonzo switch (which) { 484187706Sgonzo case PCIB_IVAR_DOMAIN: 485187706Sgonzo *result = 0; 486187706Sgonzo return (0); 487187706Sgonzo case PCIB_IVAR_BUS: 488187706Sgonzo *result = sc->sc_busno; 489187706Sgonzo return (0); 490187706Sgonzo } 491187706Sgonzo 492187706Sgonzo return (ENOENT); 493187706Sgonzo} 494187706Sgonzo 495187706Sgonzostatic int 496187706Sgonzoar71xx_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) 497187706Sgonzo{ 498187706Sgonzo struct ar71xx_pci_softc * sc = device_get_softc(dev); 499187706Sgonzo 500187706Sgonzo switch (which) { 501187706Sgonzo case PCIB_IVAR_BUS: 502187706Sgonzo sc->sc_busno = result; 503187706Sgonzo return (0); 504187706Sgonzo } 505187706Sgonzo 506187706Sgonzo return (ENOENT); 507187706Sgonzo} 508187706Sgonzo 509187706Sgonzostatic struct resource * 510187706Sgonzoar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, 511187706Sgonzo u_long start, u_long end, u_long count, u_int flags) 512187706Sgonzo{ 513187706Sgonzo 514187706Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 515192161Sgonzo struct resource *rv; 516187706Sgonzo struct rman *rm; 517187706Sgonzo 518187706Sgonzo switch (type) { 519187706Sgonzo case SYS_RES_IRQ: 520187706Sgonzo rm = &sc->sc_irq_rman; 521187706Sgonzo break; 522187706Sgonzo case SYS_RES_MEMORY: 523187706Sgonzo rm = &sc->sc_mem_rman; 524187706Sgonzo break; 525187706Sgonzo default: 526187706Sgonzo return (NULL); 527187706Sgonzo } 528187706Sgonzo 529187706Sgonzo rv = rman_reserve_resource(rm, start, end, count, flags, child); 530187706Sgonzo 531187706Sgonzo if (rv == NULL) 532187706Sgonzo return (NULL); 533187706Sgonzo 534187706Sgonzo rman_set_rid(rv, *rid); 535187706Sgonzo 536187706Sgonzo if (flags & RF_ACTIVE) { 537187706Sgonzo if (bus_activate_resource(child, type, *rid, rv)) { 538187706Sgonzo rman_release_resource(rv); 539187706Sgonzo return (NULL); 540187706Sgonzo } 541187706Sgonzo } 542187706Sgonzo 543192161Sgonzo 544187706Sgonzo return (rv); 545187706Sgonzo} 546187706Sgonzo 547192161Sgonzo 548187706Sgonzostatic int 549192161Sgonzoar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, 550192161Sgonzo struct resource *r) 551192161Sgonzo{ 552192161Sgonzo int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), 553192161Sgonzo child, type, rid, r)); 554192161Sgonzo 555192161Sgonzo if (!res) { 556192161Sgonzo switch(type) { 557192161Sgonzo case SYS_RES_MEMORY: 558192161Sgonzo case SYS_RES_IOPORT: 559192161Sgonzo rman_set_bustag(r, ar71xx_bus_space_pcimem); 560192161Sgonzo break; 561192161Sgonzo } 562192161Sgonzo } 563192161Sgonzo 564192161Sgonzo return (res); 565192161Sgonzo} 566192161Sgonzo 567192161Sgonzo 568192161Sgonzo 569192161Sgonzostatic int 570191872Sgonzoar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, 571191872Sgonzo int flags, driver_filter_t *filt, driver_intr_t *handler, 572191872Sgonzo void *arg, void **cookiep) 573191872Sgonzo{ 574191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(bus); 575191872Sgonzo struct intr_event *event; 576191872Sgonzo int irq, error; 577191872Sgonzo 578191872Sgonzo irq = rman_get_start(ires); 579191872Sgonzo 580191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 581191872Sgonzo panic("%s: bad irq %d", __func__, irq); 582191872Sgonzo 583191872Sgonzo event = sc->sc_eventstab[irq]; 584191872Sgonzo if (event == NULL) { 585191872Sgonzo error = intr_event_create(&event, (void *)irq, 0, irq, 586192822Sgonzo ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, 587210900Sgonzo "pci intr%d:", irq); 588191872Sgonzo 589210900Sgonzo if (error == 0) { 590210900Sgonzo sc->sc_eventstab[irq] = event; 591210900Sgonzo sc->sc_intr_counter[irq] = 592210900Sgonzo mips_intrcnt_create(event->ie_name); 593210900Sgonzo } 594210900Sgonzo else 595210900Sgonzo return error; 596191872Sgonzo } 597191872Sgonzo 598191872Sgonzo intr_event_add_handler(event, device_get_nameunit(child), filt, 599191872Sgonzo handler, arg, intr_priority(flags), flags, cookiep); 600210900Sgonzo mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); 601191872Sgonzo 602192822Sgonzo ar71xx_pci_unmask_irq((void*)irq); 603191872Sgonzo 604191872Sgonzo return (0); 605191872Sgonzo} 606191872Sgonzo 607191872Sgonzostatic int 608191872Sgonzoar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, 609187706Sgonzo void *cookie) 610187706Sgonzo{ 611191872Sgonzo struct ar71xx_pci_softc *sc = device_get_softc(dev); 612191872Sgonzo int irq, result; 613187706Sgonzo 614191872Sgonzo irq = rman_get_start(ires); 615191872Sgonzo if (irq > AR71XX_PCI_IRQ_END) 616191872Sgonzo panic("%s: bad irq %d", __func__, irq); 617191872Sgonzo 618191872Sgonzo if (sc->sc_eventstab[irq] == NULL) 619191872Sgonzo panic("Trying to teardown unoccupied IRQ"); 620191872Sgonzo 621192822Sgonzo ar71xx_pci_mask_irq((void*)irq); 622191872Sgonzo 623191872Sgonzo result = intr_event_remove_handler(cookie); 624191872Sgonzo if (!result) 625191872Sgonzo sc->sc_eventstab[irq] = NULL; 626191872Sgonzo 627191872Sgonzo return (result); 628187706Sgonzo} 629187706Sgonzo 630187706Sgonzostatic int 631191872Sgonzoar71xx_pci_intr(void *arg) 632191872Sgonzo{ 633191872Sgonzo struct ar71xx_pci_softc *sc = arg; 634191872Sgonzo struct intr_event *event; 635194273Sgonzo uint32_t reg, irq, mask; 636191872Sgonzo 637191872Sgonzo reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); 638194273Sgonzo mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); 639194273Sgonzo /* 640194273Sgonzo * Handle only unmasked interrupts 641194273Sgonzo */ 642194273Sgonzo reg &= mask; 643191872Sgonzo for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { 644191872Sgonzo if (reg & (1 << irq)) { 645191872Sgonzo event = sc->sc_eventstab[irq]; 646191872Sgonzo if (!event || TAILQ_EMPTY(&event->ie_handlers)) { 647191872Sgonzo /* Ignore timer interrupts */ 648191872Sgonzo if (irq != 0) 649191872Sgonzo printf("Stray IRQ %d\n", irq); 650191872Sgonzo continue; 651191872Sgonzo } 652191872Sgonzo 653221256Sadrian /* Flush DDR FIFO for IP2 */ 654221256Sadrian ar71xx_device_ddr_flush_ip2(); 655221256Sadrian 656191872Sgonzo /* TODO: frame instead of NULL? */ 657191872Sgonzo intr_event_handle(event, NULL); 658210900Sgonzo mips_intrcnt_inc(sc->sc_intr_counter[irq]); 659191872Sgonzo } 660191872Sgonzo } 661191872Sgonzo 662191872Sgonzo return (FILTER_HANDLED); 663191872Sgonzo} 664191872Sgonzo 665191872Sgonzostatic int 666187706Sgonzoar71xx_pci_maxslots(device_t dev) 667187706Sgonzo{ 668187706Sgonzo 669187706Sgonzo return (PCI_SLOTMAX); 670187706Sgonzo} 671187706Sgonzo 672187706Sgonzostatic int 673187706Sgonzoar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) 674187706Sgonzo{ 675195474Sgonzo if (pci_get_slot(device) < AR71XX_PCI_BASE_SLOT) 676195474Sgonzo panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", 677195474Sgonzo __func__, pci_get_slot(device)); 678187706Sgonzo 679195474Sgonzo return (pci_get_slot(device) - AR71XX_PCI_BASE_SLOT); 680187706Sgonzo} 681187706Sgonzo 682187706Sgonzostatic device_method_t ar71xx_pci_methods[] = { 683187706Sgonzo /* Device interface */ 684187706Sgonzo DEVMETHOD(device_probe, ar71xx_pci_probe), 685187706Sgonzo DEVMETHOD(device_attach, ar71xx_pci_attach), 686187706Sgonzo DEVMETHOD(device_shutdown, bus_generic_shutdown), 687187706Sgonzo DEVMETHOD(device_suspend, bus_generic_suspend), 688187706Sgonzo DEVMETHOD(device_resume, bus_generic_resume), 689187706Sgonzo 690187706Sgonzo /* Bus interface */ 691187706Sgonzo DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), 692187706Sgonzo DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), 693187706Sgonzo DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), 694187706Sgonzo DEVMETHOD(bus_release_resource, bus_generic_release_resource), 695192161Sgonzo DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), 696187706Sgonzo DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 697191872Sgonzo DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), 698187706Sgonzo DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), 699187706Sgonzo 700187706Sgonzo /* pcib interface */ 701187706Sgonzo DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), 702187706Sgonzo DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), 703187706Sgonzo DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), 704187706Sgonzo DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), 705187706Sgonzo 706227843Smarius DEVMETHOD_END 707187706Sgonzo}; 708187706Sgonzo 709187706Sgonzostatic driver_t ar71xx_pci_driver = { 710187706Sgonzo "pcib", 711187706Sgonzo ar71xx_pci_methods, 712187706Sgonzo sizeof(struct ar71xx_pci_softc), 713187706Sgonzo}; 714187706Sgonzo 715187706Sgonzostatic devclass_t ar71xx_pci_devclass; 716187706Sgonzo 717187706SgonzoDRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); 718