1/*	$NetBSD: asc.c,v 1.23 2008/05/14 13:29:27 tsutsui Exp $	*/
2
3/*-
4 * Copyright (c) 2003 Izumi Tsutsui.  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 ``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.
25 */
26
27#include <sys/cdefs.h>
28__KERNEL_RCSID(0, "$NetBSD: asc.c,v 1.23 2008/05/14 13:29:27 tsutsui Exp $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/device.h>
33#include <sys/buf.h>
34
35#include <machine/autoconf.h>
36#include <sys/bus.h>
37
38#include <uvm/uvm_extern.h>
39
40#include <dev/scsipi/scsipi_all.h>
41#include <dev/scsipi/scsi_all.h>
42#include <dev/scsipi/scsiconf.h>
43
44#include <arc/jazz/jazziovar.h>
45#include <arc/jazz/dma.h>
46#include <arc/jazz/pica.h>
47
48#include <dev/ic/ncr53c9xreg.h>
49#include <dev/ic/ncr53c9xvar.h>
50
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? */
54
55struct asc_softc {
56	struct ncr53c9x_softc sc_ncr53c9x;	/* glue to MI code */
57
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 */
61
62	bus_dma_tag_t sc_dmat;		/* DMA tag */
63	bus_dmamap_t sc_dmamap;		/* DMA map for transfers */
64
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 */
70};
71
72/*
73 * Autoconfiguration data for config.
74 */
75int asc_match(device_t, cfdata_t, void *);
76void asc_attach(device_t, device_t, void *);
77
78CFATTACH_DECL_NEW(asc, sizeof(struct asc_softc),
79    asc_match, asc_attach, NULL, NULL);
80
81static void asc_minphys(struct buf *);
82
83/*
84 *  Functions and the switch for the MI code.
85 */
86uint8_t asc_read_reg(struct ncr53c9x_softc *, int);
87void asc_write_reg(struct ncr53c9x_softc *, int, uint8_t);
88int asc_dma_isintr(struct ncr53c9x_softc *);
89void asc_dma_reset(struct ncr53c9x_softc *);
90int asc_dma_intr(struct ncr53c9x_softc *);
91int asc_dma_setup(struct ncr53c9x_softc *, uint8_t **, size_t *, int, size_t *);
92void asc_dma_go(struct ncr53c9x_softc *);
93void asc_dma_stop(struct ncr53c9x_softc *);
94int asc_dma_isactive(struct ncr53c9x_softc *);
95
96struct ncr53c9x_glue asc_glue = {
97	asc_read_reg,
98	asc_write_reg,
99	asc_dma_isintr,
100	asc_dma_reset,
101	asc_dma_intr,
102	asc_dma_setup,
103	asc_dma_go,
104	asc_dma_stop,
105	asc_dma_isactive,
106	NULL			/* gl_clear_latched_intr */
107};
108
109/*
110 * Match driver based on name
111 */
112int
113asc_match(device_t parent, cfdata_t cf, void *aux)
114{
115	struct jazzio_attach_args *ja = aux;
116
117	if (strcmp(ja->ja_name, "ESP216") != 0)
118		return 0;
119	return 1;
120}
121
122void
123asc_attach(device_t parent, device_t self, void *aux)
124{
125	struct asc_softc *asc = device_private(self);
126	struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x;
127	struct jazzio_attach_args *ja = aux;
128	bus_space_tag_t iot;
129	uint8_t asc_id;
130
131#if 0
132	/* Need info from platform dependent config?? */
133	if (asc_conf == NULL)
134		panic("asc_conf isn't initialized");
135#endif
136
137	sc->sc_dev = self;
138	sc->sc_glue = &asc_glue;
139
140	asc->sc_iot = iot = ja->ja_bust;
141	asc->sc_dmat = ja->ja_dmat;
142
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");
145		return;
146	}
147
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");
151		goto out1;
152	}
153
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");
157		goto out2;
158	}
159
160	/*
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...
164	 */
165
166	/*
167	 * Set up static configuration info.
168	 */
169	sc->sc_id = 7; /* XXX should be taken from ARC BIOS */
170	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
171
172	/* identify 53CF9x-2 or not */
173	asc_write_reg(sc, NCR_CMD, NCRCMD_RSTCHIP);
174	DELAY(25);
175	asc_write_reg(sc, NCR_CMD, NCRCMD_DMA | NCRCMD_NOP);
176	DELAY(25);
177	asc_write_reg(sc, NCR_CFG2, NCRCFG2_FE);
178	DELAY(25);
179	asc_write_reg(sc, NCR_CMD, NCRCMD_DMA | NCRCMD_NOP);
180	DELAY(25);
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;
191	} else {
192		sc->sc_rev = NCR_VARIANT_NCR53C94;
193		sc->sc_freq = 25; /* MHz */
194		sc->sc_maxxfer = 64 * 1024;
195	}
196
197	/*
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.
201	 */
202
203	/*
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
211	 */
212	sc->sc_minsync = 1000 / sc->sc_freq;
213
214	/* establish interrupt */
215	jazzio_intr_establish(ja->ja_intr, ncr53c9x_intr, asc);
216
217	/* Do the common parts of attachment. */
218	sc->sc_adapter.adapt_minphys = asc_minphys;
219	sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
220	ncr53c9x_attach(sc);
221
222#if 0
223	/* Turn on target selection using the `DMA' method */
224	sc->sc_features |= NCR_F_DMASELECT;
225#endif
226	return;
227
228 out2:
229	bus_space_unmap(iot, asc->sc_dmaioh, R4030_DMA_RANGE);
230 out1:
231	bus_space_unmap(iot, asc->sc_ioh, ASC_NPORTS);
232}
233
234
235static void
236asc_minphys(struct buf *bp)
237{
238
239#define ASC_MAX_XFER	(32 * 1024)	/* XXX can't xfer 64kbytes? */
240
241	if (bp->b_bcount > ASC_MAX_XFER)
242		bp->b_bcount = ASC_MAX_XFER;
243	minphys(bp);
244}
245
246/*
247 * Glue functions.
248 */
249
250uint8_t
251asc_read_reg(struct ncr53c9x_softc *sc, int reg)
252{
253	struct asc_softc *asc = (struct asc_softc *)sc;
254
255	return bus_space_read_1(asc->sc_iot, asc->sc_ioh, reg);
256}
257
258void
259asc_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val)
260{
261	struct asc_softc *asc = (struct asc_softc *)sc;
262
263	bus_space_write_1(asc->sc_iot, asc->sc_ioh, reg, val);
264}
265
266int
267asc_dma_isintr(struct ncr53c9x_softc *sc)
268{
269
270	return asc_read_reg(sc, NCR_STAT) & NCRSTAT_INT;
271}
272
273void
274asc_dma_reset(struct ncr53c9x_softc *sc)
275{
276	struct asc_softc *asc = (struct asc_softc *)sc;
277
278	/* halt DMA */
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);
281}
282
283int
284asc_dma_intr(struct ncr53c9x_softc *sc)
285{
286	struct asc_softc *asc = (struct asc_softc *)sc;
287	int datain, resid, trans;
288
289	datain = asc->sc_datain;
290
291#ifdef DIAGNOSTIC
292	/* This is an "assertion" :) */
293	if (asc->sc_active == 0)
294		panic("%s: DMA wasn't active", __func__);
295#endif
296
297	/* DMA has stopped */
298
299	asc->sc_active = 0;
300
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)));
308
309		return 0;
310	}
311
312	resid = 0;
313
314	/*
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.
319	 */
320	if (!datain &&
321	    (resid = (asc_read_reg(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
322		NCR_DMA(("asc_dma_intr: empty asc FIFO of %d ", resid));
323	}
324
325	if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
326		/*
327		 * `Terminal count' is off, so read the residue
328		 * out of the ASC counter registers.
329		 */
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));
334
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' */
338			resid = 65536;
339	}
340
341	/* halt DMA */
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);
345
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);
350
351	trans = asc->sc_dmasize - resid;
352
353	if (trans < 0) {		/* transfered < 0 ? */
354#if 0
355		/*
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.
359		 */
360		printf("%s: xfer (%d) > req (%d)\n",
361		    sc->sc_dev.dv_xname, trans, asc->sc_dmasize);
362#endif
363		trans = asc->sc_dmasize;
364	}
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,
369	    trans, resid));
370
371	*asc->sc_dmalen -= trans;
372	*asc->sc_dmaaddr += trans;
373
374	return 0;
375}
376
377int
378asc_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len,
379    int datain, size_t *dmasize)
380{
381	struct asc_softc *asc = (struct asc_softc *)sc;
382
383	/* halt DMA */
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);
386
387	asc->sc_dmaaddr = addr;
388	asc->sc_dmalen = len;
389	asc->sc_dmasize = *dmasize;
390	asc->sc_datain = datain;
391
392	/*
393	 * No need to set up DMA in `Transfer Pad' operation.
394	 */
395	if (*dmasize == 0)
396		return 0;
397
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);
405
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);
413
414	/* start DMA */
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));
418
419	return 0;
420}
421
422void
423asc_dma_go(struct ncr53c9x_softc *sc)
424{
425	struct asc_softc *asc = (struct asc_softc *)sc;
426
427	/* No DMA transfer in Transfer Pad operation */
428	if (asc->sc_dmasize == 0)
429		return;
430
431	asc->sc_active = 1;
432}
433
434void
435asc_dma_stop(struct ncr53c9x_softc *sc)
436{
437	struct asc_softc *asc = (struct asc_softc *)sc;
438
439	/* halt DMA */
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);
442
443	bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
444
445	asc->sc_active = 0;
446}
447
448int
449asc_dma_isactive(struct ncr53c9x_softc *sc)
450{
451	struct asc_softc *asc = (struct asc_softc *)sc;
452
453	return asc->sc_active;
454}
455