1/* $NecBSD: ct_isa.c,v 1.6 1999/07/26 06:32:01 honda Exp $ */ 2 3#include <sys/cdefs.h> 4__FBSDID("$FreeBSD$"); 5/* $NetBSD$ */ 6 7/*- 8 * [NetBSD for NEC PC-98 series] 9 * Copyright (c) 1995, 1996, 1997, 1998 10 * NetBSD/pc98 porting staff. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#define SCSIBUS_RESCAN 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/bio.h> 42#include <sys/buf.h> 43#include <sys/queue.h> 44#include <sys/malloc.h> 45#include <sys/bus.h> 46#include <sys/module.h> 47#include <sys/errno.h> 48 49#include <vm/vm.h> 50 51#include <machine/bus.h> 52#include <machine/resource.h> 53#include <sys/bus.h> 54#include <sys/rman.h> 55#include <machine/md_var.h> 56 57#include <pc98/cbus/cbus.h> 58#include <isa/isavar.h> 59 60#include <compat/netbsd/dvcfg.h> 61 62#include <cam/scsi/scsi_low.h> 63 64#include <dev/ic/wd33c93reg.h> 65#include <dev/ct/ctvar.h> 66#include <dev/ct/bshwvar.h> 67 68#define BSHW_IOSZ 0x08 69#define BSHW_IOBASE 0xcc0 70#define BSHW_MEMSZ (PAGE_SIZE * 2) 71 72static int ct_isa_match(device_t); 73static int ct_isa_attach(device_t); 74static int ct_space_map(device_t, struct bshw *, 75 struct resource **, struct resource **); 76static void ct_space_unmap(device_t, struct ct_softc *); 77static struct bshw *ct_find_hw(device_t); 78static void ct_dmamap(void *, bus_dma_segment_t *, int, int); 79static void ct_isa_bus_access_weight(struct ct_bus_access_handle *); 80static void ct_isa_dmasync_before(struct ct_softc *); 81static void ct_isa_dmasync_after(struct ct_softc *); 82 83struct ct_isa_softc { 84 struct ct_softc sc_ct; 85 struct bshw_softc sc_bshw; 86}; 87 88static struct isa_pnp_id ct_pnp_ids[] = { 89 { 0x0100e7b1, "Logitec LHA-301" }, 90 { 0x110154dc, "I-O DATA SC-98III" }, 91 { 0x4120acb4, "MELCO IFC-NN" }, 92 { 0, NULL } 93}; 94 95static device_method_t ct_isa_methods[] = { 96 /* Device interface */ 97 DEVMETHOD(device_probe, ct_isa_match), 98 DEVMETHOD(device_attach, ct_isa_attach), 99 { 0, 0 } 100}; 101 102static driver_t ct_isa_driver = { 103 "ct", ct_isa_methods, sizeof(struct ct_isa_softc), 104}; 105 106static devclass_t ct_devclass; 107 108DRIVER_MODULE(ct, isa, ct_isa_driver, ct_devclass, 0, 0); 109 110static int 111ct_isa_match(device_t dev) 112{ 113 struct bshw *hw; 114 struct resource *port_res, *mem_res; 115 struct ct_bus_access_handle ch; 116 int rv; 117 118 if (ISA_PNP_PROBE(device_get_parent(dev), dev, ct_pnp_ids) == ENXIO) 119 return ENXIO; 120 121 switch (isa_get_logicalid(dev)) { 122 case 0x0100e7b1: /* LHA-301 */ 123 case 0x110154dc: /* SC-98III */ 124 case 0x4120acb4: /* IFC-NN */ 125 /* XXX - force to SMIT mode */ 126 device_set_flags(dev, device_get_flags(dev) | 0x40000); 127 break; 128 } 129 130 if (isa_get_port(dev) == -1) 131 bus_set_resource(dev, SYS_RES_IOPORT, 0, 132 BSHW_IOBASE, BSHW_IOSZ); 133 134 if ((hw = ct_find_hw(dev)) == NULL) 135 return ENXIO; 136 if (ct_space_map(dev, hw, &port_res, &mem_res) != 0) 137 return ENXIO; 138 139 bzero(&ch, sizeof(ch)); 140 ch.ch_iot = rman_get_bustag(port_res); 141 ch.ch_ioh = rman_get_bushandle(port_res), 142 ch.ch_bus_weight = ct_isa_bus_access_weight; 143 144 rv = ctprobesubr(&ch, 0, BSHW_DEFAULT_HOSTID, 145 BSHW_DEFAULT_CHIPCLK, NULL); 146 if (rv != 0) 147 { 148 struct bshw_softc bshw_tab; 149 struct bshw_softc *bs = &bshw_tab; 150 151 memset(bs, 0, sizeof(*bs)); 152 bshw_read_settings(&ch, bs); 153 bus_set_resource(dev, SYS_RES_IRQ, 0, bs->sc_irq, 1); 154 bus_set_resource(dev, SYS_RES_DRQ, 0, bs->sc_drq, 1); 155 } 156 157 bus_release_resource(dev, SYS_RES_IOPORT, 0, port_res); 158 if (mem_res != NULL) 159 bus_release_resource(dev, SYS_RES_MEMORY, 0, mem_res); 160 161 if (rv != 0) 162 return 0; 163 return ENXIO; 164} 165 166static int 167ct_isa_attach(device_t dev) 168{ 169 struct ct_isa_softc *pct = device_get_softc(dev); 170 struct ct_softc *ct = &pct->sc_ct; 171 struct ct_bus_access_handle *chp = &ct->sc_ch; 172 struct scsi_low_softc *slp = &ct->sc_sclow; 173 struct bshw_softc *bs = &pct->sc_bshw; 174 struct bshw *hw; 175 int irq_rid, drq_rid, chiprev; 176 u_int8_t *vaddr; 177 bus_addr_t addr; 178 intrmask_t s; 179 180 hw = ct_find_hw(dev); 181 if (ct_space_map(dev, hw, &ct->port_res, &ct->mem_res) != 0) { 182 device_printf(dev, "bus io mem map failed\n"); 183 return ENXIO; 184 } 185 186 bzero(chp, sizeof(*chp)); 187 chp->ch_iot = rman_get_bustag(ct->port_res); 188 chp->ch_ioh = rman_get_bushandle(ct->port_res); 189 if (ct->mem_res) { 190 chp->ch_memt = rman_get_bustag(ct->mem_res); 191 chp->ch_memh = rman_get_bushandle(ct->mem_res); 192 } 193 chp->ch_bus_weight = ct_isa_bus_access_weight; 194 195 irq_rid = 0; 196 ct->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, 197 RF_ACTIVE); 198 drq_rid = 0; 199 ct->drq_res = bus_alloc_resource_any(dev, SYS_RES_DRQ, &drq_rid, 200 RF_ACTIVE); 201 if (ct->irq_res == NULL || ct->drq_res == NULL) { 202 ct_space_unmap(dev, ct); 203 return ENXIO; 204 } 205 206 if (ctprobesubr(chp, 0, BSHW_DEFAULT_HOSTID, 207 BSHW_DEFAULT_CHIPCLK, &chiprev) == 0) 208 { 209 device_printf(dev, "hardware missing\n"); 210 ct_space_unmap(dev, ct); 211 return ENXIO; 212 } 213 214 /* setup DMA map */ 215 if (bus_dma_tag_create(NULL, 1, 0, 216 BUS_SPACE_MAXADDR_24BIT, BUS_SPACE_MAXADDR, 217 NULL, NULL, DFLTPHYS, 1, 218 BUS_SPACE_MAXSIZE_32BIT, 219 BUS_DMA_ALLOCNOW, NULL, NULL, 220 &ct->sc_dmat) != 0) { 221 device_printf(dev, "can't set up ISA DMA map\n"); 222 ct_space_unmap(dev, ct); 223 return ENXIO; 224 } 225 226 if (bus_dmamem_alloc(ct->sc_dmat, (void **)&vaddr, BUS_DMA_NOWAIT, 227 &ct->sc_dmamapt) != 0) { 228 device_printf(dev, "can't set up ISA DMA map\n"); 229 ct_space_unmap(dev, ct); 230 return ENXIO; 231 } 232 233 bus_dmamap_load(ct->sc_dmat, ct->sc_dmamapt, vaddr, DFLTPHYS, 234 ct_dmamap, &addr, BUS_DMA_NOWAIT); 235 236 /* setup machdep softc */ 237 bs->sc_hw = hw; 238 bs->sc_io_control = 0; 239 bs->sc_bounce_phys = (u_int8_t *)addr; 240 bs->sc_bounce_addr = vaddr; 241 bs->sc_bounce_size = DFLTPHYS; 242 bs->sc_minphys = (1 << 24); 243 bs->sc_dmasync_before = ct_isa_dmasync_before; 244 bs->sc_dmasync_after = ct_isa_dmasync_after; 245 bshw_read_settings(chp, bs); 246 247 /* setup ct driver softc */ 248 ct->ct_hw = bs; 249 ct->ct_dma_xfer_start = bshw_dma_xfer_start; 250 ct->ct_pio_xfer_start = bshw_smit_xfer_start; 251 ct->ct_dma_xfer_stop = bshw_dma_xfer_stop; 252 ct->ct_pio_xfer_stop = bshw_smit_xfer_stop; 253 ct->ct_bus_reset = bshw_bus_reset; 254 ct->ct_synch_setup = bshw_synch_setup; 255 256 ct->sc_xmode = CT_XMODE_DMA; 257 if (chp->ch_memh != NULL) 258 ct->sc_xmode |= CT_XMODE_PIO; 259 260 ct->sc_chiprev = chiprev; 261 switch (chiprev) 262 { 263 case CT_WD33C93: 264 /* s = "WD33C93"; */ 265 ct->sc_chipclk = 8; 266 break; 267 case CT_WD33C93_A: 268 if (DVCFG_MAJOR(device_get_flags(dev)) > 0) 269 { 270 /* s = "AM33C93_A"; */ 271 ct->sc_chipclk = 20; 272 ct->sc_chiprev = CT_AM33C93_A; 273 } 274 else 275 { 276 /* s = "WD33C93_A"; */ 277 ct->sc_chipclk = 10; 278 } 279 break; 280 281 case CT_AM33C93_A: 282 /* s = "AM33C93_A"; */ 283 ct->sc_chipclk = 20; 284 break; 285 286 default: 287 case CT_WD33C93_B: 288 /* s = "WD33C93_B"; */ 289 ct->sc_chipclk = 20; 290 break; 291 } 292#if 0 293 printf("%s: chiprev %s chipclk %d MHz\n", 294 slp->sl_dev.dv_xname, s, ct->sc_chipclk); 295#endif 296 297 slp->sl_dev = dev; 298 slp->sl_hostid = bs->sc_hostid; 299 slp->sl_cfgflags = device_get_flags(dev); 300 301 s = splcam(); 302 ctattachsubr(ct); 303 splx(s); 304 305 if (bus_setup_intr(dev, ct->irq_res, INTR_TYPE_CAM, 306 NULL, (driver_intr_t *)ctintr, ct, &ct->sc_ih)) { 307 ct_space_unmap(dev, ct); 308 return ENXIO; 309 } 310 311 return 0; 312} 313 314static struct bshw * 315ct_find_hw(device_t dev) 316{ 317 return DVCFG_HW(&bshw_hwsel, DVCFG_MAJOR(device_get_flags(dev))); 318} 319 320static int 321ct_space_map(device_t dev, struct bshw *hw, 322 struct resource **iohp, struct resource **memhp) 323{ 324 int port_rid, mem_rid; 325 326 *memhp = NULL; 327 328 port_rid = 0; 329 *iohp = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 0, ~0, 330 BSHW_IOSZ, RF_ACTIVE); 331 if (*iohp == NULL) 332 return ENXIO; 333 334 if ((hw->hw_flags & BSHW_SMFIFO) == 0 || isa_get_maddr(dev) == -1) 335 return 0; 336 337 mem_rid = 0; 338 *memhp = bus_alloc_resource(dev, SYS_RES_MEMORY, &mem_rid, 0, ~0, 339 BSHW_MEMSZ, RF_ACTIVE); 340 if (*memhp == NULL) { 341 bus_release_resource(dev, SYS_RES_IOPORT, port_rid, *iohp); 342 return ENXIO; 343 } 344 345 return 0; 346} 347 348static void 349ct_space_unmap(device_t dev, struct ct_softc *ct) 350{ 351 if (ct->port_res != NULL) 352 bus_release_resource(dev, SYS_RES_IOPORT, 0, ct->port_res); 353 if (ct->mem_res != NULL) 354 bus_release_resource(dev, SYS_RES_MEMORY, 0, ct->mem_res); 355 if (ct->irq_res != NULL) 356 bus_release_resource(dev, SYS_RES_IRQ, 0, ct->irq_res); 357 if (ct->drq_res != NULL) 358 bus_release_resource(dev, SYS_RES_DRQ, 0, ct->drq_res); 359} 360 361static void 362ct_dmamap(void *arg, bus_dma_segment_t *seg, int nseg, int error) 363{ 364 bus_addr_t *addr = (bus_addr_t *)arg; 365 366 *addr = seg->ds_addr; 367} 368 369static void 370ct_isa_bus_access_weight(struct ct_bus_access_handle *chp) 371{ 372 373 outb(0x5f, 0); 374} 375 376static void 377ct_isa_dmasync_before(struct ct_softc *ct) 378{ 379 380 if (need_pre_dma_flush) 381 wbinvd(); 382} 383 384static void 385ct_isa_dmasync_after(struct ct_softc *ct) 386{ 387 388 if (need_post_dma_flush) 389 invd(); 390} 391