1 /* $NetBSD: asc.c,v 1.22 2008/04/13 04:55:52 tsutsui Exp $ */
4 * Copyright (c) 2003 Izumi Tsutsui. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: asc.c,v 1.22 2008/04/13 04:55:52 tsutsui Exp $");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/device.h>
35 #include <machine/autoconf.h>
36 #include <machine/bus.h>
38 #include <uvm/uvm_extern.h>
40 #include <dev/scsipi/scsipi_all.h>
41 #include <dev/scsipi/scsi_all.h>
42 #include <dev/scsipi/scsiconf.h>
44 #include <arc/jazz/jazziovar.h>
45 #include <arc/jazz/dma.h>
46 #include <arc/jazz/pica.h>
48 #include <dev/ic/ncr53c9xreg.h>
49 #include <dev/ic/ncr53c9xvar.h>
51 #define ASC_NPORTS 0x10
52 #define ASC_ID_53CF94 0xa2 /* XXX should be in MI ncr53c9xreg.h? */
53 #define ASC_ID_FAS216 0x12 /* XXX should be in MI ncr53c9xreg.h? */
56 struct ncr53c9x_softc sc_ncr53c9x
; /* glue to MI code */
58 bus_space_tag_t sc_iot
; /* bus space tag */
59 bus_space_handle_t sc_ioh
; /* bus space handle */
60 bus_space_handle_t sc_dmaioh
; /* bus space handle for DMAC */
62 bus_dma_tag_t sc_dmat
; /* DMA tag */
63 bus_dmamap_t sc_dmamap
; /* DMA map for transfers */
65 int sc_active
; /* DMA state */
66 int sc_datain
; /* DMA Data Direction */
67 size_t sc_dmasize
; /* DMA size */
68 uint8_t **sc_dmaaddr
; /* DMA address */
69 size_t *sc_dmalen
; /* DMA length */
73 * Autoconfiguration data for config.
75 int asc_match(device_t
, cfdata_t
, void *);
76 void asc_attach(device_t
, device_t
, void *);
78 CFATTACH_DECL_NEW(asc
, sizeof(struct asc_softc
),
79 asc_match
, asc_attach
, NULL
, NULL
);
81 static void asc_minphys(struct buf
*);
84 * Functions and the switch for the MI code.
86 uint8_t asc_read_reg(struct ncr53c9x_softc
*, int);
87 void asc_write_reg(struct ncr53c9x_softc
*, int, uint8_t);
88 int asc_dma_isintr(struct ncr53c9x_softc
*);
89 void asc_dma_reset(struct ncr53c9x_softc
*);
90 int asc_dma_intr(struct ncr53c9x_softc
*);
91 int asc_dma_setup(struct ncr53c9x_softc
*, uint8_t **, size_t *, int, size_t *);
92 void asc_dma_go(struct ncr53c9x_softc
*);
93 void asc_dma_stop(struct ncr53c9x_softc
*);
94 int asc_dma_isactive(struct ncr53c9x_softc
*);
96 struct ncr53c9x_glue asc_glue
= {
106 NULL
/* gl_clear_latched_intr */
110 * Match driver based on name
113 asc_match(device_t parent
, cfdata_t cf
, void *aux
)
115 struct jazzio_attach_args
*ja
= aux
;
117 if (strcmp(ja
->ja_name
, "ESP216") != 0)
123 asc_attach(device_t parent
, device_t self
, void *aux
)
125 struct asc_softc
*asc
= device_private(self
);
126 struct ncr53c9x_softc
*sc
= &asc
->sc_ncr53c9x
;
127 struct jazzio_attach_args
*ja
= aux
;
132 /* Need info from platform dependent config?? */
133 if (asc_conf
== NULL
)
134 panic("asc_conf isn't initialized");
138 sc
->sc_glue
= &asc_glue
;
140 asc
->sc_iot
= iot
= ja
->ja_bust
;
141 asc
->sc_dmat
= ja
->ja_dmat
;
143 if (bus_space_map(iot
, ja
->ja_addr
, ASC_NPORTS
, 0, &asc
->sc_ioh
)) {
144 aprint_error(": unable to map I/O space\n");
148 if (bus_space_map(iot
, R4030_SYS_DMA0_REGS
, R4030_DMA_RANGE
,
149 0, &asc
->sc_dmaioh
)) {
150 aprint_error(": unable to map DMA I/O space\n");
154 if (bus_dmamap_create(asc
->sc_dmat
, MAXPHYS
, 1, MAXPHYS
, 0,
155 BUS_DMA_ALLOCNOW
| BUS_DMA_NOWAIT
, &asc
->sc_dmamap
)) {
156 aprint_error(": unable to create DMA map\n");
161 * XXX More of this should be in ncr53c9x_attach(), but
162 * XXX should we really poke around the chip that much in
163 * XXX the MI code? Think about this more...
167 * Set up static configuration info.
169 sc
->sc_id
= 7; /* XXX should be taken from ARC BIOS */
170 sc
->sc_cfg1
= sc
->sc_id
| NCRCFG1_PARENB
;
172 /* identify 53CF9x-2 or not */
173 asc_write_reg(sc
, NCR_CMD
, NCRCMD_RSTCHIP
);
175 asc_write_reg(sc
, NCR_CMD
, NCRCMD_DMA
| NCRCMD_NOP
);
177 asc_write_reg(sc
, NCR_CFG2
, NCRCFG2_FE
);
179 asc_write_reg(sc
, NCR_CMD
, NCRCMD_DMA
| NCRCMD_NOP
);
181 asc_id
= asc_read_reg(sc
, NCR_TCH
);
182 if (asc_id
== ASC_ID_53CF94
|| asc_id
== ASC_ID_FAS216
) {
183 /* XXX should be have NCR_VARIANT_NCR53CF94? */
184 sc
->sc_rev
= NCR_VARIANT_NCR53C94
;
185 sc
->sc_cfg2
= NCRCFG2_SCSI2
| NCRCFG2_FE
;
186 sc
->sc_cfg3
= NCRF9XCFG3_IDM
| NCRF9XCFG3_FCLK
;
187 sc
->sc_features
= NCR_F_FASTSCSI
;
188 sc
->sc_cfg3_fscsi
= NCRF9XCFG3_FSCSI
;
189 sc
->sc_freq
= 40; /* MHz */
190 sc
->sc_maxxfer
= 16 * 1024 * 1024;
192 sc
->sc_rev
= NCR_VARIANT_NCR53C94
;
193 sc
->sc_freq
= 25; /* MHz */
194 sc
->sc_maxxfer
= 64 * 1024;
198 * XXX minsync and maxxfer _should_ be set up in MI code,
199 * XXX but it appears to have some dependency on what sort
200 * XXX of DMA we're hooked up to, etc.
204 * This is the value used to start sync negotiations
205 * Note that the NCR register "SYNCTP" is programmed
206 * in "clocks per byte", and has a minimum value of 4.
207 * The SCSI period used in negotiation is one-fourth
208 * of the time (in nanoseconds) needed to transfer one byte.
209 * Since the chip's clock is given in MHz, we have the following
210 * formula: 4 * period = (1000 / freq) * 4
212 sc
->sc_minsync
= 1000 / sc
->sc_freq
;
214 /* establish interrupt */
215 jazzio_intr_establish(ja
->ja_intr
, ncr53c9x_intr
, asc
);
217 /* Do the common parts of attachment. */
218 sc
->sc_adapter
.adapt_minphys
= asc_minphys
;
219 sc
->sc_adapter
.adapt_request
= ncr53c9x_scsipi_request
;
223 /* Turn on target selection using the `DMA' method */
224 sc
->sc_features
|= NCR_F_DMASELECT
;
229 bus_space_unmap(iot
, asc
->sc_dmaioh
, R4030_DMA_RANGE
);
231 bus_space_unmap(iot
, asc
->sc_ioh
, ASC_NPORTS
);
236 asc_minphys(struct buf
*bp
)
239 #define ASC_MAX_XFER (32 * 1024) /* XXX can't xfer 64kbytes? */
241 if (bp
->b_bcount
> ASC_MAX_XFER
)
242 bp
->b_bcount
= ASC_MAX_XFER
;
251 asc_read_reg(struct ncr53c9x_softc
*sc
, int reg
)
253 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
255 return bus_space_read_1(asc
->sc_iot
, asc
->sc_ioh
, reg
);
259 asc_write_reg(struct ncr53c9x_softc
*sc
, int reg
, uint8_t val
)
261 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
263 bus_space_write_1(asc
->sc_iot
, asc
->sc_ioh
, reg
, val
);
267 asc_dma_isintr(struct ncr53c9x_softc
*sc
)
270 return asc_read_reg(sc
, NCR_STAT
) & NCRSTAT_INT
;
274 asc_dma_reset(struct ncr53c9x_softc
*sc
)
276 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
279 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_ENAB
, 0);
280 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_MODE
, 0);
284 asc_dma_intr(struct ncr53c9x_softc
*sc
)
286 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
287 int datain
, resid
, trans
;
289 datain
= asc
->sc_datain
;
292 /* This is an "assertion" :) */
293 if (asc
->sc_active
== 0)
294 panic("%s: DMA wasn't active", __func__
);
297 /* DMA has stopped */
301 if (asc
->sc_dmasize
== 0) {
302 /* A "Transfer Pad" operation complete */
303 NCR_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n",
304 NCR_READ_REG(sc
, NCR_TCL
) |
305 (NCR_READ_REG(sc
, NCR_TCM
) << 8),
306 NCR_READ_REG(sc
, NCR_TCL
),
307 NCR_READ_REG(sc
, NCR_TCM
)));
315 * If a transfer onto the SCSI bus gets interrupted by the device
316 * (e.g. for a SAVEPOINTER message), the data in the FIFO counts
317 * as residual since the ESP counter registers get decremented as
318 * bytes are clocked into the FIFO.
321 (resid
= (asc_read_reg(sc
, NCR_FFLAG
) & NCRFIFO_FF
)) != 0) {
322 NCR_DMA(("asc_dma_intr: empty asc FIFO of %d ", resid
));
325 if ((sc
->sc_espstat
& NCRSTAT_TC
) == 0) {
327 * `Terminal count' is off, so read the residue
328 * out of the ASC counter registers.
330 resid
+= (NCR_READ_REG(sc
, NCR_TCL
) |
331 (NCR_READ_REG(sc
, NCR_TCM
) << 8) |
332 ((sc
->sc_cfg2
& NCRCFG2_FE
)
333 ? (NCR_READ_REG(sc
, NCR_TCH
) << 16) : 0));
335 if (resid
== 0 && asc
->sc_dmasize
== 65536 &&
336 (sc
->sc_cfg2
& NCRCFG2_FE
) == 0)
337 /* A transfer of 64K is encoded as `TCL=TCM=0' */
342 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_COUNT
, 0);
343 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_ENAB
, 0);
344 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_MODE
, 0);
346 bus_dmamap_sync(asc
->sc_dmat
, asc
->sc_dmamap
,
347 0, asc
->sc_dmamap
->dm_mapsize
,
348 datain
? BUS_DMASYNC_POSTREAD
: BUS_DMASYNC_POSTWRITE
);
349 bus_dmamap_unload(asc
->sc_dmat
, asc
->sc_dmamap
);
351 trans
= asc
->sc_dmasize
- resid
;
353 if (trans
< 0) { /* transfered < 0 ? */
356 * This situation can happen in perfectly normal operation
357 * if the ESP is reselected while using DMA to select
358 * another target. As such, don't print the warning.
360 printf("%s: xfer (%d) > req (%d)\n",
361 sc
->sc_dev
.dv_xname
, trans
, asc
->sc_dmasize
);
363 trans
= asc
->sc_dmasize
;
365 NCR_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n",
366 NCR_READ_REG(sc
, NCR_TCL
),
367 NCR_READ_REG(sc
, NCR_TCM
),
368 (sc
->sc_cfg2
& NCRCFG2_FE
) ? NCR_READ_REG(sc
, NCR_TCH
) : 0,
371 *asc
->sc_dmalen
-= trans
;
372 *asc
->sc_dmaaddr
+= trans
;
378 asc_dma_setup(struct ncr53c9x_softc
*sc
, uint8_t **addr
, size_t *len
,
379 int datain
, size_t *dmasize
)
381 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
384 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_ENAB
, 0);
385 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_MODE
, 0);
387 asc
->sc_dmaaddr
= addr
;
388 asc
->sc_dmalen
= len
;
389 asc
->sc_dmasize
= *dmasize
;
390 asc
->sc_datain
= datain
;
393 * No need to set up DMA in `Transfer Pad' operation.
398 bus_dmamap_load(asc
->sc_dmat
, asc
->sc_dmamap
, *addr
, *len
, NULL
,
399 ((sc
->sc_nexus
->xs
->xs_control
& XS_CTL_NOSLEEP
) ?
400 BUS_DMA_NOWAIT
: BUS_DMA_WAITOK
) | BUS_DMA_STREAMING
|
401 (datain
? BUS_DMA_READ
: BUS_DMA_WRITE
));
402 bus_dmamap_sync(asc
->sc_dmat
, asc
->sc_dmamap
,
403 0, asc
->sc_dmamap
->dm_mapsize
,
404 datain
? BUS_DMASYNC_PREREAD
: BUS_DMASYNC_PREWRITE
);
406 /* load transfer parameters */
407 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
,
408 R4030_DMA_ADDR
, asc
->sc_dmamap
->dm_segs
[0].ds_addr
);
409 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
,
410 R4030_DMA_COUNT
, asc
->sc_dmamap
->dm_segs
[0].ds_len
);
411 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
,
412 R4030_DMA_MODE
, R4030_DMA_MODE_160NS
| R4030_DMA_MODE_16
);
415 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
,
416 R4030_DMA_ENAB
, R4030_DMA_ENAB_RUN
|
417 (asc
->sc_datain
? R4030_DMA_ENAB_READ
: R4030_DMA_ENAB_WRITE
));
423 asc_dma_go(struct ncr53c9x_softc
*sc
)
425 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
427 /* No DMA transfer in Transfer Pad operation */
428 if (asc
->sc_dmasize
== 0)
435 asc_dma_stop(struct ncr53c9x_softc
*sc
)
437 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
440 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_ENAB
, 0);
441 bus_space_write_4(asc
->sc_iot
, asc
->sc_dmaioh
, R4030_DMA_MODE
, 0);
443 bus_dmamap_unload(asc
->sc_dmat
, asc
->sc_dmamap
);
449 asc_dma_isactive(struct ncr53c9x_softc
*sc
)
451 struct asc_softc
*asc
= (struct asc_softc
*)sc
;
453 return asc
->sc_active
;