1/*- 2 * Copyright (c) 2005 Poul-Henning Kamp 3 * Copyright (c) 2010 Joerg Wunsch 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/systm.h> 33#include <sys/module.h> 34#include <sys/bus.h> 35#include <dev/pci/pcireg.h> 36#include <dev/pci/pcivar.h> 37 38#include <machine/bus.h> 39#include <machine/resource.h> 40#include <machine/stdarg.h> 41#include <sys/rman.h> 42 43/* vtophys */ 44#include <vm/vm.h> 45#include <vm/pmap.h> 46#include <machine/pmap.h> 47 48#define UPD7210_HW_DRIVER 1 49#include <dev/ieee488/upd7210.h> 50#include <dev/ieee488/tnt4882.h> 51 52struct tnt_softc { 53 int foo; 54 struct upd7210 upd7210; 55 56 struct resource *res[3]; 57 void *intr_handler; 58}; 59 60static struct resource_spec tnt_res_spec[] = { 61 { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE}, 62 { SYS_RES_MEMORY, PCIR_BAR(1), RF_ACTIVE}, 63 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, 64 { -1, 0 } 65}; 66 67struct tst { 68 enum {RD, WT, xDELAY, END} 69 action; 70 enum tnt4882reg reg; 71 uint8_t val; 72}; 73 74/* 75 * From NI Application note 095: 76 * Writing Functional Self-Tests for the TNT4882 GPIB Interface Chip 77 * XXX: fill in the rest ? 78 */ 79static struct tst tst_reset[] = { 80 {WT, tauxcr, 0x80}, /* chip reset if in 9914 mode */ 81 {WT, auxmr, 0x80}, /* swrst if swapped */ 82 {WT, tauxcr, 0x99}, /* switch to 7210 mode */ 83 {WT, auxmr, 0x99}, /* switch to 7210 mode if swapped */ 84 {WT, auxmr, 0x02}, /* execute chip reset */ 85 {WT, keyreg, 0x00}, /* important! clear the swap bit */ 86 {WT, eosr, 0x00}, /* clear EOS register */ 87 {WT, cdor, 0x00}, /* clear data lines */ 88 {WT, imr1, 0x00}, /* disable all interrupts */ 89 {WT, imr2, 0x00}, 90 {WT, imr0, 0x80}, 91 {WT, adr, 0x80}, 92 {WT, adr, 0x00}, 93 {WT, admr, 0x00}, /* clear addressing modes */ 94 {WT, auxmr, 0x00}, /* release from idle state with pon */ 95 {WT, auxmr, 0x60}, /* reset ppr */ 96 {WT, bcr, 0x00}, /* reset bcr */ 97 {WT, misc, 0x04}, /* set wrap plug bit */ 98 {WT, cmdr, 0xB2}, /* issue soft reset */ 99 {WT, hssel, 0x00}, /* select two-chip mode */ 100 {END, 0, 0} 101}; 102 103static struct tst tst_read_reg[] = { 104 {RD, isr1, 0x00}, /* Verify mask registers are clear */ 105 {RD, isr2, 0x00}, 106 {RD, adsr, 0x40}, /* Verify ATN is not asserted */ 107 {RD, adr0, 0x00}, /* Verify Primary address not set */ 108 {RD, adr1, 0x00}, /* Verify Secondary address not set */ 109 {RD, sts1, 0x8B}, /* Verify DONE, STOP, HALT, and GSYNC set */ 110 {RD, isr3, 0x19}, /* Verify STOP, Not Full FIFO, & DONE set */ 111 {RD, sts2, 0x9A}, /* Verify FIFO A/B is empty */ 112 {RD, sasr, 0x00}, /* Verify clear */ 113 {RD, isr0, 0x01}, /* Verify SYNC bit is set */ 114 {END, 0, 0} 115}; 116 117static struct tst tst_bsr_dcr[] = { 118 {WT, bcr, 0x55}, /* Set DAV, NRFD, SRQ, and REN */ 119 {WT, dcr, 0xAA}, /* Write pattern to GPIB data lines */ 120 {RD, bsr, 0x55}, /* Verify DAV, NRFD, SRQ, and REN are set */ 121 {RD, dsr, 0xAA}, /* Verify data pattern written previously */ 122 {WT, bcr, 0xAA}, /* Set ATN, NDAC, EOI, & IFC */ 123 {WT, dcr, 0x55}, /* Write pattern to GPIB data lines */ 124 {RD, bsr, 0xAA}, /* Verify ATN, NDAC, EOI, & IFC are set */ 125 {RD, dsr, 0x55}, /* Verify data pattern written previously */ 126 {WT, bcr, 0x00}, /* Clear control lines */ 127 {WT, dcr, 0x00}, /* Clear data lines */ 128 {RD, bsr, 0x00}, /* Verify control lines are clear */ 129 {RD, dsr, 0x00}, /* Verify data lines are clear */ 130 {END, 0, 0} 131}; 132 133static struct tst tst_adr0_1[] = { 134 {WT, adr, 0x55}, /* Set Primary talk address */ 135 {WT, adr, 0xAA}, /* Set Secondary listen address */ 136 {RD, adr0, 0x55}, /* Read Primary address */ 137 {RD, adr1, 0x2A}, /* Read Secondary address */ 138 {WT, adr, 0x2A}, /* Set Primay listen address */ 139 {WT, adr, 0xD5}, /* Set Secondary talk address */ 140 {RD, adr0, 0x2A}, /* Read Primary address */ 141 {RD, adr1, 0x55}, /* Read Secondary address */ 142 {END, 0, 0} 143}; 144 145static struct tst tst_cdor_dir[] = { 146 {WT, admr, 0xF0}, /* program AT-GPIB as talker only and 147 * listener only */ 148 {RD, isr1, 0x02}, /* check DO bit set */ 149 {RD, adsr, 0x46}, /* check AT-GPIB is both talker active 150 * and listener active */ 151 {WT, cdor, 0xAA}, /* write out data byte */ 152 {xDELAY, 0, 1}, /* One ISA I/O Cycle (500-ns) */ 153 {RD, isr1, 0x03}, /* check DO and DI bits set */ 154 {RD, dir, 0xAA}, /* verify data received */ 155 {WT, cdor, 0x55}, /* write out data byte */ 156 {xDELAY, 0, 1}, /* One ISA I/O Cycle (500-ns) */ 157 {RD, dir, 0x55}, /* verify data received */ 158 {END, 0, 0} 159}; 160 161static struct tst tst_spmr_spsr[] = { 162 {WT, spsr, 0x00}, /* Write pattern to SPSR register */ 163 {RD, spmr, 0x00}, /* Read back previously written pattern */ 164 {WT, spsr, 0xBF}, /* Write pattern to SPSR register */ 165 {RD, spmr, 0xBF}, /* Read back previously written pattern */ 166 {END, 0, 0} 167}; 168 169static struct tst tst_count0_1[] = { 170 {WT, cnt0, 0x55}, /* Verify every other bit can be set */ 171 {WT, cnt1, 0xAA}, 172 {RD, cnt0, 0x55}, /* Read back previously written pattern */ 173 {RD, cnt1, 0xAA}, 174 {WT, cnt0, 0xAA}, /* Verify every other bit can be set */ 175 {WT, cnt1, 0x55}, 176 {RD, cnt0, 0xAA}, /* Read back previously written pattern */ 177 {RD, cnt1, 0x55}, 178 {END, 0, 0} 179}; 180 181static int 182tst_exec(struct tnt_softc *sc, struct tst *tp, const char *name) 183{ 184 uint8_t u; 185 int step; 186 187 for (step = 0; tp->action != END; tp++, step++) { 188 switch (tp->action) { 189 case WT: 190 bus_write_1(sc->res[1], tp->reg, tp->val); 191 break; 192 case RD: 193 u = bus_read_1(sc->res[1], tp->reg); 194 if (u != tp->val) { 195 printf( 196 "Test %s, step %d: reg(%02x) = %02x", 197 name, step, tp->reg, u); 198 printf( "should have been %02x\n", tp->val); 199 return (1); 200 } 201 break; 202 case xDELAY: 203 DELAY(tp->val); 204 break; 205 default: 206 printf("Unknown action in test %s, step %d: %d\n", 207 name, step, tp->action); 208 return (1); 209 } 210 } 211 if (bootverbose) 212 printf("Test %s passed\n", name); 213 return (0); 214} 215 216static int 217tnt_probe(device_t dev) 218{ 219 220 if (pci_get_vendor(dev) == 0x1093 && pci_get_device(dev) == 0xc801) { 221 device_set_desc(dev, "NI PCI-GPIB"); 222 return (BUS_PROBE_DEFAULT); 223 } 224 return (ENXIO); 225} 226 227static int 228tnt_attach(device_t dev) 229{ 230 struct tnt_softc *sc; 231 int error, i; 232 uint8_t version; 233 234 sc = device_get_softc(dev); 235 236 error = bus_alloc_resources(dev, tnt_res_spec, sc->res); 237 if (error) 238 return (error); 239 240 error = bus_setup_intr(dev, sc->res[2], INTR_TYPE_MISC | INTR_MPSAFE, 241 NULL, upd7210intr, &sc->upd7210, &sc->intr_handler); 242 243 /* IO Device Window Base Size Register (IODWBSR) */ 244 bus_write_4(sc->res[0], 0xc0, rman_get_start(sc->res[1]) | 0x80); 245 246 tst_exec(sc, tst_reset, "Reset"); 247 tst_exec(sc, tst_read_reg, "Read registers"); 248 tst_exec(sc, tst_bsr_dcr, "BSR & DCR"); 249 tst_exec(sc, tst_adr0_1, "ADR0,1"); 250 tst_exec(sc, tst_cdor_dir, "CDOR/DIR"); 251 tst_exec(sc, tst_spmr_spsr, "CPMR/SPSR"); 252 tst_exec(sc, tst_count0_1, "COUNT0:1"); 253 tst_exec(sc, tst_reset, "Reset"); 254 255 version = bus_read_1(sc->res[1], csr); 256 version = (version >> 4) & 0x0f; 257 device_printf(dev, "Chip version 0x%02x (TNT%s)\n", 258 version, 259 version >= 4? "5004 or above": "4882"); 260 if (version >= 4) { 261 device_printf(dev, "Forcing FIFO mode\n"); 262 sc->upd7210.use_fifo = 1; 263 } else { 264 sc->upd7210.use_fifo = 0; 265 } 266 267 /* pass 7210 interrupts through */ 268 bus_write_1(sc->res[1], imr3, 0x02); 269 270 for (i = 0; i < 8; i++) { 271 sc->upd7210.reg_res[i] = sc->res[1]; 272 sc->upd7210.reg_offset[i] = i * 2; 273 } 274 275 /* No DMA help */ 276 sc->upd7210.dmachan = -1; 277 278 /* No "special interrupt handling" needed here. */ 279 sc->upd7210.irq_clear_res = NULL; 280 281 upd7210attach(&sc->upd7210); 282 device_printf(dev, "attached gpib%d\n", sc->upd7210.unit); 283 284 if (sc->upd7210.use_fifo) 285 bus_write_1(sc->res[0], hssel, 0x01); /* one-chip mode */ 286 287 288 return (0); 289} 290 291static int 292tnt_detach(device_t dev) 293{ 294 struct tnt_softc *sc; 295 296 sc = device_get_softc(dev); 297 bus_teardown_intr(dev, sc->res[2], sc->intr_handler); 298 upd7210detach(&sc->upd7210); 299 300 bus_release_resources(dev, tnt_res_spec, sc->res); 301 302 return (0); 303} 304 305static device_method_t tnt4882_methods[] = { 306 DEVMETHOD(device_probe, tnt_probe), 307 DEVMETHOD(device_attach, tnt_attach), 308 DEVMETHOD(device_detach, tnt_detach), 309 { 0, 0 } 310}; 311 312static driver_t pci_gpib_driver = { 313 "tnt4882", 314 tnt4882_methods, 315 sizeof(struct tnt_softc) 316}; 317 318static devclass_t pci_gpib_devclass; 319 320DRIVER_MODULE(pci_gpib, pci, pci_gpib_driver, pci_gpib_devclass, 0, 0); 321