Index: stable/4/sys/pccard/i82365.h =================================================================== --- stable/4/sys/pccard/i82365.h (revision 83007) +++ stable/4/sys/pccard/i82365.h (revision 83008) @@ -1,295 +1,301 @@ /* * i82365.h - Definitions for Intel 82365 PCIC * PCMCIA Card Interface Controller * * originally by Barry Jaspan; hacked over by Keith Moore * hacked to unrecognisability by Andrew McRae (andrew@mega.com.au) * * Updated 3/3/95 to include Cirrus Logic stuff. *------------------------------------------------------------------------- * * Copyright (c) 2001 M. Warner Losh. All rights reserved. * Copyright (c) 1995 Andrew McRae. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #define PCIC_I82365 0 /* Intel i82365SL-A/B or clone */ #define PCIC_IBM 1 /* IBM clone */ #define PCIC_VLSI 2 /* VLSI chip */ #define PCIC_PD672X 3 /* Cirrus logic 672x */ #define PCIC_PD6710 4 /* Cirrus logic 6710 */ #define PCIC_VG365 5 /* Vadem 365 */ #define PCIC_VG465 6 /* Vadem 465 */ #define PCIC_VG468 7 /* Vadem 468 */ #define PCIC_VG469 8 /* Vadem 469 */ #define PCIC_RF5C296 9 /* Ricoh RF5C296 */ #define PCIC_RF5C396 10 /* Ricoh RF5C396 */ #define PCIC_IBM_KING 11 /* IBM KING PCMCIA Controller */ #define PCIC_I82365SL_DF 12 /* Intel i82365sl-DF step */ /* * Address of the controllers. Each controller can manage * two PCMCIA slots. Up to 8 slots are supported in total. * The PCIC controller is accessed via an index port and a * data port. The index port has the 8 bit address of the * register accessed via the data port. How I long for * real memory mapped I/O! * The top two bits of the index address are used to * identify the port number, and the lower 6 bits * select one of the 64 possible data registers. */ #define PCIC_INDEX 0 /* Index register */ #define PCIC_DATA 1 /* Data register */ #define PCIC_NPORT 2 /* Number of ports */ #define PCIC_PORT_0 0x3e0 /* index reg, chips 0 and 1 */ /* * Register index addresses. */ #define PCIC_ID_REV 0x00 /* Identification and Revision */ #define PCIC_STATUS 0x01 /* Interface Status */ #define PCIC_POWER 0x02 /* Power and RESETDRV control */ #define PCIC_INT_GEN 0x03 /* Interrupt and General Control */ #define PCIC_STAT_CHG 0x04 /* Card Status Change */ #define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */ #define PCIC_ADDRWINE 0x06 /* Address Window Enable */ #define PCIC_IOCTL 0x07 /* I/O Control */ #define PCIC_IO0 0x08 /* I/O Address 0 */ #define PCIC_IO1 0x0c /* I/O Address 1 */ #define PCIC_MEMBASE 0x10 /* Base of memory window registers */ #define PCIC_CDGC 0x16 /* Card Detect and General Control */ #define PCIC_MISC1 0x16 /* PD672x: Misc control register 1 per slot */ #define PCIC_GLO_CTRL 0x1e /* Global Control Register */ #define PCIC_MISC2 0x1e /* PD672x: Misc control register 2 per chip */ #define PCIC_CLCHIP 0x1f /* PD67xx: Chip I/D */ #define PCIC_CVSR 0x2f /* Vadem: Voltage select register */ #define PCIC_RICOH_MCR2 0x2f /* Ricoh: Mode Control Register 2 */ #define PCIC_VMISC 0x3a /* Vadem: Misc control register */ #define PCIC_RICOH_ID 0x3a /* Ricoh: ID register */ +#define PCIC_TOPIC_FCR 0x3e /* Toshiba ToPIC: Function Control Register */ + #define PCIC_TIME_SETUP0 0x3a #define PCIC_TIME_CMD0 0x3b #define PCIC_TIME_RECOV0 0x3c #define PCIC_TIME_SETUP1 0x3d #define PCIC_TIME_CMD1 0x3e #define PCIC_TIME_RECOV1 0x3f #define PCIC_SLOT_SIZE 0x40 /* Size of register set for one slot */ /* Now register bits, ordered by reg # */ /* For Identification and Revision (PCIC_ID_REV) */ #define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */ #define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */ #define PCIC_INTEL2 0x84 /* Intel 82365SL step D */ #define PCIC_VLSI82C146 0x84 /* VLSI 82C146 */ #define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */ #define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */ #define PCIC_IBM3 0x8a /* IBM KING PCIC clone; Both Memory and I/O */ /* For Interface Status register (PCIC_STATUS) */ #define PCIC_VPPV 0x80 /* Vpp_valid */ #define PCIC_POW 0x40 /* PC Card power active */ #define PCIC_READY 0x20 /* Ready/~Busy */ #define PCIC_MWP 0x10 /* Memory Write Protect */ #define PCIC_CD 0x0C /* Both card detect bits */ #define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */ /* For the Power and RESETDRV register (PCIC_POWER) */ #define PCIC_OUTENA 0x80 /* Output Enable */ #define PCIC_DISRST 0x40 /* Disable RESETDRV */ #define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */ #define PCIC_PCPWRE 0x10 /* PC Card Power Enable */ #define PCIC_VCC 0x18 /* Vcc control bits */ #define PCIC_VCC_5V 0x10 /* 5 volts */ #define PCIC_VCC_ON 0x10 /* Turn on VCC on some chips. */ #define PCIC_VCC_3V 0x18 /* 3 volts */ #define PCIC_VCC_5V_KING 0x14 /* 5 volts for KING PCIC */ #define PCIC_VPP 0x03 /* Vpp control bits */ #define PCIC_VPP_5V 0x01 /* 5 volts */ #define PCIC_VPP_12V 0x02 /* 12 volts */ /* For the Interrupt and General Control register (PCIC_INT_GEN) */ #define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */ #define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */ #define PCIC_IOCARD 0x20 #define PCIC_MEMCARD 0x00 #define PCIC_INTR_ENA 0x10 /* PCI CSC Interrupt enable */ /* For the Card Status Change register (PCIC_STAT_CHG) */ #define PCIC_CDTCH 0x08 /* Card Detect Change */ #define PCIC_RDYCH 0x04 /* Ready Change */ #define PCIC_BATWRN 0x02 /* Battery Warning */ #define PCIC_BATDED 0x01 /* Battery Dead */ /* For the Card status change interrupt PCIC_STAT_INT */ #define PCIC_CSCSELECT 0xf0 /* CSCSELECT */ #define PCIC_SI_IRQ_SHIFT 4 #define PCIC_CDEN 0x8 #define PCIC_READYEN 0x4 #define PCIC_BATWARNEN 0x2 #define PCIC_BATDEADEN 0x1 /* * For the Address Window Enable Register (PCIC_ADDRWINE) * The lower 6 bits contain enable bits for the memory * windows (LSB = memory window 0). */ #define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */ #define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */ #define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */ /* * For the I/O Control Register (PCIC_IOCTL) * The lower nybble is the flags for I/O window 0 * The upper nybble is the flags for I/O window 1 */ #define PCIC_IO_16BIT 0x01 /* I/O to this segment is 16 bit */ #define PCIC_IO_CS16 0x02 /* I/O cs16 source is the card */ #define PCIC_IO_0WS 0x04 /* zero wait states added on 8 bit cycles */ #define PCIC_IO_WS 0x08 /* Wait states added for 16 bit cycles */ /* * The memory window registers contain the start and end * physical host address that the PCIC maps to the card, * and an offset calculated from the card memory address. * All values are shifted down 12 bits, so allocation is * done in 4Kb blocks. Only 12 bits of each value is * stored, limiting the range to the ISA address size of * 24 bits. The upper 4 bits of the most significant byte * within the values are used for various flags. * * The layout is: * * base+0 : lower 8 bits of system memory start address * base+1 : upper 4 bits of system memory start address + flags * base+2 : lower 8 bits of system memory end address * base+3 : upper 4 bits of system memory end address + flags * base+4 : lower 8 bits of offset to card address * base+5 : upper 4 bits of offset to card address + flags * * The following two bytes are reserved for other use. */ #define PCIC_MEMSIZE 8 /* * Flags for system memory start address upper byte */ #define PCIC_ZEROWS 0x40 /* Zero wait states */ #define PCIC_DATA16 0x80 /* Data width is 16 bits */ /* * Flags for system memory end address upper byte */ #define PCIC_MW0 0x40 /* Wait state bit 0 */ #define PCIC_MW1 0x80 /* Wait state bit 1 */ /* * Flags for card offset upper byte */ #define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */ #define PCIC_WP 0x80 /* Write-protect this window */ /* For Card Detect and General Control register (PCIC_CDGC) */ #define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */ #define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */ #define PCIC_GPI_EN 0x04 /* GPI Enable */ #define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */ #define PCIC_CDRES_EN 0x10 /* card detect resume enable */ #define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */ #define PCIC_VS1STAT 0x40 /* 0 VS1# low, 1 VS1# high */ #define PCIC_VS2STAT 0x80 /* 0 VS2# low, 1 VS2# high */ /* CL-PD67[12]x: For 3.3V cards, etc. (PCIC_MISC1) */ #define PCIC_MISC1_5V_DETECT 0x01 /* PD6710 only */ #define PCIC_MISC1_VCC_33 0x02 /* Set Vcc is 3.3V, else 5.0V */ #define PCIC_MISC1_PMINT 0x04 /* Pulse management intr */ #define PCIC_MISC1_PCINT 0x08 /* Pulse card interrupt */ #define PCIC_MISC1_SPEAKER 0x10 /* Enable speaker */ #define PCIC_MISC1_INPACK 0x80 /* INPACK throttles data */ /* i82365B and newer (!PD67xx) Global Control register (PCIC_GLO_CTRL) */ #define PCIC_PWR_DOWN 0x01 /* power down */ #define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */ #define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */ /* Rev B only */ #define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */ #define PCIC_IRQ1_LEVEL 0x10 /* CL-PD67[12]x: For Misc. Control Register 2 (PCIC_MISC2) */ #define PCIC_LPDM_EN 0x02 /* Cirrus PD672x: low power dynamic mode */ /* CL-PD67[12]x: Chip info (PCIC_CLCHIP) */ #define PCIC_CLC_TOGGLE 0xc0 /* These bits toggle 1 -> 0 */ #define PCIC_CLC_DUAL 0x20 /* Single/dual socket version */ /* Vadem: Card Voltage Select register (PCIC_CVSR) */ #define PCIC_CVSR_VS 0x03 /* Voltage select */ #define PCIC_CVSR_VS_5 0x00 /* 5.0 V */ #define PCIC_CVSR_VS_33a 0x01 /* alt 3.3V */ #define PCIC_CVSR_VS_XX 0x02 /* X.XV when available */ #define PCIC_CVSR_VS_33 0x03 /* 3.3V */ /* Ricoh: Misc Control Register 2 (PCIC_RICOH_MCR2) */ #define PCIC_MCR2_VCC_33 0x01 /* 3.3V */ /* Vadem: misc register (PCIC_VMISC) */ #define PCIC_VADEMREV 0x40 /* Ricoh: ID register values (PCIC_RICOH_ID) */ #define PCIC_RID_296 0x32 #define PCIC_RID_396 0xb2 + +/* Toshiba ToPIC: Function Control Register */ +#define PCIC_FCR_3V_EN 0x01 /* Enable 3V cards */ +#define PCIC_FCR_VS_EN 0x02 /* Voltage Sense enable */ /* * Mask of allowable interrupts. * * For IBM-AT machines, irqs 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 are * allowed. Nearly all IBM-AT machines with pcic cards or bridges * wire these interrupts (or a subset thereof) to the corresponding * pins on the ISA bus. Some older laptops are reported to not route * all the interrupt pins to the bus because the designers knew that * some would conflict with builtin devices. * * For NEC PC98 machines, irq 3, 5, 6, 9, 10, 11, 12, 13 are allowed. * These correspond to the C-BUS signals INT 0, 1, 2, 3, 41, 42, 5, 6 * respectively. This is with the desktop C-BUS addin card. * * Hiroshi TSUKADA-san writes in FreeBSD98-testers that cbus IRQ * 6 is routed to the IRQ 7 pin of the pcic in pc98 cbus based * cards. I do not know how pc98 laptop models are wired. */ #ifdef PC98 #define PCIC_INT_MASK_ALLOWED 0x3E68 /* PC98 */ #else #define PCIC_INT_MASK_ALLOWED 0xDEB8 /* AT */ #endif #define PCIC_IO_WIN 2 #define PCIC_MEM_WIN 5 #define PCIC_CARD_SLOTS 4 #define PCIC_MAX_CARDS 2 #define PCIC_MAX_SLOTS (PCIC_MAX_CARDS * PCIC_CARD_SLOTS) Index: stable/4/sys/pccard/pcic.c =================================================================== --- stable/4/sys/pccard/pcic.c (revision 83007) +++ stable/4/sys/pccard/pcic.c (revision 83008) @@ -1,1016 +1,1100 @@ /* * Intel PCIC or compatible Controller driver *------------------------------------------------------------------------- * * Copyright (c) 2001 M. Warner Losh. All rights reserved. * Copyright (c) 1995 Andrew McRae. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include /* Get pnp IDs */ #include #include #include #include "card_if.h" /* * Prototypes for interrupt handler. */ static int pcic_ioctl(struct slot *, int, caddr_t); static int pcic_power(struct slot *); static void pcic_mapirq(struct slot *, int); static timeout_t pcic_reset; static void pcic_resume(struct slot *); static void pcic_disable(struct slot *); static int pcic_memory(struct slot *, int); static int pcic_io(struct slot *, int); devclass_t pcic_devclass; static struct slot_ctrl pcic_cinfo = { pcic_mapirq, pcic_memory, pcic_io, pcic_reset, pcic_disable, pcic_power, pcic_ioctl, pcic_resume, PCIC_MEM_WIN, PCIC_IO_WIN }; /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, pcic, CTLFLAG_RD, 0, "PCIC parameters"); int pcic_override_irq = 0; TUNABLE_INT("machdep.pccard.pcic_irq", &pcic_override_irq); TUNABLE_INT("hw.pcic.irq", &pcic_override_irq); SYSCTL_INT(_hw_pcic, OID_AUTO, irq, CTLFLAG_RD, &pcic_override_irq, 0, "Override the IRQ configured by the config system for all pcic devices"); /* * Read a register from the PCIC. */ unsigned char pcic_getb_io(struct pcic_slot *sp, int reg) { bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, sp->offset + reg); return (bus_space_read_1(sp->bst, sp->bsh, PCIC_DATA)); } /* * Write a register on the PCIC */ void pcic_putb_io(struct pcic_slot *sp, int reg, unsigned char val) { /* * Many datasheets recommend using outw rather than outb to save * a microsecond. Maybe we should do this, but we'd likely only * save 20-30us on card activation. */ bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, sp->offset + reg); bus_space_write_1(sp->bst, sp->bsh, PCIC_DATA, val); } /* * Clear bit(s) of a register. */ __inline void pcic_clrb(struct pcic_slot *sp, int reg, unsigned char mask) { sp->putb(sp, reg, sp->getb(sp, reg) & ~mask); } /* * Set bit(s) of a register */ __inline void pcic_setb(struct pcic_slot *sp, int reg, unsigned char mask) { sp->putb(sp, reg, sp->getb(sp, reg) | mask); } /* * Write a 16 bit value to 2 adjacent PCIC registers */ static __inline void pcic_putw(struct pcic_slot *sp, int reg, unsigned short word) { sp->putb(sp, reg, word & 0xFF); sp->putb(sp, reg + 1, (word >> 8) & 0xff); } /* * pc98 cbus cards introduce a slight wrinkle here. They route the irq7 pin * from the pcic chip to INT 2 on the cbus. INT 2 is normally mapped to * irq 6 on the pc98 architecture, so if we get a request for irq 6 * lie to the hardware and say it is 7. All the other usual mappings for * cbus INT into irq space are the same as the rest of the system. */ static __inline int host_irq_to_pcic(int irq) { #ifdef PC98 if (irq == 6) irq = 7; #endif return (irq); } /* * Free up resources allocated so far. */ void pcic_dealloc(device_t dev) { struct pcic_softc *sc; sc = (struct pcic_softc *) device_get_softc(dev); if (sc->slot_poll) untimeout(sc->slot_poll, sc, sc->timeout_ch); if (sc->iores) bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores); if (sc->memres) bus_release_resource(dev, SYS_RES_MEMORY, sc->memrid, sc->memres); if (sc->ih) bus_teardown_intr(dev, sc->irqres, sc->ih); if (sc->irqres) bus_release_resource(dev, SYS_RES_IRQ, sc->irqrid, sc->irqres); } /* * entry point from main code to map/unmap memory context. */ static int pcic_memory(struct slot *slt, int win) { struct pcic_slot *sp = slt->cdata; struct mem_desc *mp = &slt->mem[win]; int reg = win * PCIC_MEMSIZE + PCIC_MEMBASE; if (win < 0 || win >= slt->ctrl->maxmem) { printf("Illegal PCIC MEMORY window request %d\n", win); return (ENXIO); } if (mp->flags & MDF_ACTIVE) { unsigned long sys_addr = (uintptr_t)(void *)mp->start >> 12; /* * Write the addresses, card offsets and length. * The values are all stored as the upper 12 bits of the * 24 bit address i.e everything is allocated as 4 Kb chunks. */ pcic_putw(sp, reg, sys_addr & 0xFFF); pcic_putw(sp, reg+2, (sys_addr + (mp->size >> 12) - 1) & 0xFFF); pcic_putw(sp, reg+4, ((mp->card >> 12) - sys_addr) & 0x3FFF); /* * Each 16 bit register has some flags in the upper bits. */ if (mp->flags & MDF_16BITS) pcic_setb(sp, reg+1, PCIC_DATA16); if (mp->flags & MDF_ZEROWS) pcic_setb(sp, reg+1, PCIC_ZEROWS); if (mp->flags & MDF_WS0) pcic_setb(sp, reg+3, PCIC_MW0); if (mp->flags & MDF_WS1) pcic_setb(sp, reg+3, PCIC_MW1); if (mp->flags & MDF_ATTR) pcic_setb(sp, reg+5, PCIC_REG); if (mp->flags & MDF_WP) pcic_setb(sp, reg+5, PCIC_WP); /* * Enable the memory window. By experiment, we need a delay. */ pcic_setb(sp, PCIC_ADDRWINE, (1<cdata; struct io_desc *ip = &slt->io[win]; if (bootverbose) { printf("pcic: I/O win %d flags %x %x-%x\n", win, ip->flags, ip->start, ip->start+ip->size-1); } switch (win) { case 0: mask = PCIC_IO0_EN; reg = PCIC_IO0; break; case 1: mask = PCIC_IO1_EN; reg = PCIC_IO1; break; default: printf("Illegal PCIC I/O window request %d\n", win); return (ENXIO); } if (ip->flags & IODF_ACTIVE) { unsigned char x, ioctlv; pcic_putw(sp, reg, ip->start); pcic_putw(sp, reg+2, ip->start+ip->size-1); x = 0; if (ip->flags & IODF_ZEROWS) x |= PCIC_IO_0WS; if (ip->flags & IODF_WS) x |= PCIC_IO_WS; if (ip->flags & IODF_CS16) x |= PCIC_IO_CS16; if (ip->flags & IODF_16BIT) x |= PCIC_IO_16BIT; /* * Extract the current flags and merge with new flags. * Flags for window 0 in lower nybble, and in upper nybble * for window 1. */ ioctlv = sp->getb(sp, PCIC_IOCTL); DELAY(100); switch (win) { case 0: sp->putb(sp, PCIC_IOCTL, x | (ioctlv & 0xf0)); break; case 1: sp->putb(sp, PCIC_IOCTL, (x << 4) | (ioctlv & 0xf)); break; } DELAY(100); pcic_setb(sp, PCIC_ADDRWINE, mask); DELAY(100); } else { pcic_clrb(sp, PCIC_ADDRWINE, mask); DELAY(100); pcic_putw(sp, reg, 0); pcic_putw(sp, reg + 2, 0); } return (0); } static void pcic_do_mgt_irq(struct pcic_slot *sp, int irq) { u_int32_t reg; if (sp->sc->csc_route == pcic_iw_pci) { /* Do the PCI side of things: Enable the Card Change int */ reg = CB_SM_CD; bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_MASK, reg); /* * TI Chips need us to set the following. We tell the * controller to route things via PCI interrupts. Also * we clear the interrupt number in the STAT_INT register * as well. The TI-12xx and newer chips require one or the * other of these to happen, depending on what is set in the * diagnostic register. I do both on the theory that other * chips might need one or the other and that no harm will * come from it. If there is harm, then I'll make it a bit * in the tables. */ pcic_setb(sp, PCIC_INT_GEN, PCIC_INTR_ENA); pcic_clrb(sp, PCIC_STAT_INT, PCIC_CSCSELECT); } else { /* Management IRQ changes */ /* * The PCIC_INTR_ENA bit means either "tie the function * and csc interrupts together" or "Route csc interrupts * via PCI" or "Reserved". In any case, we want to clear * it since we're using ISA interrupts. */ pcic_clrb(sp, PCIC_INT_GEN, PCIC_INTR_ENA); irq = host_irq_to_pcic(irq); sp->putb(sp, PCIC_STAT_INT, (irq << PCIC_SI_IRQ_SHIFT) | PCIC_CDEN); } } int pcic_attach(device_t dev) { int i; device_t kid; struct pcic_softc *sc; struct slot *slt; struct pcic_slot *sp; sc = (struct pcic_softc *) device_get_softc(dev); callout_handle_init(&sc->timeout_ch); sp = &sc->slots[0]; for (i = 0; i < PCIC_CARD_SLOTS; i++, sp++) { if (!sp->slt) continue; sp->slt = 0; kid = device_add_child(dev, NULL, -1); if (kid == NULL) { device_printf(dev, "Can't add pccard bus slot %d", i); return (ENXIO); } device_probe_and_attach(kid); slt = pccard_init_slot(kid, &pcic_cinfo); if (slt == 0) { device_printf(dev, "Can't get pccard info slot %d", i); return (ENXIO); } sc->slotmask |= (1 << i); slt->cdata = sp; sp->slt = slt; sp->sc = sc; } sp = &sc->slots[0]; for (i = 0; i < PCIC_CARD_SLOTS; i++, sp++) { if (sp->slt == NULL) continue; pcic_do_mgt_irq(sp, sc->irq); sp->slt->irq = sc->irq; /* Check for changes */ pcic_setb(sp, PCIC_POWER, PCIC_PCPWRE | PCIC_DISRST); sp->slt->laststate = sp->slt->state = empty; pcic_do_stat_delta(sp); } return (bus_generic_attach(dev)); } static int pcic_sresource(struct slot *slt, caddr_t data) { struct pccard_resource *pr; struct resource *r; int flags; int rid = 0; device_t bridgedev = slt->dev; struct pcic_slot *sp = slt->cdata; pr = (struct pccard_resource *)data; pr->resource_addr = ~0ul; /* * If we're using PCI interrupt routing, then force the IRQ to * use and to heck with what the user requested. If they want * to be able to request IRQs, they must use ISA interrupt * routing. If we don't give them an irq, and it is the * pccardd 0,0 case, then just return (giving the "bad resource" * return in pr->resource_addr). */ if (pr->type == SYS_RES_IRQ) { if (sp->sc->func_route >= pcic_iw_pci) { pr->resource_addr = sp->sc->irq; return (0); } if (pr->min == 0 && pr->max == 0) return (0); } /* * Make sure we grok this type. */ switch(pr->type) { default: return (EINVAL); case SYS_RES_MEMORY: case SYS_RES_IRQ: case SYS_RES_IOPORT: break; } /* * Allocate the resource, and align it to the most natural * size. If we get it, then tell userland what we actually got * in the range they requested. */ flags = rman_make_alignment_flags(pr->size); r = bus_alloc_resource(bridgedev, pr->type, &rid, pr->min, pr->max, pr->size, flags); if (r != NULL) { pr->resource_addr = (u_long)rman_get_start(r); bus_release_resource(bridgedev, pr->type, rid, r); } return (0); } /* * ioctl calls - Controller specific ioctls */ static int pcic_ioctl(struct slot *slt, int cmd, caddr_t data) { struct pcic_slot *sp = slt->cdata; struct pcic_reg *preg = (struct pcic_reg *) data; switch(cmd) { default: return (ENOTTY); case PIOCGREG: /* Get pcic register */ preg->value = sp->getb(sp, preg->reg); break; /* Set pcic register */ case PIOCSREG: sp->putb(sp, preg->reg, preg->value); break; case PIOCSRESOURCE: /* Can I use this resource? */ pcic_sresource(slt, data); break; } return (0); } /* + * pcic_cardbus_power + * + * Power the card up, as specified, using the cardbus power + * registers to control power. Microsoft recommends that cardbus + * vendors support powering the card via cardbus registers because + * there is no standard for 3.3V cards. Since at least a few of the + * cardbus bridges have minor issues with power via the ExCA registers, + * go ahead and do it all via cardbus registers. + * + * An expamination of the code will show the relative + * ease that we do Vpp as well. + * + * Too bad it appears to not work. + */ +static int +pcic_cardbus_power(struct pcic_slot *sp, struct slot *slt) +{ + uint32_t reg; + + /* + * Preserve the clock stop bit of the socket power register. + */ + reg = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_POWER); + printf("old value 0x%x\n", reg); + reg &= CB_SP_CLKSTOP; + + switch(slt->pwr.vpp) { + default: + return (EINVAL); + case 0: + reg |= CB_SP_VPP_0V; + break; + case 33: + reg |= CB_SP_VPP_3V; + break; + case 50: + reg |= CB_SP_VPP_5V; + break; + case 120: + reg |= CB_SP_VPP_12V; + break; + } + + switch(slt->pwr.vcc) { + default: + return (EINVAL); + case 0: + reg |= CB_SP_VCC_0V; + break; + case 33: + reg |= CB_SP_VCC_3V; + break; + case 50: + reg |= CB_SP_VCC_5V; + break; + } + printf("Setting power reg to 0x%x", reg); + bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_POWER, reg); + + return (EIO); +} + +/* * pcic_power - Enable the power of the slot according to * the parameters in the power structure(s). */ static int pcic_power(struct slot *slt) { unsigned char c; unsigned char reg = PCIC_DISRST | PCIC_PCPWRE; struct pcic_slot *sp = slt->cdata; struct pcic_softc *sc = sp->sc; - if (sc->flags & (PCIC_DF_POWER | PCIC_AB_POWER)) { + /* + * Cardbus power registers are completely different. + */ + if (sc->flags & PCIC_CARDBUS_POWER) + return (pcic_cardbus_power(sp, slt)); + + if (sc->flags & PCIC_DF_POWER) { /* * Look at the VS[12]# bits on the card. If VS1 is clear * then we should apply 3.3 volts. */ c = sp->getb(sp, PCIC_CDGC); if ((c & PCIC_VS1STAT) == 0) slt->pwr.vcc = 33; } /* * XXX Note: The Vpp controls varies quit a bit between bridge chips * and the following might not be right in all cases. The Linux * code and wildboar code bases are more complex. However, most * applications want vpp == vcc and the following code does appear * to do that for all bridge sets. */ switch(slt->pwr.vpp) { default: return (EINVAL); case 0: break; case 50: case 33: reg |= PCIC_VPP_5V; break; case 120: reg |= PCIC_VPP_12V; break; } if (slt->pwr.vcc) reg |= PCIC_VCC_ON; /* Turn on Vcc */ switch(slt->pwr.vcc) { default: return (EINVAL); case 0: break; case 33: /* * The wildboar code has comments that state that * the IBM KING controller doesn't support 3.3V * on the "IBM Smart PC card drive". The code * intemates that's the only place they have seen * it used and that there's a boatload of issues * with it. I'm not even sure this is right because * the only docs I've been able to find say this is for * 5V power. Of course, this "doc" is just code comments * so who knows for sure. */ if (sc->flags & PCIC_KING_POWER) { reg |= PCIC_VCC_5V_KING; break; } if (sc->flags & PCIC_VG_POWER) { pcic_setb(sp, PCIC_CVSR, PCIC_CVSR_VS); break; } if (sc->flags & PCIC_PD_POWER) { pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33); break; } if (sc->flags & PCIC_RICOH_POWER) { pcic_setb(sp, PCIC_RICOH_MCR2, PCIC_MCR2_VCC_33); break; } - - /* - * Technically, The A, B, C stepping didn't support - * the 3.3V cards. However, many cardbus bridges are - * identified as B step cards by our probe routine, so - * we do both. It won't hurt the A, B, C bridges that - * don't support this bit since it is one of the - * reserved bits. - */ - if (sc->flags & (PCIC_AB_POWER | PCIC_DF_POWER)) + if (sc->flags & PCIC_DF_POWER) reg |= PCIC_VCC_3V; break; case 50: if (sc->flags & PCIC_KING_POWER) reg |= PCIC_VCC_5V_KING; /* * For all of the variant power schemes for 3.3V go * ahead and turn off the 3.3V enable bit. For all * bridges, the setting the Vcc on bit does the rest. * Note that we don't have to turn off the 3.3V bit * for the '365 step D since with the reg assigments * to this point it doesn't get turned on. */ if (sc->flags & PCIC_VG_POWER) pcic_clrb(sp, PCIC_CVSR, PCIC_CVSR_VS); if (sc->flags & PCIC_PD_POWER) pcic_clrb(sp, PCIC_MISC1, PCIC_MISC1_VCC_33); if (sc->flags & PCIC_RICOH_POWER) pcic_clrb(sp, PCIC_RICOH_MCR2, PCIC_MCR2_VCC_33); break; } sp->putb(sp, PCIC_POWER, reg); DELAY(300*1000); if (slt->pwr.vcc) { reg |= PCIC_OUTENA; sp->putb(sp, PCIC_POWER, reg); DELAY(100*1000); } /* * Some chipsets will attempt to preclude us from supplying * 5.0V to cards that only handle 3.3V. We seem to need to * try 3.3V to paper over some power handling issues in other * parts of the system. I suspect they are in the pccard bus * driver, but may be in pccardd as well. */ if (!(sp->getb(sp, PCIC_STATUS) & PCIC_POW) && slt->pwr.vcc == 50) { slt->pwr.vcc = 33; slt->pwr.vpp = 0; return (pcic_power(slt)); } return (0); } /* * tell the PCIC which irq we want to use. only the following are legal: * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15. We require the callers of this * routine to do the check for legality. */ static void pcic_mapirq(struct slot *slt, int irq) { struct pcic_slot *sp = slt->cdata; - if (sp->sc->csc_route == pcic_iw_pci) - return; - irq = host_irq_to_pcic(irq); - if (irq == 0) - pcic_clrb(sp, PCIC_INT_GEN, 0xF); - else - sp->putb(sp, PCIC_INT_GEN, - (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq); + + sp->sc->chip->map_irq(sp, irq); } /* * pcic_reset - Reset the card and enable initial power. */ static void pcic_reset(void *chan) { struct slot *slt = chan; struct pcic_slot *sp = slt->cdata; + if (bootverbose) + device_printf(sp->sc->dev, "reset %d ", slt->insert_seq); switch (slt->insert_seq) { case 0: /* Something funny happended on the way to the pub... */ + if (bootverbose) + printf("\n"); return; case 1: /* Assert reset */ pcic_clrb(sp, PCIC_INT_GEN, PCIC_CARDRESET); + if (bootverbose) + printf("int is %x stat is %x\n", + sp->getb(sp, PCIC_INT_GEN), + sp->getb(sp, PCIC_STATUS)); slt->insert_seq = 2; timeout(pcic_reset, (void *)slt, hz/4); return; case 2: /* Deassert it again */ pcic_setb(sp, PCIC_INT_GEN, PCIC_CARDRESET | PCIC_IOCARD); + if (bootverbose) + printf("int is %x stat is %x\n", + sp->getb(sp, PCIC_INT_GEN), + sp->getb(sp, PCIC_STATUS)); slt->insert_seq = 3; timeout(pcic_reset, (void *)slt, hz/4); return; case 3: /* Wait if card needs more time */ + if (bootverbose) + printf("int is %x stat is %x\n", + sp->getb(sp, PCIC_INT_GEN), + sp->getb(sp, PCIC_STATUS)); if (!sp->getb(sp, PCIC_STATUS) & PCIC_READY) { timeout(pcic_reset, (void *)slt, hz/10); return; } } slt->insert_seq = 0; if (sp->controller == PCIC_PD672X || sp->controller == PCIC_PD6710) { sp->putb(sp, PCIC_TIME_SETUP0, 0x1); sp->putb(sp, PCIC_TIME_CMD0, 0x6); sp->putb(sp, PCIC_TIME_RECOV0, 0x0); sp->putb(sp, PCIC_TIME_SETUP1, 1); sp->putb(sp, PCIC_TIME_CMD1, 0xf); sp->putb(sp, PCIC_TIME_RECOV1, 0); } selwakeup(&slt->selp); } /* * pcic_disable - Disable the slot. */ static void pcic_disable(struct slot *slt) { struct pcic_slot *sp = slt->cdata; - pcic_clrb(sp, PCIC_INT_GEN, 0xf | PCIC_CARDTYPE | PCIC_CARDRESET); + pcic_clrb(sp, PCIC_INT_GEN, PCIC_CARDTYPE | PCIC_CARDRESET); + pcic_mapirq(slt, 0); sp->putb(sp, PCIC_POWER, 0); } /* * pcic_resume - Suspend/resume support for PCIC */ static void pcic_resume(struct slot *slt) { struct pcic_slot *sp = slt->cdata; pcic_do_mgt_irq(sp, slt->irq); if (sp->controller == PCIC_PD672X) { pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER); pcic_setb(sp, PCIC_MISC2, PCIC_LPDM_EN); } if (sp->slt->state != inactive) pcic_do_stat_delta(sp); } int pcic_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct pccard_devinfo *devi = device_get_ivars(child); int err; if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) return (bus_generic_activate_resource(dev, child, type, rid, r)); switch (type) { case SYS_RES_IOPORT: { struct io_desc *ip; ip = &devi->slt->io[rid]; if (ip->flags == 0) { if (rid == 0) ip->flags = IODF_WS | IODF_16BIT | IODF_CS16; else ip->flags = devi->slt->io[0].flags; } ip->flags |= IODF_ACTIVE; ip->start = rman_get_start(r); ip->size = rman_get_end(r) - rman_get_start(r) + 1; err = pcic_io(devi->slt, rid); if (err) return (err); break; } case SYS_RES_IRQ: /* * We actually defer the activation of the IRQ resource * until the interrupt is registered to avoid stray * interrupt messages. */ break; case SYS_RES_MEMORY: { struct mem_desc *mp; if (rid >= NUM_MEM_WINDOWS) return (EINVAL); mp = &devi->slt->mem[rid]; mp->flags |= MDF_ACTIVE; mp->start = (caddr_t) rman_get_start(r); mp->size = rman_get_end(r) - rman_get_start(r) + 1; err = pcic_memory(devi->slt, rid); if (err) return (err); break; } default: break; } err = bus_generic_activate_resource(dev, child, type, rid, r); return (err); } int pcic_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct pccard_devinfo *devi = device_get_ivars(child); int err; if (dev != device_get_parent(device_get_parent(child)) || devi == NULL) return (bus_generic_deactivate_resource(dev, child, type, rid, r)); switch (type) { case SYS_RES_IOPORT: { struct io_desc *ip = &devi->slt->io[rid]; ip->flags &= ~IODF_ACTIVE; err = pcic_io(devi->slt, rid); if (err) return (err); break; } case SYS_RES_IRQ: break; case SYS_RES_MEMORY: { struct mem_desc *mp = &devi->slt->mem[rid]; mp->flags &= ~(MDF_ACTIVE | MDF_ATTR); err = pcic_memory(devi->slt, rid); if (err) return (err); break; } default: break; } err = bus_generic_deactivate_resource(dev, child, type, rid, r); return (err); } int pcic_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *intr, void *arg, void **cookiep) { struct pcic_softc *sc = device_get_softc(dev); struct pccard_devinfo *devi = device_get_ivars(child); int err; #if __FreeBSD_version >= 500000 if (sc->csc_route == pcic_iw_pci && (flags & INTR_FAST)) #else if (sc->csc_route == pcic_iw_pci && (flags & INTR_TYPE_FAST)) #endif return (EINVAL); if (((1 << rman_get_start(irq)) & PCIC_INT_MASK_ALLOWED) == 0) { device_printf(dev, "Hardware does not support irq %ld.\n", rman_get_start(irq)); return (EINVAL); } err = bus_generic_setup_intr(dev, child, irq, flags, intr, arg, cookiep); if (err == 0) pcic_mapirq(devi->slt, rman_get_start(irq)); else device_printf(dev, "Error %d irq %ld\n", err, rman_get_start(irq)); return (err); } int pcic_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { struct pccard_devinfo *devi = device_get_ivars(child); pcic_mapirq(devi->slt, 0); return (bus_generic_teardown_intr(dev, child, irq, cookie)); } int pcic_set_res_flags(device_t bus, device_t child, int restype, int rid, u_long value) { struct pccard_devinfo *devi = device_get_ivars(child); int err = 0; switch (restype) { case SYS_RES_MEMORY: { struct mem_desc *mp = &devi->slt->mem[rid]; switch (value) { case PCCARD_A_MEM_COM: mp->flags &= ~MDF_ATTR; break; case PCCARD_A_MEM_ATTR: mp->flags |= MDF_ATTR; break; case PCCARD_A_MEM_8BIT: mp->flags &= ~MDF_16BITS; break; case PCCARD_A_MEM_16BIT: mp->flags |= MDF_16BITS; break; } err = pcic_memory(devi->slt, rid); break; } default: err = EOPNOTSUPP; } return (err); } int pcic_get_res_flags(device_t bus, device_t child, int restype, int rid, u_long *value) { struct pccard_devinfo *devi = device_get_ivars(child); int err = 0; if (value == 0) return (ENOMEM); switch (restype) { case SYS_RES_IOPORT: { struct io_desc *ip = &devi->slt->io[rid]; *value = ip->flags; break; } case SYS_RES_MEMORY: { struct mem_desc *mp = &devi->slt->mem[rid]; *value = mp->flags; break; } default: err = EOPNOTSUPP; } return (err); } int pcic_set_memory_offset(device_t bus, device_t child, int rid, u_int32_t offset #if __FreeBSD_version >= 500000 ,u_int32_t *deltap #endif ) { struct pccard_devinfo *devi = device_get_ivars(child); struct mem_desc *mp = &devi->slt->mem[rid]; mp->card = offset; #if __FreeBSD_version >= 500000 if (deltap) *deltap = 0; /* XXX BAD XXX */ #endif return (pcic_memory(devi->slt, rid)); } int pcic_get_memory_offset(device_t bus, device_t child, int rid, u_int32_t *offset) { struct pccard_devinfo *devi = device_get_ivars(child); struct mem_desc *mp = &devi->slt->mem[rid]; if (offset == 0) return (ENOMEM); *offset = mp->card; return (0); } struct resource * pcic_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct pcic_softc *sc = device_get_softc(dev); /* * If we're routing via pci, we can share. */ if (sc->func_route == pcic_iw_pci && type == SYS_RES_IRQ) { if (bootverbose) device_printf(child, "Forcing IRQ to %d\n", sc->irq); start = end = sc->irq; flags |= RF_SHAREABLE; } return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } void pcic_do_stat_delta(struct pcic_slot *sp) { if ((sp->getb(sp, PCIC_STATUS) & PCIC_CD) != PCIC_CD) pccard_event(sp->slt, card_removed); else pccard_event(sp->slt, card_inserted); } /* * Wrapper function for pcicintr so that signatures match. */ void pcic_isa_intr(void *arg) { pcic_isa_intr1(arg); } /* * PCIC timer. If the controller doesn't have a free IRQ to use * or if interrupt steering doesn't work, poll the controller for * insertion/removal events. */ void pcic_timeout(void *chan) { struct pcic_softc *sc = (struct pcic_softc *) chan; if (pcic_isa_intr1(chan) != 0) { device_printf(sc->dev, "Static bug detected, ignoring hardware."); sc->slot_poll = 0; return; } sc->timeout_ch = timeout(sc->slot_poll, chan, hz/2); } /* * PCIC Interrupt handler. * Check each slot in turn, and read the card status change * register. If this is non-zero, then a change has occurred * on this card, so send an event to the main code. */ int pcic_isa_intr1(void *arg) { int slot, s; u_int8_t chg; struct pcic_softc *sc = (struct pcic_softc *) arg; struct pcic_slot *sp = &sc->slots[0]; s = splhigh(); for (slot = 0; slot < PCIC_CARD_SLOTS; slot++, sp++) { if (sp->slt == NULL) continue; if ((chg = sp->getb(sp, PCIC_STAT_CHG)) != 0) { /* * if chg is 0xff, then we know that we've hit * the famous "static bug" for some desktop * pcmcia cards. This is caused by static * discharge frying the poor card's mind and * it starts return 0xff forever. We return * an error and stop polling the card. When * we're interrupt based, we never see this. * The card just goes away silently. */ if (chg == 0xff) { splx(s); return (EIO); } if (chg & PCIC_CDTCH) pcic_do_stat_delta(sp); } } splx(s); + return (0); +} + +int +pcic_isa_mapirq(struct pcic_slot *sp, int irq) +{ + irq = host_irq_to_pcic(irq); + sp->sc->chip->func_intr_way(sp, pcic_iw_isa); + if (irq == 0) + pcic_clrb(sp, PCIC_INT_GEN, 0xF); + else + sp->putb(sp, PCIC_INT_GEN, + (sp->getb(sp, PCIC_INT_GEN) & 0xF0) | irq); return (0); } Index: stable/4/sys/pccard/pcic_isa.c =================================================================== --- stable/4/sys/pccard/pcic_isa.c (revision 83007) +++ stable/4/sys/pccard/pcic_isa.c (revision 83008) @@ -1,367 +1,398 @@ /* * Copyright (c) 2001 M. Warner Losh. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include /* Get pnp IDs */ #include #include #include #include "card_if.h" static struct isa_pnp_id pcic_ids[] = { {PCIC_PNP_ACTIONTEC, NULL}, /* AEI0218 */ {PCIC_PNP_IBM3765, NULL}, /* IBM3765 */ {PCIC_PNP_82365, NULL}, /* PNP0E00 */ {PCIC_PNP_CL_PD6720, NULL}, /* PNP0E01 */ {PCIC_PNP_VLSI_82C146, NULL}, /* PNP0E02 */ {PCIC_PNP_82365_CARDBUS, NULL}, /* PNP0E03 */ {PCIC_PNP_SCM_SWAPBOX, NULL}, /* SCM0469 */ {PCIC_NEC_PC9801_102, NULL}, /* NEC8091 */ {PCIC_NEC_PC9821RA_E01, NULL}, /* NEC8121 */ {0} }; static struct { const char *name; u_int32_t flags; } bridges[] = { { "Intel i82365SL-A/B", PCIC_AB_POWER}, { "IBM PCIC", PCIC_AB_POWER}, { "VLSI 82C146", PCIC_AB_POWER}, { "Cirrus logic 672x", PCIC_PD_POWER}, { "Cirrus logic 6710", PCIC_PD_POWER}, { "Vadem 365", PCIC_VG_POWER}, { "Vadem 465", PCIC_VG_POWER}, { "Vadem 468", PCIC_VG_POWER}, { "Vadem 469", PCIC_VG_POWER}, { "Ricoh RF5C296", PCIC_RICOH_POWER}, { "Ricoh RF5C396", PCIC_RICOH_POWER}, { "IBM KING", PCIC_KING_POWER}, { "Intel i82365SL-DF", PCIC_DF_POWER} }; +static pcic_intr_way_t pcic_isa_intr_way; +static pcic_init_t pcic_isa_init; + +struct pcic_chip pcic_isa_chip = { + pcic_isa_intr_way, + pcic_isa_intr_way, + pcic_isa_mapirq, + pcic_isa_init +}; + /* * Look for an Intel PCIC (or compatible). * For each available slot, allocate a PC-CARD slot. */ static int pcic_isa_probe(device_t dev) { int slotnum, validslots = 0; struct pcic_slot *sp; struct pcic_slot *sp0; struct pcic_slot *sp1; struct pcic_slot spsave; unsigned char c; struct resource *r; int rid; struct pcic_softc *sc; int error; /* Check isapnp ids */ error = ISA_PNP_PROBE(device_get_parent(dev), dev, pcic_ids); if (error == ENXIO) return (ENXIO); if (bus_get_resource_start(dev, SYS_RES_IOPORT, 0) == 0) bus_set_resource(dev, SYS_RES_IOPORT, 0, PCIC_PORT_0, PCIC_NPORT); rid = 0; r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); if (!r) { if (bootverbose) device_printf(dev, "Cannot get I/O range\n"); return (ENOMEM); } sc = (struct pcic_softc *) device_get_softc(dev); sc->dev = dev; sp = &sc->slots[0]; for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { /* * Initialise the PCIC slot table. */ sp->getb = pcic_getb_io; sp->putb = pcic_putb_io; sp->bst = rman_get_bustag(r); sp->bsh = rman_get_bushandle(r); sp->offset = slotnum * PCIC_SLOT_SIZE; sp->controller = -1; } /* * Prescan for the broken VLSI chips. * * According to the Linux PCMCIA code from David Hinds, * working chipsets return 0x84 from their (correct) ID ports, * while the broken ones would need to be probed at the new * offset we set after we assume it's broken. * * Note: because of this, we may incorrectly detect a single * slot vlsi chip as a i82365sl step D. I cannot find a * datasheet for the affected chip, so that's the best we can * do for now. */ sp0 = &sc->slots[0]; sp1 = &sc->slots[1]; if (sp0->getb(sp0, PCIC_ID_REV) == PCIC_VLSI82C146 && sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { spsave = *sp1; sp1->bsh += 4; sp1->offset = PCIC_SLOT_SIZE << 1; if (sp1->getb(sp1, PCIC_ID_REV) != PCIC_VLSI82C146) { *sp1 = spsave; } else { sp0->controller = PCIC_VLSI; sp1->controller = PCIC_VLSI; } } /* * Look for normal chipsets here. */ sp = &sc->slots[0]; for (slotnum = 0; slotnum < PCIC_CARD_SLOTS; slotnum++, sp++) { /* * see if there's a PCMCIA controller here * Intel PCMCIA controllers use 0x82 and 0x83 * IBM clone chips use 0x88 and 0x89, apparently */ c = sp->getb(sp, PCIC_ID_REV); sp->revision = -1; switch(c) { /* * 82365 or clones. */ case PCIC_INTEL0: case PCIC_INTEL1: sp->controller = PCIC_I82365; sp->revision = c & 1; /* * Check for Vadem chips by unlocking their extra * registers and looking for valid ID. Bit 3 in * the ID register is normally 0, except when * PCIC_VADEMREV is set. Other bridges appear * to ignore this frobbing. */ bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, 0x0E); bus_space_write_1(sp->bst, sp->bsh, PCIC_INDEX, 0x37); pcic_setb(sp, PCIC_VMISC, PCIC_VADEMREV); c = sp->getb(sp, PCIC_ID_REV); if (c & 0x08) { switch (sp->revision = c & 7) { case 1: sp->controller = PCIC_VG365; break; case 2: sp->controller = PCIC_VG465; break; case 3: sp->controller = PCIC_VG468; break; default: sp->controller = PCIC_VG469; break; } pcic_clrb(sp, PCIC_VMISC, PCIC_VADEMREV); } /* * Check for RICOH RF5C[23]96 PCMCIA Controller */ c = sp->getb(sp, PCIC_RICOH_ID); if (c == PCIC_RID_396) sp->controller = PCIC_RF5C396; else if (c == PCIC_RID_296) sp->controller = PCIC_RF5C296; break; /* * Intel i82365sl-DF step or maybe a vlsi 82c146 * we detected the vlsi case earlier, so if the controller * isn't set, we know it is a i82365sl step D. */ case PCIC_INTEL2: if (sp->controller == -1) sp->controller = PCIC_I82365SL_DF; break; case PCIC_IBM1: case PCIC_IBM2: sp->controller = PCIC_IBM; sp->revision = c & 1; break; case PCIC_IBM3: sp->controller = PCIC_IBM_KING; sp->revision = c & 1; break; default: continue; } /* * Check for Cirrus logic chips. */ sp->putb(sp, PCIC_CLCHIP, 0); c = sp->getb(sp, PCIC_CLCHIP); if ((c & PCIC_CLC_TOGGLE) == PCIC_CLC_TOGGLE) { c = sp->getb(sp, PCIC_CLCHIP); if ((c & PCIC_CLC_TOGGLE) == 0) { if (c & PCIC_CLC_DUAL) sp->controller = PCIC_PD672X; else sp->controller = PCIC_PD6710; sp->revision = 8 - ((c & 0x1F) >> 2); } } device_set_desc(dev, bridges[(int) sp->controller].name); sc->flags = bridges[(int) sp->controller].flags; /* * OK it seems we have a PCIC or lookalike. * Allocate a slot and initialise the data structures. */ validslots++; sp->slt = (struct slot *) 1; /* * Modem cards send the speaker audio (dialing noises) * to the host's speaker. Cirrus Logic PCIC chips must * enable this. There is also a Low Power Dynamic Mode bit * that claims to reduce power consumption by 30%, so * enable it and hope for the best. */ if (sp->controller == PCIC_PD672X) { pcic_setb(sp, PCIC_MISC1, PCIC_MISC1_SPEAKER); pcic_setb(sp, PCIC_MISC2, PCIC_LPDM_EN); } } bus_release_resource(dev, SYS_RES_IOPORT, rid, r); return (validslots ? 0 : ENXIO); } static int pcic_isa_attach(device_t dev) { struct pcic_softc *sc; int rid; struct resource *r; int irq = 0; int error; sc = device_get_softc(dev); rid = 0; r = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); if (!r) { pcic_dealloc(dev); return (ENXIO); } sc->iorid = rid; sc->iores = r; sc->csc_route = pcic_iw_isa; sc->func_route = pcic_iw_isa; + sc->chip = &pcic_isa_chip; rid = 0; r = NULL; r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); if (r == NULL && pcic_override_irq != 0) { irq = pcic_override_irq; r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1, RF_ACTIVE); } if (r && ((1 << (rman_get_start(r))) & PCIC_INT_MASK_ALLOWED) == 0) { device_printf(dev, "Hardware does not support irq %d, trying polling.\n", irq); bus_release_resource(dev, SYS_RES_IRQ, rid, r); irq = 0; r = NULL; } sc->irqrid = rid; sc->irqres = r; irq = 0; if (r != NULL) { error = bus_setup_intr(dev, r, INTR_TYPE_MISC, pcic_isa_intr, (void *) sc, &sc->ih); if (error) { pcic_dealloc(dev); return (error); } irq = rman_get_start(r); device_printf(dev, "management irq %d\n", irq); } sc->irq = irq; if (irq == 0) { sc->slot_poll = pcic_timeout; sc->timeout_ch = timeout(sc->slot_poll, (void *) sc, hz/2); device_printf(dev, "Polling mode\n"); } return (pcic_attach(dev)); +} + +/* + * ISA cards can only do ISA interrupts. There's no need to do + * anything but check args for sanity. + */ +static int +pcic_isa_intr_way(struct pcic_slot *sp, enum pcic_intr_way iw) +{ + if (iw != pcic_iw_isa) + return (EINVAL); + return (0); +} + +/* + * No speicial initialization is necesary for ISA cards. + */ +static void +pcic_isa_init(device_t dev) +{ } static device_method_t pcic_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pcic_isa_probe), DEVMETHOD(device_attach, pcic_isa_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_alloc_resource, pcic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, pcic_activate_resource), DEVMETHOD(bus_deactivate_resource, pcic_deactivate_resource), DEVMETHOD(bus_setup_intr, pcic_setup_intr), DEVMETHOD(bus_teardown_intr, pcic_teardown_intr), /* Card interface */ DEVMETHOD(card_set_res_flags, pcic_set_res_flags), DEVMETHOD(card_get_res_flags, pcic_get_res_flags), DEVMETHOD(card_set_memory_offset, pcic_set_memory_offset), DEVMETHOD(card_get_memory_offset, pcic_get_memory_offset), { 0, 0 } }; static driver_t pcic_driver = { "pcic", pcic_methods, sizeof(struct pcic_softc) }; DRIVER_MODULE(pcic, isa, pcic_driver, pcic_devclass, 0, 0); Index: stable/4/sys/pccard/pcic_pci.c =================================================================== --- stable/4/sys/pccard/pcic_pci.c (revision 83007) +++ stable/4/sys/pccard/pcic_pci.c (revision 83008) @@ -1,908 +1,1294 @@ /* * Copyright (c) 2001 M. Warner Losh. All Rights Reserved. * Copyright (c) 1997 Ted Faber All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Absolutely no warranty of function or purpose is made by the author * Ted Faber. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #if __FreeBSD_version < 500000 #include #include #else #include #include #endif #include #include #include #include #include #include #include "card_if.h" #define PRVERB(x) do { \ if (bootverbose) { device_printf x; } \ } while (0) static int pcic_pci_get_memory(device_t dev); SYSCTL_DECL(_hw_pcic); static int pcic_ignore_function_1 = 0; TUNABLE_INT("hw.pcic.ignore_function_1", &pcic_ignore_function_1); SYSCTL_INT(_hw_pcic, OID_AUTO, ignore_function_1, CTLFLAG_RD, &pcic_ignore_function_1, 0, "When set, driver ignores pci function 1 of the bridge"); /* * The following should be a hint, so we can do it on a per device * instance, but this is convenient. Do not set this unless pci * routing doesn't work. It is purposely vague and undocumented * at the moment. */ static int pcic_intr_path = (int)pcic_iw_pci; TUNABLE_INT("hw.pcic.intr_path", &pcic_intr_path); SYSCTL_INT(_hw_pcic, OID_AUTO, intr_path, CTLFLAG_RD, &pcic_intr_path, 0, "Which path to send the interrupts over."); static int pcic_init_routing = 0; TUNABLE_INT("hw.pcic.init_routing", &pcic_init_routing); SYSCTL_INT(_hw_pcic, OID_AUTO, init_routing, CTLFLAG_RD, &pcic_init_routing, 0, "Force the interrupt routing to be initialized on those bridges where\n\ doing so will cause probelms. Often when no interrupts appear to be routed\n\ setting this tunable to 1 will resolve the problem. PCI Cards will almost\n\ always require this, while builtin bridges need it less often"); -typedef void (*init_t)(device_t); - static void pcic_pci_cardbus_init(device_t); -static void pcic_pci_oz67xx_init(device_t); -static void pcic_pci_oz68xx_init(device_t); -static void pcic_pci_pd67xx_init(device_t); -static void pcic_pci_pd683x_init(device_t); -static void pcic_pci_ricoh_init(device_t); -static void pcic_pci_ti_init(device_t); -static void pcic_pci_topic_init(device_t); +static pcic_intr_mapirq_t pcic_pci_gen_mapirq; +static pcic_intr_way_t pcic_pci_oz67xx_func; +static pcic_intr_way_t pcic_pci_oz67xx_csc; +static pcic_init_t pcic_pci_oz67xx_init; + +static pcic_intr_way_t pcic_pci_oz68xx_func; +static pcic_intr_way_t pcic_pci_oz68xx_csc; +static pcic_init_t pcic_pci_oz68xx_init; + +static pcic_intr_way_t pcic_pci_pd67xx_func; +static pcic_intr_way_t pcic_pci_pd67xx_csc; +static pcic_init_t pcic_pci_pd67xx_init; + +static pcic_intr_way_t pcic_pci_pd68xx_func; +static pcic_intr_way_t pcic_pci_pd68xx_csc; +static pcic_init_t pcic_pci_pd68xx_init; + +static pcic_intr_way_t pcic_pci_ricoh_func; +static pcic_intr_way_t pcic_pci_ricoh_csc; +static pcic_init_t pcic_pci_ricoh_init; + +static pcic_intr_way_t pcic_pci_ti113x_func; +static pcic_intr_way_t pcic_pci_ti113x_csc; +static pcic_init_t pcic_pci_ti_init; + +static pcic_intr_way_t pcic_pci_ti12xx_func; +static pcic_intr_way_t pcic_pci_ti12xx_csc; + +static pcic_intr_way_t pcic_pci_topic_func; +static pcic_intr_way_t pcic_pci_topic_csc; +static pcic_init_t pcic_pci_topic_init; + +static struct pcic_chip pcic_pci_oz67xx_chip = { + pcic_pci_oz67xx_func, + pcic_pci_oz67xx_csc, + pcic_pci_gen_mapirq, + pcic_pci_oz67xx_init +}; + +static struct pcic_chip pcic_pci_oz68xx_chip = { + pcic_pci_oz68xx_func, + pcic_pci_oz68xx_csc, + pcic_pci_gen_mapirq, + pcic_pci_oz68xx_init +}; + +static struct pcic_chip pcic_pci_pd67xx_chip = { + pcic_pci_pd67xx_func, + pcic_pci_pd67xx_csc, + pcic_pci_gen_mapirq, + pcic_pci_pd67xx_init +}; + +static struct pcic_chip pcic_pci_pd68xx_chip = { + pcic_pci_pd68xx_func, + pcic_pci_pd68xx_csc, + pcic_pci_gen_mapirq, + pcic_pci_pd68xx_init +}; + +static struct pcic_chip pcic_pci_ricoh_chip = { + pcic_pci_ricoh_func, + pcic_pci_ricoh_csc, + pcic_pci_gen_mapirq, + pcic_pci_ricoh_init +}; + +static struct pcic_chip pcic_pci_ti113x_chip = { + pcic_pci_ti113x_func, + pcic_pci_ti113x_csc, + pcic_pci_gen_mapirq, + pcic_pci_ti_init +}; + +static struct pcic_chip pcic_pci_ti12xx_chip = { + pcic_pci_ti12xx_func, + pcic_pci_ti12xx_csc, + pcic_pci_gen_mapirq, + pcic_pci_ti_init +}; + +static struct pcic_chip pcic_pci_topic_chip = { + pcic_pci_topic_func, + pcic_pci_topic_csc, + pcic_pci_gen_mapirq, + pcic_pci_topic_init +}; + struct pcic_pci_table { u_int32_t devid; const char *descr; int type; u_int32_t flags; - init_t init; + struct pcic_chip *chip; } pcic_pci_devs[] = { { PCI_DEVICE_ID_PCIC_CLPD6729, "Cirrus Logic PD6729/6730 PC-Card Controller", - PCIC_PD672X, PCIC_PD_POWER, pcic_pci_pd67xx_init }, + PCIC_PD672X, PCIC_PD_POWER, &pcic_pci_pd67xx_chip }, { PCI_DEVICE_ID_PCIC_CLPD6832, "Cirrus Logic PD6832 PCI-CardBus Bridge", - PCIC_PD672X, PCIC_PD_POWER, pcic_pci_pd683x_init }, + PCIC_PD672X, PCIC_PD_POWER, &pcic_pci_pd68xx_chip }, { PCI_DEVICE_ID_PCIC_CLPD6833, "Cirrus Logic PD6833 PCI-CardBus Bridge", - PCIC_PD672X, PCIC_PD_POWER, pcic_pci_pd683x_init }, + PCIC_PD672X, PCIC_PD_POWER, &pcic_pci_pd68xx_chip }, { PCI_DEVICE_ID_PCIC_OZ6729, "O2micro OZ6729 PC-Card Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_oz67xx_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz67xx_chip }, { PCI_DEVICE_ID_PCIC_OZ6730, "O2micro OZ6730 PC-Card Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_oz67xx_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz67xx_chip }, { PCI_DEVICE_ID_PCIC_OZ6832, "O2micro 6832/6833 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_oz68xx_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz68xx_chip }, { PCI_DEVICE_ID_PCIC_OZ6860, "O2micro 6860/6836 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_oz68xx_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz68xx_chip }, { PCI_DEVICE_ID_PCIC_OZ6872, "O2micro 6812/6872 PCI-Cardbus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_oz68xx_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_oz68xx_chip }, { PCI_DEVICE_ID_RICOH_RL5C465, "Ricoh RL5C465 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_RICOH_POWER, pcic_pci_ricoh_init }, + PCIC_RF5C296, PCIC_RICOH_POWER, &pcic_pci_ricoh_chip }, { PCI_DEVICE_ID_RICOH_RL5C475, "Ricoh RL5C475 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_RICOH_POWER, pcic_pci_ricoh_init }, + PCIC_RF5C296, PCIC_RICOH_POWER, &pcic_pci_ricoh_chip }, { PCI_DEVICE_ID_RICOH_RL5C476, "Ricoh RL5C476 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_RICOH_POWER, pcic_pci_ricoh_init }, + PCIC_RF5C296, PCIC_RICOH_POWER, &pcic_pci_ricoh_chip }, { PCI_DEVICE_ID_RICOH_RL5C477, "Ricoh RL5C477 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_RICOH_POWER, pcic_pci_ricoh_init }, + PCIC_RF5C296, PCIC_RICOH_POWER, &pcic_pci_ricoh_chip }, { PCI_DEVICE_ID_RICOH_RL5C478, "Ricoh RL5C478 PCI-CardBus Bridge", - PCIC_RF5C296, PCIC_RICOH_POWER, pcic_pci_ricoh_init }, + PCIC_RF5C296, PCIC_RICOH_POWER, &pcic_pci_ricoh_chip }, { PCI_DEVICE_ID_PCIC_TI1031, "TI PCI-1031 PCI-PCMCIA Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti113x_chip }, { PCI_DEVICE_ID_PCIC_TI1130, "TI PCI-1130 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti113x_chip }, { PCI_DEVICE_ID_PCIC_TI1131, "TI PCI-1131 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti113x_chip }, + { PCI_DEVICE_ID_PCIC_TI1210, + "TI PCI-1210 PCI-CardBus Bridge", + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1211, "TI PCI-1211 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1220, "TI PCI-1220 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1221, "TI PCI-1221 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1225, "TI PCI-1225 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1250, "TI PCI-1250 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1251, "TI PCI-1251 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1251B, "TI PCI-1251B PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1410, "TI PCI-1410 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1420, "TI PCI-1420 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1450, "TI PCI-1450 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI1451, "TI PCI-1451 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, + { PCI_DEVICE_ID_PCIC_TI4410, + "TI PCI-4410 PCI-CardBus Bridge", + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, + { PCI_DEVICE_ID_PCIC_TI4450, + "TI PCI-4450 PCI-CardBus Bridge", + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_PCIC_TI4451, "TI PCI-4451 PCI-CardBus Bridge", - PCIC_I82365SL_DF, PCIC_DF_POWER, pcic_pci_ti_init }, + PCIC_I82365SL_DF, PCIC_DF_POWER, &pcic_pci_ti12xx_chip }, { PCI_DEVICE_ID_TOSHIBA_TOPIC95, "Toshiba ToPIC95 PCI-CardBus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_topic_init }, + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_topic_chip }, + { PCI_DEVICE_ID_TOSHIBA_TOPIC95B, + "Toshiba ToPIC95B PCI-CardBus Bridge", + PCIC_I82365, PCIC_AB_POWER, &pcic_pci_topic_chip }, { PCI_DEVICE_ID_TOSHIBA_TOPIC97, "Toshiba ToPIC97 PCI-CardBus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_topic_init }, + PCIC_I82365, PCIC_DF_POWER, &pcic_pci_topic_chip }, { PCI_DEVICE_ID_TOSHIBA_TOPIC100, "Toshiba ToPIC100 PCI-CardBus Bridge", - PCIC_I82365, PCIC_AB_POWER, pcic_pci_topic_init }, + PCIC_I82365, PCIC_DF_POWER, &pcic_pci_topic_chip }, { 0, NULL, 0, 0, NULL } }; /* * Read a register from the PCIC. */ static unsigned char pcic_pci_getb2(struct pcic_slot *sp, int reg) { return (bus_space_read_1(sp->bst, sp->bsh, sp->offset + reg)); } /* * Write a register on the PCIC */ static void pcic_pci_putb2(struct pcic_slot *sp, int reg, unsigned char val) { bus_space_write_1(sp->bst, sp->bsh, sp->offset + reg, val); } /* * lookup inside the table */ static struct pcic_pci_table * pcic_pci_lookup(u_int32_t devid, struct pcic_pci_table *tbl) { while (tbl->devid) { if (tbl->devid == devid) return (tbl); tbl++; } return (NULL); } -static void -pcic_pci_oz67xx_init(device_t dev) +/* + * The standard way to control fuction interrupts is via bit 7 in the BCR + * register. Some data sheets indicate that this is just for "intterupts" + * while others are clear that it is for function interrupts. When this + * bit is set, function interrupts are routed via the ExCA register. When + * this bit is clear, they are routed via the PCI bus, usually via the int + * in the INTPIN register. + */ +static int +pcic_pci_gen_func(struct pcic_slot *sp, enum pcic_intr_way way) { + u_int16_t bcr; + + bcr = pci_read_config(sp->sc->dev, CB_PCI_BRIDGE_CTRL, 2); + if (way == pcic_iw_pci) + bcr &= ~CB_BCR_INT_EXCA; + else + bcr |= CB_BCR_INT_EXCA; + pci_write_config(sp->sc->dev, CB_PCI_BRIDGE_CTRL, bcr, 2); + return (0); +} + + +/* + * The O2micro OZ67xx chips functions. + */ +static int +pcic_pci_oz67xx_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_oz67xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ /* - * This is almost certainly incomplete. + * Need datasheet to find out what's going on. However, the + * 68xx datasheets are so vague that it is hard to know what + * the right thing to do is. */ + /* XXX */ + return (0); +} + + +static void +pcic_pci_oz67xx_init(device_t dev) +{ device_printf(dev, "Warning: O2micro OZ67xx chips may not work\n"); pcic_pci_cardbus_init(dev); } +/* + * The O2micro OZ68xx chips functions. + */ +static int +pcic_pci_oz68xx_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_oz68xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + /* + * The 68xx datasheets make it hard to know what the right thing + * do do here is. We do hwat we knjow, which is nothing, and + * hope for the best. + */ + /* XXX */ + return (0); +} + static void pcic_pci_oz68xx_init(device_t dev) { /* * This is almost certainly incomplete. */ device_printf(dev, "Warning: O2micro OZ68xx chips may not work\n"); pcic_pci_cardbus_init(dev); } +/* + * The Cirrus Logic PD6729/30. These are weird beasts, so be careful. + */ +static int +pcic_pci_pd67xx_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + /* + * We're only supporting ISA interrupts, so do nothing for the + * moment. + */ + /* XXX */ + return (0); +} + +static int +pcic_pci_pd67xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + /* + * We're only supporting ISA interrupts, so do nothing for the + * moment. + */ + /* XXX */ + return (0); +} + + static void pcic_pci_pd67xx_init(device_t dev) { struct pcic_softc *sc = device_get_softc(dev); if (sc->csc_route == pcic_iw_pci || sc->func_route == pcic_iw_pci) device_printf(dev, "CL-PD67xx broken for PCI routing.\n"); } /* - * Set up the CL-PD6832 + * Set up the CL-PD6832 and 6833. */ -static void -pcic_pci_pd683x_init(device_t dev) +static int +pcic_pci_pd68xx_func(struct pcic_slot *sp, enum pcic_intr_way way) { - struct pcic_softc *sc = device_get_softc(dev); + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_pd68xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + struct pcic_softc *sc = sp->sc; + device_t dev = sc->dev; u_int32_t device_id = pci_get_devid(dev); u_long bcr; u_long cm1; /* - * CLPD6832 management interrupt enable bit is bit 11 (MGMT_IRQ_ENA) - * in bridge control register(offset 0x3d). - * When this bit is turned on, card status change interrupt sets - * on ISA IRQ interrupt. - * Bit 7 controls the function interrupts and appears to be stanard. + * CLPD6832 management interrupt enable bit is bit 11 + * (MGMT_IRQ_ENA) in bridge control register(offset 0x3d). + * When on, card status interrupts are ISA controlled by + * the ExCA register 0x05. * - * The CLPD6833 does things differently. It has bit 7, but not bit - * 11. Bit 11's functionality appears to be in the "Configuration + * The CLPD6833 does things differently. It doesn't have bit + * 11 in the bridge control register. Instead, this + * functionality appears to be in the "Configuration * Miscellaneous 1" register bit 1. */ - bcr = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); if (device_id == PCI_DEVICE_ID_PCIC_CLPD6832) { - if (sc->csc_route == pcic_iw_pci) + bcr = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); + if (way == pcic_iw_pci) bcr &= ~CLPD6832_BCR_MGMT_IRQ_ENA; else bcr |= CLPD6832_BCR_MGMT_IRQ_ENA; + pci_write_config(dev, CB_PCI_BRIDGE_CTRL, bcr, 2); } - if (sc->func_route == pcic_iw_pci) - bcr &= ~CB_BCR_INT_EXCA; - else - bcr |= CB_BCR_INT_EXCA; - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, bcr, 2); if (device_id == PCI_DEVICE_ID_PCIC_CLPD6833) { cm1 = pci_read_config(dev, CLPD6833_CFG_MISC_1, 4); - if (sc->csc_route == pcic_iw_pci) + if (way == pcic_iw_pci) cm1 &= ~CLPD6833_CM1_MGMT_EXCA_ENA; else cm1 |= CLPD6833_CM1_MGMT_EXCA_ENA; pci_write_config(dev, CLPD6833_CFG_MISC_1, cm1, 4); } + return (0); +} + +static void +pcic_pci_pd68xx_init(device_t dev) +{ pcic_pci_cardbus_init(dev); } +static int +pcic_pci_ricoh_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_ricoh_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + struct pcic_softc *sc = sp->sc; + device_t dev = sc->dev; + u_int16_t mcr2; + + /* + * For CSC interrupts via ISA, we can't do that exactly. + * However, we can disable INT# routing, which is usually what + * we want. This is bit 7 in the field. Note, bit 6 looks + * interesting, but appears to be unnecessary. + */ + mcr2 = pci_read_config(dev, R5C47X_MISC_CONTROL_REGISTER_2, 2); + if (way == pcic_iw_pci) + mcr2 &= ~R5C47X_MCR2_CSC_TO_INTX_DISABLE; + else + mcr2 |= R5C47X_MCR2_CSC_TO_INTX_DISABLE; + pci_write_config(dev, R5C47X_MISC_CONTROL_REGISTER_2, mcr2, 2); + + return (0); +} + static void pcic_pci_ricoh_init(device_t dev) { u_int16_t brgcntl; u_int32_t device_id = pci_get_devid(dev); switch (device_id) { case PCI_DEVICE_ID_RICOH_RL5C465: case PCI_DEVICE_ID_RICOH_RL5C466: /* * Ricoh chips have a legacy bridge enable different than most * Code cribbed from NEWBUS's bridge code since I can't find a * datasheet for them that has register definitions. */ brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); brgcntl &= ~(CB_BCR_RL_3E2_EN | CB_BCR_RL_3E0_EN); pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); break; } pcic_pci_cardbus_init(dev); } /* + * TI 1030, 1130, and 1131. + */ +static int +pcic_pci_ti113x_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + u_int32_t cardcntl; + device_t dev = sp->sc->dev; + + /* + * The TI-1130 (and 1030 and 1131) have a different interrupt + * routing control than the newer cards. assume we're not + * routing PCI, but enable as necessary when we find someone + * uses PCI interrupts. In order to get any pci interrupts, + * PCI_IRQ_ENA (bit 5) must be set. If either PCI_IREQ (bit + * 4) or PCI_CSC (bit 3) are set, then set bit 5 at the same + * time, since setting them enables the PCI interrupt routing. + * + * It also appears necessary to set the function routing bit + * in the bridge control register, but cardbus_init does that + * for us. + */ + cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); + if (way == pcic_iw_pci) + cardcntl |= TI113X_CARDCNTL_PCI_IREQ; + else + cardcntl &= ~TI113X_CARDCNTL_PCI_IREQ; + if (cardcntl & (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC)) + cardcntl &= ~TI113X_CARDCNTL_PCI_IRQ_ENA; + else + cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA; + pci_write_config(dev, TI113X_PCI_CARD_CONTROL, cardcntl, 1); + + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_ti113x_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + u_int32_t cardcntl; + device_t dev = sp->sc->dev; + + /* + * The TI-1130 (and 1030 and 1131) have a different interrupt + * routing control than the newer cards. assume we're not + * routing PCI, but enable as necessary when we find someone + * uses PCI interrupts. In order to get any pci interrupts, + * PCI_IRQ_ENA (bit 5) must be set. If either PCI_IREQ (bit + * 4) or PCI_CSC (bit 3) are set, then set bit 5 at the same + * time, since setting them enables the PCI interrupt routing. + * + * It also appears necessary to set the function routing bit + * in the bridge control register, but cardbus_init does that + * for us. + */ + cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); + if (way == pcic_iw_pci) + cardcntl |= TI113X_CARDCNTL_PCI_CSC; + else + cardcntl &= ~TI113X_CARDCNTL_PCI_CSC; + if (cardcntl & (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC)) + cardcntl &= ~TI113X_CARDCNTL_PCI_IRQ_ENA; + else + cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA; + pci_write_config(dev, TI113X_PCI_CARD_CONTROL, cardcntl, 1); + + return (0); +} + +static int +pcic_pci_ti12xx_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_ti12xx_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + /* + * Nothing happens here. The TI12xx parts will route the + * CSC interrupt via PCI if ExCA register tells it to use + * interrupt 0. And via IRQ otherwise (except for reserved + * values which may or may not do anything). + * + * We just hope for the best here that doing nothing is the + * right thing to do. + */ + return (0); +} + +/* * TI PCI-CardBus Host Adapter specific function code. * This function is separated from pcic_pci_attach(). * Takeshi Shibagaki(shiba@jp.freebsd.org). */ static void pcic_pci_ti_init(device_t dev) { u_int32_t syscntl, diagctl, devcntl, cardcntl; u_int32_t device_id = pci_get_devid(dev); struct pcic_softc *sc = device_get_softc(dev); int ti113x = (device_id == PCI_DEVICE_ID_PCIC_TI1031) || (device_id == PCI_DEVICE_ID_PCIC_TI1130) || (device_id == PCI_DEVICE_ID_PCIC_TI1131); syscntl = pci_read_config(dev, TI113X_PCI_SYSTEM_CONTROL, 4); devcntl = pci_read_config(dev, TI113X_PCI_DEVICE_CONTROL, 1); cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); if (ti113x) { device_printf(dev, "TI113X PCI Config Reg: "); - - /* - * The TI-1130 (and 1030 and 1131) have a different - * interrupt routing control than the newer cards. - * assume we're not routing PCI, but enable as necessary - * when we find someone uses PCI interrupts. In order to - * get any pci interrupts, PCI_IRQ_ENA (bit 5) must - * be set. If either PCI_IREQ (bit 4) or PCI_CSC (bit 3) - * are set, then set bit 5 at the same time, since setting - * them enables the PCI interrupt routing. - */ - cardcntl &= ~TI113X_CARDCNTL_PCI_IRQ_ENA; - if (sc->func_route == pcic_iw_pci) - cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA | - TI113X_CARDCNTL_PCI_IREQ; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_IREQ; - if (sc->csc_route == pcic_iw_pci) - cardcntl |= TI113X_CARDCNTL_PCI_IRQ_ENA | - TI113X_CARDCNTL_PCI_CSC; - else - cardcntl &= ~TI113X_CARDCNTL_PCI_CSC; - pci_write_config(dev, TI113X_PCI_CARD_CONTROL, cardcntl, 1); - cardcntl = pci_read_config(dev, TI113X_PCI_CARD_CONTROL, 1); if (syscntl & TI113X_SYSCNTL_CLKRUN_ENA) { if (syscntl & TI113X_SYSCNTL_CLKRUN_SEL) printf("[clkrun irq 12]"); else printf("[clkrun irq 10]"); } } else { device_printf(dev, "TI12XX PCI Config Reg: "); /* * Turn on async CSC interrupts. This appears to * be the default, but the old, pre pci-aware, code * did this and it appears PAO does as well. */ diagctl = pci_read_config(dev, TI12XX_PCI_DIAGNOSTIC, 1); diagctl |= TI12XX_DIAG_CSC_INTR; pci_write_config(dev, TI12XX_PCI_DIAGNOSTIC, diagctl, 1); /* * Turn off Zoom Video. Some cards have this enabled, * some do not but it causes problems when enabled. This * register doesn't exist on the 1130 (and likely the 1131, * but without a datasheet it is impossible to know). * Some 12xx chips may not have it, but setting it is * believed to be harmless. */ pci_write_config(dev, TI12XX_PCI_MULTIMEDIA_CONTROL, 0, 4); } - /* - * Default card control register setting is PCI interrupt. - * The method of this code switches PCI INT and ISA IRQ by bit - * 7 of Bridge Control Register(Offset:0x3e,0x13e). - * Takeshi Shibagaki(shiba@jp.freebsd.org) + /* + * Special code for the Orinoco cards (and a few others). They + * seem to need this special code to make them work only over pci + * interrupts. Sadly, doing this code also causes problems for + * many laptops, so we have to make it controlled by a tunable. */ if (sc->func_route == pcic_iw_pci) { if (pcic_init_routing) { devcntl &= ~TI113X_DEVCNTL_INTR_MASK; pci_write_config(dev, TI113X_PCI_DEVICE_CONTROL, devcntl, 1); devcntl = pci_read_config(dev, TI113X_PCI_DEVICE_CONTROL, 1); syscntl |= TI113X_SYSCNTL_INTRTIE; } syscntl &= ~TI113X_SYSCNTL_SMIENB; pci_write_config(dev, TI113X_PCI_SYSTEM_CONTROL, syscntl, 1); } if (cardcntl & TI113X_CARDCNTL_RING_ENA) printf("[ring enable]"); if (cardcntl & TI113X_CARDCNTL_SPKR_ENA) printf("[speaker enable]"); if (syscntl & TI113X_SYSCNTL_PWRSAVINGS) printf("[pwr save]"); switch(devcntl & TI113X_DEVCNTL_INTR_MASK){ case TI113X_DEVCNTL_INTR_ISA : printf("[CSC parallel isa irq]"); break; case TI113X_DEVCNTL_INTR_SERIAL : printf("[CSC serial isa irq]"); break; case TI113X_DEVCNTL_INTR_NONE : printf("[pci only]"); break; case TI12XX_DEVCNTL_INTR_ALLSERIAL : printf("[FUNC pci int + CSC serial isa irq]"); break; } printf("\n"); pcic_pci_cardbus_init(dev); } +/* + * Code for TOPIC chips + */ +static int +pcic_pci_topic_func(struct pcic_slot *sp, enum pcic_intr_way way) +{ + return (pcic_pci_gen_func(sp, way)); +} + +static int +pcic_pci_topic_csc(struct pcic_slot *sp, enum pcic_intr_way way) +{ + device_t dev = sp->sc->dev; + u_int32_t icr; + + icr = pci_read_config(dev, TOPIC_INTERRUPT_CONTROL, 1); + if (way == pcic_iw_pci) + icr |= TOPIC_ICR_INTA; + else + icr &= ~TOPIC_ICR_INTA; + pci_write_config(dev, TOPIC_INTERRUPT_CONTROL, icr, 1); + + return (0); +} + static void pcic_pci_topic_init(device_t dev) { - /* - * This is almost certainly incomplete. - */ - device_printf(dev, "Warning: Toshiba ToPIC chips may not work\n"); + struct pcic_softc *sc = device_get_softc(dev); + u_int32_t device_id; + + device_id = pci_get_devid(dev); + if (device_id == PCI_DEVICE_ID_TOSHIBA_TOPIC100 || + device_id == PCI_DEVICE_ID_TOSHIBA_TOPIC97) { + /* + * We need to enable voltage sense and 3V cards explicitly + * in the bridge. The datasheets I have for both the + * ToPIC 97 and 100 both lists these ports. Without + * datasheets for the ToPIC95s, I can't tell if we need + * to do it there or not. + */ + pcic_setb(&sc->slots[0], PCIC_TOPIC_FCR, + PCIC_FCR_3V_EN | PCIC_FCR_VS_EN); + } pcic_pci_cardbus_init(dev); } static void pcic_pci_cardbus_init(device_t dev) { + struct pcic_softc *sc = device_get_softc(dev); u_int16_t brgcntl; int unit; - struct pcic_softc *sc = device_get_softc(dev); unit = device_get_unit(dev); - if (sc->func_route == pcic_iw_pci) { - /* Use INTA for routing function interrupts via pci bus */ - brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); - brgcntl &= ~CB_BCR_INT_EXCA; - brgcntl |= CB_BCR_WRITE_POST_EN | CB_BCR_MASTER_ABORT; - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); - } else { - /* Output ISA IRQ indicated in ExCA register(0x03). */ - brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); - brgcntl |= CB_BCR_INT_EXCA; - pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); - } + brgcntl = pci_read_config(dev, CB_PCI_BRIDGE_CTRL, 2); + brgcntl |= CB_BCR_WRITE_POST_EN | CB_BCR_MASTER_ABORT; + pci_write_config(dev, CB_PCI_BRIDGE_CTRL, brgcntl, 2); /* Turn off legacy address */ pci_write_config(dev, CB_PCI_LEGACY16_IOADDR, 0, 2); /* - * Write zeros into the remaining BARs. This seems to turn off - * the pci configuration of these things and make the cardbus - * bridge use the values for memory programmed into the pcic - * registers. + * Write zeros into the remaining memory I/O windows. This + * seems to turn off the pci configuration of these things and + * make the cardbus bridge use the values for memory + * programmed into the pcic registers. */ pci_write_config(dev, CB_PCI_MEMBASE0, 0, 4); pci_write_config(dev, CB_PCI_MEMLIMIT0, 0, 4); pci_write_config(dev, CB_PCI_MEMBASE1, 0, 4); pci_write_config(dev, CB_PCI_MEMLIMIT1, 0, 4); pci_write_config(dev, CB_PCI_IOBASE0, 0, 4); pci_write_config(dev, CB_PCI_IOLIMIT0, 0, 4); pci_write_config(dev, CB_PCI_IOBASE1, 0, 4); pci_write_config(dev, CB_PCI_IOLIMIT1, 0, 4); + /* + * Force the function interrupts to be pulse rather than + * edge triggered. + */ + sc->chip->func_intr_way(&sc->slots[0], pcic_iw_isa); + sc->chip->csc_intr_way(&sc->slots[0], sc->csc_route); + return; } static const char * pcic_pci_cardtype(u_int32_t stat) { if (stat & CB_SS_NOTCARD) return ("Cardtype unrecognized by bridge"); if ((stat & (CB_SS_16BIT | CB_SS_CB)) == (CB_SS_16BIT | CB_SS_CB)) return ("16-bit and 32-bit (can't happen)"); if (stat & CB_SS_16BIT) return ("16-bit pccard"); if (stat & CB_SS_CB) return ("32-bit cardbus"); return ("none (can't happen)"); } /* * Card insertion and removal code. The insertion events need to be * debounced so that the noisy insertion/removal events don't result * in the hardware being initialized many times, only to be torn down * as well. This may also cause races with pccardd. Instead, we wait * for the insertion signal to be stable for 0.5 seconds before we declare * it to be a real insertion event. Removal is done right away. * * Note: We only handle the card detect change events. We don't handle * power events and status change events. */ static void pcic_cd_insert(void *arg) { struct pcic_softc *sc = (struct pcic_softc *) arg; struct pcic_slot *sp = &sc->slots[0]; u_int32_t stat; sc->cd_pending = 0; stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); /* Just return if the interrupt handler missed a remove transition. */ if ((stat & CB_SS_CD) != 0) return; sc->cd_present = 1; if ((stat & CB_SS_16BIT) == 0) device_printf(sp->sc->dev, "Card type %s is unsupported\n", pcic_pci_cardtype(stat)); else pccard_event(sp->slt, card_inserted); } static void pcic_pci_intr(void *arg) { struct pcic_softc *sc = (struct pcic_softc *) arg; struct pcic_slot *sp = &sc->slots[0]; u_int32_t event; u_int32_t stat; int present; event = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_EVENT); if (event != 0) { stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); if (bootverbose) device_printf(sc->dev, "Event mask 0x%x stat 0x%x\n", event, stat); present = (stat & CB_SS_CD) == 0; if (present != sc->cd_present) { if (sc->cd_pending) { untimeout(pcic_cd_insert, arg, sc->cd_ch); sc->cd_pending = 0; } /* Delay insert events to debounce noisy signals. */ if (present) { sc->cd_ch = timeout(pcic_cd_insert, arg, hz/2); sc->cd_pending = 1; } else { sc->cd_present = 0; - sp->intr = NULL; pccard_event(sp->slt, card_removed); } } + if (stat & CB_SS_BADVCC) + device_printf(sc->dev, "BAD Vcc request"); + /* Ack the interrupt */ bus_space_write_4(sp->bst, sp->bsh, 0, event); } /* * Some TI chips also require us to read the old ExCA register for * card status change when we route CSC via PCI! So, we go ahead * and read it to clear the bits. Maybe we should check the status * ala the ISA interrupt handler, but those changes should be caught * in the CD change. */ sp->getb(sp, PCIC_STAT_CHG); } /* * Return the ID string for the controller if the vendor/product id * matches, NULL otherwise. */ static int pcic_pci_probe(device_t dev) { u_int8_t subclass; u_int8_t progif; const char *desc; u_int32_t device_id; struct pcic_pci_table *itm; struct resource *res; int rid; device_id = pci_get_devid(dev); desc = NULL; itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); if (pcic_ignore_function_1 && pci_get_function(dev) == 1) { if (itm != NULL) PRVERB((dev, "Ignoring function 1\n")); return (ENXIO); } if (itm != NULL) desc = itm->descr; if (desc == NULL && pci_get_class(dev) == PCIC_BRIDGE) { subclass = pci_get_subclass(dev); progif = pci_get_progif(dev); if (subclass == PCIS_BRIDGE_PCMCIA && progif == 0) desc = "Generic PCI-PCMCIA Bridge"; if (subclass == PCIS_BRIDGE_CARDBUS && progif == 0) desc = "YENTA PCI-CARDBUS Bridge"; if (bootverbose && desc) printf("Found unknown %s devid 0x%x\n", desc, device_id); } if (desc == NULL) return (ENXIO); device_set_desc(dev, desc); /* * Take us out of power down mode, if necessary. It also * appears that even reading the power register is enough on * some systems to cause correct behavior. */ if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Reset the power state. */ device_printf(dev, "chip is in D%d power mode " "-- setting to D0\n", pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); } /* * Allocated/deallocate interrupt. This forces the PCI BIOS or * other MD method to route the interrupts to this card. * This so we get the interrupt number in the probe message. * We only need to route interrupts when we're doing pci * parallel interrupt routing. + * + * Note: The CLPD6729 is a special case. See its init function + * for an explaination of ISA vs PCI interrupts. */ - if (pcic_intr_path == pcic_iw_pci) { + if (pcic_intr_path == pcic_iw_pci && + device_id != PCI_DEVICE_ID_PCIC_CLPD6729) { rid = 0; +#ifdef __i386__ + /* + * IRQ 0 is invalid on x86, but not other platforms. + * If we have irq 0, then write 255 to force a new, non- + * bogus one to be assigned. + */ + if (pci_get_irq(dev) == 0) { + pci_set_irq(dev, 255); + pci_write_config(dev, PCIR_INTLINE, 255, 1); + } +#endif res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); if (res) bus_release_resource(dev, SYS_RES_IRQ, rid, res); } return (0); } static void pcic_pci_shutdown(device_t dev) { struct pcic_softc *sc; struct pcic_slot *sp; sc = (struct pcic_softc *) device_get_softc(dev); sp = &sc->slots[0]; /* + * Make the chips use ISA again. + */ + sc->chip->func_intr_way(&sc->slots[0], pcic_iw_isa); + sc->chip->csc_intr_way(&sc->slots[0], pcic_iw_isa); + + /* * Turn off the power to the slot in an attempt to * keep the system from hanging on reboot. We also turn off * card interrupts in an attempt to control interrupt storms. * on some (all?) this has the effect of also turning off * card status change interrupts. A side effect of writing 0 * to INT_GEN is that the card is placed into "reset" mode * where nothing happens until it is taken out of "reset" * mode. + * + * Also, turn off the generation of status interrupts too. */ sp->putb(sp, PCIC_INT_GEN, 0); + sp->putb(sp, PCIC_STAT_INT, 0); sp->putb(sp, PCIC_POWER, 0); /* * Writing to INT_GEN can cause an interrupt, so we blindly * ack all possible interrupts here. Reading the stat change * shouldn't be necessary, but some TI chipsets need it in the * normal course of operations, so we do it here too. We can't * lose any interrupts after this point, so go ahead and ack * everything. The bits in INT_GEN clear upon reading them. + * We also set the interrupt mask to 0, in an effort to avoid + * getting further interrupts. */ - bus_space_write_4(sp->bst, sp->bsh, 0, 0xffffffff); + bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_MASK, 0); + bus_space_write_4(sp->bst, sp->bsh, CB_SOCKET_EVENT, 0xffffffff); sp->getb(sp, PCIC_STAT_CHG); } /* * General PCI based card dispatch routine. Right now * it only understands the Ricoh, CL-PD6832 and TI parts. It does * try to do generic things with other parts. */ static int pcic_pci_attach(device_t dev) { u_int32_t device_id = pci_get_devid(dev); u_long command; struct pcic_slot *sp; struct pcic_softc *sc; u_int32_t sockbase; + u_int32_t stat; struct pcic_pci_table *itm; int rid; + int i; struct resource *r = NULL; int error; u_long irq = 0; driver_intr_t *intr = NULL; /* * In sys/pci/pcireg.h, PCIR_COMMAND must be separated * PCI_COMMAND_REG(0x04) and PCI_STATUS_REG(0x06). * Takeshi Shibagaki(shiba@jp.freebsd.org). */ command = pci_read_config(dev, PCIR_COMMAND, 4); command |= PCIM_CMD_PORTEN | PCIM_CMD_MEMEN; pci_write_config(dev, PCIR_COMMAND, command, 4); sc = (struct pcic_softc *) device_get_softc(dev); sp = &sc->slots[0]; sp->sc = sc; sockbase = pci_read_config(dev, 0x10, 4); if (sockbase & 0x1) { sc->iorid = CB_PCI_SOCKET_BASE; sc->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iorid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (sc->iores == NULL) return (ENOMEM); - sp->getb = pcic_getb_io; - sp->putb = pcic_putb_io; sp->bst = rman_get_bustag(sc->iores); sp->bsh = rman_get_bushandle(sc->iores); - sp->offset = pci_get_function(dev) * PCIC_SLOT_SIZE; sp->controller = PCIC_PD672X; sp->revision = 0; sc->flags = PCIC_PD_POWER; itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); + for (i = 0; i < 2; i++) { + sp[i].getb = pcic_getb_io; + sp[i].putb = pcic_putb_io; + sp[i].offset = i * PCIC_SLOT_SIZE; + sp[i].controller = PCIC_PD672X; + printf("ID is 0x%x\n", sp[i].getb(sp, PCIC_ID_REV)); + if ((sp[i].getb(sp, PCIC_ID_REV) & 0xc0) == 0x80) + sp[i].slt = (struct slot *) 1; + } + /* + * We only support isa at this time. These cards can be + * wired up as either ISA cards *OR* PCI cards (well, weird + * hybrids are possible, but not seen in the wild). Since it + * is an either or thing, we assume ISA since all laptops that + * we supported in 4.3 and earlier work. + */ + sc->csc_route = pcic_iw_isa; + sc->func_route = pcic_iw_isa; + if (itm) + sc->flags = itm->flags; } else { sc->memrid = CB_PCI_SOCKET_BASE; sc->memres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memrid, 0, ~0, 1, RF_ACTIVE); if (sc->memres == NULL && pcic_pci_get_memory(dev) != 0) return (ENOMEM); sp->getb = pcic_pci_getb2; sp->putb = pcic_pci_putb2; sp->offset = CB_EXCA_OFFSET; sp->bst = rman_get_bustag(sc->memres); sp->bsh = rman_get_bushandle(sc->memres); itm = pcic_pci_lookup(device_id, &pcic_pci_devs[0]); if (itm != NULL) { sp->controller = itm->type; sp->revision = 0; - sc->flags = itm->flags; + sc->flags = itm->flags; } else { /* By default, assume we're a D step compatible */ sp->controller = PCIC_I82365SL_DF; sp->revision = 0; sc->flags = PCIC_DF_POWER; } + /* sc->flags = PCIC_CARDBUS_POWER; */ + sp->slt = (struct slot *) 1; + sc->csc_route = pcic_intr_path; + sc->func_route = pcic_intr_path; + stat = bus_space_read_4(sp->bst, sp->bsh, CB_SOCKET_STATE); + sc->cd_present = (stat & CB_SS_CD) == 0; } sc->dev = dev; - sc->csc_route = pcic_intr_path; - sc->func_route = pcic_intr_path; - sp->slt = (struct slot *) 1; + sc->chip = itm->chip; if (sc->csc_route == pcic_iw_pci) { rid = 0; r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); if (r == NULL) { sc->csc_route = pcic_iw_isa; sc->func_route = pcic_iw_isa; device_printf(dev, "No PCI interrupt routed, trying ISA.\n"); } else { intr = pcic_pci_intr; irq = rman_get_start(r); } } if (sc->csc_route == pcic_iw_isa) { rid = 0; irq = pcic_override_irq; if (irq != 0) { r = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1, RF_ACTIVE); if (r == NULL) { device_printf(dev, "Can't route ISA CSC interrupt.\n"); pcic_dealloc(dev); return (ENXIO); } + device_printf(dev, + "Management interrupt on ISA IRQ %ld\n", irq); intr = pcic_isa_intr; } else { sc->slot_poll = pcic_timeout; sc->timeout_ch = timeout(sc->slot_poll, sc, hz/2); device_printf(dev, "Polling mode\n"); intr = NULL; } } /* * Initialize AFTER we figure out what kind of interrupt we're * going to be using, if any. */ - if (itm && itm->init) - itm->init(dev); - else - pcic_pci_cardbus_init(dev); + if (!sc->chip) + panic("Bug: sc->chip not set!\n"); + sc->chip->init(dev); /* * Now install the interrupt handler, if necessary. */ sc->irqrid = rid; sc->irqres = r; sc->irq = irq; if (intr) { error = bus_setup_intr(dev, r, INTR_TYPE_AV, intr, sc, &sc->ih); if (error) { pcic_dealloc(dev); return (error); } } - return (pcic_attach(dev)); } static int pcic_pci_detach(device_t dev) { return (EBUSY); /* Can't detach this device */ } /* * The PCI bus should do this for us. However, it doesn't quite yet, so * we cope by doing it ourselves. If it ever does, this code can go quietly * into that good night. */ static int pcic_pci_get_memory(device_t dev) { struct pcic_softc *sc; u_int32_t sockbase; sc = (struct pcic_softc *) device_get_softc(dev); sockbase = pci_read_config(dev, sc->memrid, 4); if (sockbase >= 0x100000 && sockbase < 0xfffffff0) { device_printf(dev, "Could not map register memory\n"); return (ENOMEM); } pci_write_config(dev, sc->memrid, 0xffffffff, 4); sockbase = pci_read_config(dev, sc->memrid, 4); sockbase = (sockbase & 0xfffffff0) & -(sockbase & 0xfffffff0); #define CARDBUS_SYS_RES_MEMORY_START 0x44000000 #define CARDBUS_SYS_RES_MEMORY_END 0xFFFFFFFF sc->memres = bus_generic_alloc_resource(device_get_parent(dev), dev, SYS_RES_MEMORY, &sc->memrid, CARDBUS_SYS_RES_MEMORY_START, CARDBUS_SYS_RES_MEMORY_END, sockbase, RF_ACTIVE | rman_make_alignment_flags(sockbase)); if (sc->memres == NULL) { device_printf(dev, "Could not grab register memory\n"); return (ENOMEM); } sockbase = rman_get_start(sc->memres); pci_write_config(dev, sc->memrid, sockbase, 4); device_printf(dev, "PCI Memory allocated: 0x%08x\n", sockbase); return (0); +} + +static int +pcic_pci_gen_mapirq(struct pcic_slot *sp, int irq) +{ + /* + * If we're doing ISA interrupt routing, then just go to the + * generic ISA routine. Also, irq 0 means turn off the interrupts + * at the bridge. We do this by making the interrupts edge + * triggered rather then level. + */ + if (sp->sc->func_route == pcic_iw_isa || irq == 0) + return (pcic_isa_mapirq(sp, irq)); + + return (sp->sc->chip->func_intr_way(sp, pcic_iw_pci)); } static device_method_t pcic_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, pcic_pci_probe), DEVMETHOD(device_attach, pcic_pci_attach), DEVMETHOD(device_detach, pcic_pci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, pcic_pci_shutdown), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_alloc_resource, pcic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, pcic_activate_resource), DEVMETHOD(bus_deactivate_resource, pcic_deactivate_resource), DEVMETHOD(bus_setup_intr, pcic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), /* Card interface */ DEVMETHOD(card_set_res_flags, pcic_set_res_flags), DEVMETHOD(card_get_res_flags, pcic_get_res_flags), DEVMETHOD(card_set_memory_offset, pcic_set_memory_offset), DEVMETHOD(card_get_memory_offset, pcic_get_memory_offset), {0, 0} }; static driver_t pcic_pci_driver = { "pcic", pcic_pci_methods, sizeof(struct pcic_softc) }; DRIVER_MODULE(pcic, pci, pcic_pci_driver, pcic_devclass, 0, 0); Index: stable/4/sys/pccard/pcic_pci.h =================================================================== --- stable/4/sys/pccard/pcic_pci.h (revision 83007) +++ stable/4/sys/pccard/pcic_pci.h (revision 83008) @@ -1,168 +1,196 @@ /* * Copyright (c) 2001 M. Warner Losh. All rights reserved. * Copyright (c) 1997 Ted Faber. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Absolutely no warranty of function or purpose is made by the author * Ted Faber. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* Share the devid database with NEWCARD */ #include /* CL-PD683x CardBus defines */ #define CLPD6833_CFG_MISC_1 0x98 /* Configuration constants */ #define CLPD6832_BCR_MGMT_IRQ_ENA 0x0800 #define CLPD6833_CM1_MGMT_EXCA_ENA 0x0001 /* Set ExCA, Clr PCI */ /* End of CL-PD6832 defines */ /* Texas Instruments PCI-1130/1131 CardBus Controller */ #define TI113X_PCI_SYSTEM_CONTROL 0x80 /* System Control */ #define TI12XX_PCI_MULTIMEDIA_CONTROL 0x84 /* Zoom Video */ #define TI113X_PCI_RETRY_STATUS 0x90 /* Retry Status */ #define TI113X_PCI_CARD_CONTROL 0x91 /* Card Control */ #define TI113X_PCI_DEVICE_CONTROL 0x92 /* Device Control */ #define TI113X_PCI_BUFFER_CONTROL 0x93 /* Buffer Control */ #define TI12XX_PCI_DIAGNOSTIC 0x93 /* Diagnostic register */ #define TI113X_PCI_SOCKET_DMA0 0x94 /* Socket DMA Register 0 */ #define TI113X_PCI_SOCKET_DMA1 0x98 /* Socket DMA Register 1 */ /* Card control register (TI113X_SYSTEM_CONTROL == 0x80) */ #define TI113X_SYSCNTL_INTRTIE 0x20000000u #define TI113X_SYSCNTL_SMIENB 0x00800000u #define TI113X_SYSCNTL_VCC_PROTECT 0x00200000u #define TI113X_SYSCNTL_CLKRUN_SEL 0x00000080u #define TI113X_SYSCNTL_PWRSAVINGS 0x00000040u #define TI113X_SYSCNTL_KEEP_CLK 0x00000002u #define TI113X_SYSCNTL_CLKRUN_ENA 0x00000001u /* Card control register (TI113X_CARD_CONTROL == 0x91) */ #define TI113X_CARDCNTL_RING_ENA 0x80u #define TI113X_CARDCNTL_ZOOM_VIDEO 0x40u #define TI113X_CARDCNTL_PCI_IRQ_ENA 0x20u #define TI113X_CARDCNTL_PCI_IREQ 0x10u #define TI113X_CARDCNTL_PCI_CSC 0x08u #define TI113X_CARDCNTL_MASK (TI113X_CARDCNTL_PCI_IRQ_ENA | TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC) #define TI113X_FUNC0_VALID TI113X_CARDCNTL_MASK #define TI113X_FUNC1_VALID (TI113X_CARDCNTL_PCI_IREQ | TI113X_CARDCNTL_PCI_CSC) /* Reserved bit 0x04u */ #define TI113X_CARDCNTL_SPKR_ENA 0x02u #define TI113X_CARDCNTL_INT 0x01u /* Device control register (TI113X_DEVICE_CONTROL == 0x92) */ #define TI113X_DEVCNTL_5V_SOCKET 0x40u #define TI113X_DEVCNTL_3V_SOCKET 0x20u #define TI113X_DEVCNTL_INTR_MASK 0x06u #define TI113X_DEVCNTL_INTR_NONE 0x00u #define TI113X_DEVCNTL_INTR_ISA 0x02u #define TI113X_DEVCNTL_INTR_SERIAL 0x04u /* TI12XX specific code */ #define TI12XX_DEVCNTL_INTR_ALLSERIAL 0x06u /* Diagnostic register (misnamed) TI12XX_PCI_DIAGNOSTIC == 0x93 */ #define TI12XX_DIAG_CSC_INTR 0x20 /* see datasheet */ /* Texas Instruments PCI-1130/1131 CardBus Controller */ #define TI113X_ExCA_IO_OFFSET0 0x36 /* Offset of I/O window */ #define TI113X_ExCA_IO_OFFSET1 0x38 /* Offset of I/O window */ #define TI113X_ExCA_MEM_WINDOW_PAGE 0x3C /* Memory Window Page */ +/* + * Ricoh R5C47[5678] parts have these registers. Maybe the 46x also use + * them, but I can't find out for sure without datasheets... + */ +#define R5C47X_MISC_CONTROL_REGISTER_2 0xa0 +#define R5C47X_MCR2_CSC_TO_INTX_DISABLE 0x0010 /* Bit 7 */ + +/* + * ToPIC specific stuff. + */ +#define TOPIC_INTERRUPT_CONTROL 0xa1 +#define TOPIC_ICR_INTA 0x1 + /* sanpei */ /* For Bridge Control register (CB_PCI_BRIDGE_CTRL) */ #define CB_BCR_MASTER_ABORT 0x0020 #define CB_BCR_CB_RESET 0x0040 #define CB_BCR_INT_EXCA 0x0080 #define CB_BCR_WRITE_POST_EN 0x0400 /* additional bits for Ricoh's cardbus products */ #define CB_BCR_RL_3E0_EN 0x0800 #define CB_BCR_RL_3E2_EN 0x1000 /* PCI Configuration Registers (common) */ #define CB_PCI_VENDOR_ID 0x00 /* vendor ID */ #define CB_PCI_DEVICE_ID 0x02 /* device ID */ #define CB_PCI_COMMAND 0x04 /* PCI command */ #define CB_PCI_STATUS 0x06 /* PCI status */ #define CB_PCI_REVISION_ID 0x08 /* PCI revision ID */ #define CB_PCI_CLASS 0x09 /* PCI class code */ #define CB_PCI_CACHE_LINE_SIZE 0x0c /* Cache line size */ #define CB_PCI_LATENCY 0x0d /* PCI latency timer */ #define CB_PCI_HEADER_TYPE 0x0e /* PCI header type */ #define CB_PCI_BIST 0x0f /* Built-in self test */ #define CB_PCI_SOCKET_BASE 0x10 /* Socket/ExCA base address reg. */ #define CB_PCI_CB_STATUS 0x16 /* CardBus Status */ #define CB_PCI_PCI_BUS_NUM 0x18 /* PCI bus number */ #define CB_PCI_CB_BUS_NUM 0x19 /* CardBus bus number */ #define CB_PCI_CB_SUB_BUS_NUM 0x1A /* Subordinate CardBus bus number */ #define CB_PCI_CB_LATENCY 0x1A /* CardBus latency timer */ #define CB_PCI_MEMBASE0 0x1C /* Memory base register 0 */ #define CB_PCI_MEMLIMIT0 0x20 /* Memory limit register 0 */ #define CB_PCI_MEMBASE1 0x24 /* Memory base register 1 */ #define CB_PCI_MEMLIMIT1 0x28 /* Memory limit register 1 */ #define CB_PCI_IOBASE0 0x2C /* I/O base register 0 */ #define CB_PCI_IOLIMIT0 0x30 /* I/O limit register 0 */ #define CB_PCI_IOBASE1 0x34 /* I/O base register 1 */ #define CB_PCI_IOLIMIT1 0x38 /* I/O limit register 1 */ #define CB_PCI_INT_LINE 0x3C /* Interrupt Line */ #define CB_PCI_INT_PIN 0x3D /* Interrupt Pin */ #define CB_PCI_BRIDGE_CTRL 0x3E /* Bridge Control */ #define CB_PCI_SUBSYS_VENDOR_ID 0x40 /* Subsystem Vendor ID */ #define CB_PCI_SUBSYS_ID 0x42 /* Subsystem ID */ #define CB_PCI_LEGACY16_IOADDR 0x44 /* Legacy 16bit I/O address */ #define CB_PCI_LEGACY16_IOENABLE 0x01 /* Enable Legacy 16bit I/O address */ /* PCI Memory register offsets for YENTA devices */ #define CB_SOCKET_EVENT 0x00 #define CB_SOCKET_MASK 0x04 #define CB_SOCKET_STATE 0x08 #define CB_SOCKET_FORCE 0x0c -#define CB_SOCKET_CONTROL 0x10 -#define CB_SOCKET_POWER 0x14 +#define CB_SOCKET_POWER 0x10 #define CB_EXCA_OFFSET 0x800 /* Offset for ExCA registers */ #define CB_SE_CD 0x6 /* Socket Event Card detect */ +#define CB_SE_POWER 0x8 + #define CB_SM_CD 0x6 /* Socket MASK Card detect */ +#define CB_SM_POWER 0x8 #define CB_SS_CARDSTS 0x00000001 /* Card Status Change */ #define CB_SS_CD1 0x00000002 /* Card Detect 1 */ #define CB_SS_CD2 0x00000004 /* Card Detect 2 */ #define CB_SS_CD 0x00000006 /* Card Detect all */ #define CB_SS_PWRCYCLE 0x00000008 /* Power Cycle */ #define CB_SS_16BIT 0x00000010 /* 16-bit Card */ #define CB_SS_CB 0x00000020 /* Cardbus Card */ #define CB_SS_IREQ 0x00000040 /* Ready */ #define CB_SS_NOTCARD 0x00000080 /* Unrecognized Card */ #define CB_SS_DATALOST 0x00000100 /* Data Lost */ #define CB_SS_BADVCC 0x00000200 /* Bad VccRequest */ #define CB_SS_5VCARD 0x00000400 /* 5 V Card */ #define CB_SS_3VCARD 0x00000800 /* 3.3 V Card */ #define CB_SS_XVCARD 0x00001000 /* X.X V Card */ #define CB_SS_YVCARD 0x00002000 /* Y.Y V Card */ #define CB_SS_5VSOCK 0x10000000 /* 5 V Socket */ #define CB_SS_3VSOCK 0x20000000 /* 3.3 V Socket */ #define CB_SS_XVSOCK 0x40000000 /* X.X V Socket */ #define CB_SS_YVSOCK 0x80000000 /* Y.Y V Socket */ + +#define CB_SP_CLKSTOP 0x80 /* Cardbus clock stop protocol */ +#define CB_SP_VCC_0V 0x00 +#define CB_SP_VCC_5V 0x20 +#define CB_SP_VCC_3V 0x30 +#define CB_SP_VCC_XV 0x40 +#define CB_SP_VCC_YV 0x50 +#define CB_SP_VPP_0V 0x00 +#define CB_SP_VPP_12V 0x01 +#define CB_SP_VPP_5V 0x02 +#define CB_SP_VPP_3V 0x03 +#define CB_SP_VPP_XV 0x04 +#define CB_SP_VPP_YV 0x05 Index: stable/4/sys/pccard/pcicvar.h =================================================================== --- stable/4/sys/pccard/pcicvar.h (revision 83007) +++ stable/4/sys/pccard/pcicvar.h (revision 83008) @@ -1,109 +1,123 @@ /* * Copyright (c) 2001 M. Warner Losh. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * Per-slot data table. */ struct pcic_slot { int offset; /* Offset value for index */ char controller; /* Device type */ char revision; /* Device Revision */ struct slot *slt; /* Back ptr to slot */ struct pcic_softc *sc; /* Back pointer to softc */ u_int8_t (*getb)(struct pcic_slot *, int); void (*putb)(struct pcic_slot *, int, u_int8_t); bus_space_tag_t bst; bus_space_handle_t bsh; - driver_intr_t *intr; - void *argp; }; enum pcic_intr_way { pcic_iw_isa = 1, pcic_iw_pci = 2 }; struct pcic_softc { u_int32_t slotmask;/* Mask of valid slots */ u_int32_t flags; /* Interesting flags */ -#define PCIC_AB_POWER 0x00000001 /* Use old A/B step power */ -#define PCIC_DF_POWER 0x00000002 /* Uses DF step regs */ -#define PCIC_PD_POWER 0x00000004 /* Uses CL-PD regs */ -#define PCIC_VG_POWER 0x00000008 /* Uses VG power regs */ -#define PCIC_KING_POWER 0x00000010 /* Uses IBM KING regs */ -#define PCIC_RICOH_POWER 0x0000020 /* Uses the ricoh power regs */ +#define PCIC_AB_POWER 0x00000001 /* Use old A/B step power */ +#define PCIC_DF_POWER 0x00000002 /* Uses DF step regs */ +#define PCIC_PD_POWER 0x00000004 /* Uses CL-PD regs */ +#define PCIC_VG_POWER 0x00000008 /* Uses VG power regs */ +#define PCIC_KING_POWER 0x00000010 /* Uses IBM KING regs */ +#define PCIC_RICOH_POWER 0x00000020 /* Uses the ricoh power regs */ +#define PCIC_CARDBUS_POWER 0x00000040 /* Cardbus power regs */ + enum pcic_intr_way csc_route; /* How to route csc interrupts */ enum pcic_intr_way func_route; /* How to route function ints */ int iorid; /* Rid of I/O region */ struct resource *iores; /* resource for I/O region */ int memrid; /* Memory rid */ struct resource *memres;/* Resource for memory mapped regs */ int irqrid; /* Irq rid */ struct resource *irqres;/* Irq resource */ void *ih; /* Our interrupt handler. */ int irq; device_t dev; /* Our device */ void (*slot_poll)(void *); struct callout_handle timeout_ch; struct pcic_slot slots[PCIC_MAX_SLOTS]; int cd_pending; /* debounce timeout active */ int cd_present; /* debounced card-present state */ struct callout_handle cd_ch; /* handle for pcic_cd_insert */ + struct pcic_chip *chip; }; +typedef int (pcic_intr_way_t)(struct pcic_slot *, enum pcic_intr_way); +typedef int (pcic_intr_mapirq_t)(struct pcic_slot *, int irq); +typedef void (pcic_init_t)(device_t); + +struct pcic_chip +{ + pcic_intr_way_t *func_intr_way; + pcic_intr_way_t *csc_intr_way; + pcic_intr_mapirq_t *map_irq; + pcic_init_t *init; +}; + extern devclass_t pcic_devclass; extern int pcic_override_irq; int pcic_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r); struct resource *pcic_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags); int pcic_attach(device_t dev); void pcic_clrb(struct pcic_slot *sp, int reg, unsigned char mask); int pcic_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *r); void pcic_dealloc(device_t dev); void pcic_do_stat_delta(struct pcic_slot *sp); int pcic_get_memory_offset(device_t bus, device_t child, int rid, u_int32_t *offset); int pcic_get_res_flags(device_t bus, device_t child, int restype, int rid, u_long *value); unsigned char pcic_getb_io(struct pcic_slot *sp, int reg); driver_intr_t pcic_isa_intr; int pcic_isa_intr1(void *); +pcic_intr_mapirq_t pcic_isa_mapirq; void pcic_putb_io(struct pcic_slot *sp, int reg, unsigned char val); int pcic_set_memory_offset(device_t bus, device_t child, int rid, u_int32_t offset #if __FreeBSD_version >= 500000 , u_int32_t *deltap #endif ); int pcic_set_res_flags(device_t bus, device_t child, int restype, int rid, u_long value); void pcic_setb(struct pcic_slot *sp, int reg, unsigned char mask); int pcic_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *intr, void *arg, void **cookiep); int pcic_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); timeout_t pcic_timeout;