xref: /netbsd-src/sys/arch/sparc/dev/esp_obio.c (revision b6584574fc253d1725f8f78df132828a069a8437)
1*b6584574Sdyoung /*	$NetBSD: esp_obio.c,v 1.24 2011/07/01 18:50:41 dyoung Exp $	*/
2e4091cb7Spk 
3e4091cb7Spk /*-
4e4091cb7Spk  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5e4091cb7Spk  * All rights reserved.
6e4091cb7Spk  *
7e4091cb7Spk  * This code is derived from software contributed to The NetBSD Foundation
8e4091cb7Spk  * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
9e4091cb7Spk  * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
10e4091cb7Spk  *
11e4091cb7Spk  * Redistribution and use in source and binary forms, with or without
12e4091cb7Spk  * modification, are permitted provided that the following conditions
13e4091cb7Spk  * are met:
14e4091cb7Spk  * 1. Redistributions of source code must retain the above copyright
15e4091cb7Spk  *    notice, this list of conditions and the following disclaimer.
16e4091cb7Spk  * 2. Redistributions in binary form must reproduce the above copyright
17e4091cb7Spk  *    notice, this list of conditions and the following disclaimer in the
18e4091cb7Spk  *    documentation and/or other materials provided with the distribution.
19e4091cb7Spk  *
20e4091cb7Spk  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21e4091cb7Spk  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22e4091cb7Spk  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23e4091cb7Spk  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24e4091cb7Spk  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25e4091cb7Spk  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26e4091cb7Spk  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27e4091cb7Spk  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28e4091cb7Spk  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29e4091cb7Spk  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30e4091cb7Spk  * POSSIBILITY OF SUCH DAMAGE.
31e4091cb7Spk  */
32e4091cb7Spk 
33a4183603Slukem #include <sys/cdefs.h>
34*b6584574Sdyoung __KERNEL_RCSID(0, "$NetBSD: esp_obio.c,v 1.24 2011/07/01 18:50:41 dyoung Exp $");
35a4183603Slukem 
36e4091cb7Spk #include <sys/types.h>
37e4091cb7Spk #include <sys/param.h>
38e4091cb7Spk #include <sys/systm.h>
39e4091cb7Spk #include <sys/kernel.h>
40e4091cb7Spk #include <sys/errno.h>
41e4091cb7Spk #include <sys/device.h>
42e4091cb7Spk #include <sys/buf.h>
43e4091cb7Spk 
44e4091cb7Spk #include <dev/scsipi/scsi_all.h>
45e4091cb7Spk #include <dev/scsipi/scsipi_all.h>
46e4091cb7Spk #include <dev/scsipi/scsiconf.h>
47e4091cb7Spk #include <dev/scsipi/scsi_message.h>
48e4091cb7Spk 
49*b6584574Sdyoung #include <sys/bus.h>
50e4091cb7Spk #include <machine/autoconf.h>
51406e0f77Spk #include <machine/intr.h>
52e4091cb7Spk 
53e4091cb7Spk #include <dev/ic/lsi64854reg.h>
54e4091cb7Spk #include <dev/ic/lsi64854var.h>
55e4091cb7Spk 
56e4091cb7Spk #include <dev/ic/ncr53c9xreg.h>
57e4091cb7Spk #include <dev/ic/ncr53c9xvar.h>
58e4091cb7Spk 
59e4091cb7Spk #include <dev/sbus/sbusvar.h>
60e4091cb7Spk 
61e4091cb7Spk struct esp_softc {
62e4091cb7Spk 	struct ncr53c9x_softc sc_ncr53c9x;	/* glue to MI code */
63e4091cb7Spk 	bus_space_tag_t		sc_bustag;
64e4091cb7Spk 	bus_dma_tag_t		sc_dmatag;
65e4091cb7Spk 	bus_space_handle_t	sc_reg;		/* the registers */
66e4091cb7Spk 	struct lsi64854_softc	*sc_dma;	/* pointer to my dma */
67e4091cb7Spk };
68e4091cb7Spk 
69e4091cb7Spk 
7078a1d236Stsutsui int	espmatch_obio(device_t, cfdata_t, void *);
7178a1d236Stsutsui void	espattach_obio(device_t, device_t, void *);
72e4091cb7Spk 
73e4091cb7Spk /* Linkup to the rest of the kernel */
7478a1d236Stsutsui CFATTACH_DECL_NEW(esp_obio, sizeof(struct esp_softc),
754bf871a7Sthorpej     espmatch_obio, espattach_obio, NULL, NULL);
76e4091cb7Spk 
77e4091cb7Spk /*
78e4091cb7Spk  * Functions and the switch for the MI code.
79e4091cb7Spk  */
8078a1d236Stsutsui static uint8_t	esp_read_reg(struct ncr53c9x_softc *, int);
8178a1d236Stsutsui static void	esp_write_reg(struct ncr53c9x_softc *, int, uint8_t);
8260ed1ea4Suwe static int	esp_dma_isintr(struct ncr53c9x_softc *);
8360ed1ea4Suwe static void	esp_dma_reset(struct ncr53c9x_softc *);
8460ed1ea4Suwe static int	esp_dma_intr(struct ncr53c9x_softc *);
8578a1d236Stsutsui static int	esp_dma_setup(struct ncr53c9x_softc *, uint8_t **,
8660ed1ea4Suwe 				    size_t *, int, size_t *);
8760ed1ea4Suwe static void	esp_dma_go(struct ncr53c9x_softc *);
8860ed1ea4Suwe static void	esp_dma_stop(struct ncr53c9x_softc *);
8960ed1ea4Suwe static int	esp_dma_isactive(struct ncr53c9x_softc *);
90e4091cb7Spk 
91e4091cb7Spk static struct ncr53c9x_glue esp_obio_glue = {
92e4091cb7Spk 	esp_read_reg,
93e4091cb7Spk 	esp_write_reg,
94e4091cb7Spk 	esp_dma_isintr,
95e4091cb7Spk 	esp_dma_reset,
96e4091cb7Spk 	esp_dma_intr,
97e4091cb7Spk 	esp_dma_setup,
98e4091cb7Spk 	esp_dma_go,
99e4091cb7Spk 	esp_dma_stop,
100e4091cb7Spk 	esp_dma_isactive,
101e4091cb7Spk 	NULL,			/* gl_clear_latched_intr */
102e4091cb7Spk };
103e4091cb7Spk 
104e4091cb7Spk int
espmatch_obio(device_t parent,cfdata_t cf,void * aux)10578a1d236Stsutsui espmatch_obio(device_t parent, cfdata_t cf, void *aux)
106e4091cb7Spk {
107e4091cb7Spk 	union obio_attach_args *uoba = aux;
108e4091cb7Spk 	struct obio4_attach_args *oba;
109e4091cb7Spk 
110e4091cb7Spk 	if (uoba->uoba_isobio4 == 0)
11178a1d236Stsutsui 		return 0;
112e4091cb7Spk 
113e4091cb7Spk 	oba = &uoba->uoba_oba4;
11478a1d236Stsutsui 	return bus_space_probe(oba->oba_bustag, oba->oba_paddr,
115e4091cb7Spk 				1,	/* probe size */
116e4091cb7Spk 				0,	/* offset */
117e4091cb7Spk 				0,	/* flags */
11878a1d236Stsutsui 				NULL, NULL);
119e4091cb7Spk }
120e4091cb7Spk 
121e4091cb7Spk void
espattach_obio(device_t parent,device_t self,void * aux)12278a1d236Stsutsui espattach_obio(device_t parent, device_t self, void *aux)
123e4091cb7Spk {
12478a1d236Stsutsui 	struct esp_softc *esc = device_private(self);
12578a1d236Stsutsui 	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
126e4091cb7Spk 	union obio_attach_args *uoba = aux;
127e4091cb7Spk 	struct obio4_attach_args *oba = &uoba->uoba_oba4;
12878a1d236Stsutsui 	device_t dma_dev;
12978a1d236Stsutsui 
13078a1d236Stsutsui 	sc->sc_dev = self;
131e4091cb7Spk 
132e4091cb7Spk 	esc->sc_bustag = oba->oba_bustag;
133e4091cb7Spk 	esc->sc_dmatag = oba->oba_dmatag;
134e4091cb7Spk 
135e4091cb7Spk 	sc->sc_id = 7;
136e4091cb7Spk 	sc->sc_freq = 24000000;
137e4091cb7Spk 
138e4091cb7Spk 	/*
139e69482d4Sjoerg 	 * Find the DMA by poking around the dma device structures and
140e69482d4Sjoerg 	 * set the reverse pointer.
141e4091cb7Spk 	 */
142e69482d4Sjoerg 	dma_dev = device_find_by_driver_unit("dma", device_unit(self));
143e69482d4Sjoerg 	if (dma_dev == NULL)
144e69482d4Sjoerg 		panic("%s: no corresponding DMA device", device_xname(self));
145e69482d4Sjoerg 	esc->sc_dma = device_private(dma_dev);
146fe6b9295Spk 	esc->sc_dma->sc_client = sc;
147e4091cb7Spk 
1487e8becd6Spk 	if (bus_space_map(oba->oba_bustag, oba->oba_paddr,
149e4091cb7Spk 			  16,	/* size (of ncr53c9xreg) */
150e4091cb7Spk 			  BUS_SPACE_MAP_LINEAR,
1517e8becd6Spk 			  &esc->sc_reg) != 0) {
15278a1d236Stsutsui 		aprint_error(": cannot map registers\n");
153e4091cb7Spk 		return;
154e4091cb7Spk 	}
155e4091cb7Spk 
156e4091cb7Spk 	/*
157e4091cb7Spk 	 * Set up glue for MI code early; we use some of it here.
158e4091cb7Spk 	 */
159e4091cb7Spk 	sc->sc_glue = &esp_obio_glue;
160e4091cb7Spk 
161a1f606d3Slukem 	/* gimme MHz */
162e4091cb7Spk 	sc->sc_freq /= 1000000;
163e4091cb7Spk 
164e4091cb7Spk 	/*
165e4091cb7Spk 	 * XXX More of this should be in ncr53c9x_attach(), but
166e4091cb7Spk 	 * XXX should we really poke around the chip that much in
167e4091cb7Spk 	 * XXX the MI code?  Think about this more...
168e4091cb7Spk 	 */
169e4091cb7Spk 
170e4091cb7Spk 	/*
171e4091cb7Spk 	 * It is necessary to try to load the 2nd config register here,
172e4091cb7Spk 	 * to find out what rev the esp chip is, else the ncr53c9x_reset
173e4091cb7Spk 	 * will not set up the defaults correctly.
174e4091cb7Spk 	 */
175e4091cb7Spk 	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
176e4091cb7Spk 	sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_RPE;
177e4091cb7Spk 	sc->sc_cfg3 = NCRCFG3_CDB;
178e4091cb7Spk 	NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
179e4091cb7Spk 
180e4091cb7Spk 	if ((NCR_READ_REG(sc, NCR_CFG2) & ~NCRCFG2_RSVD) !=
181e4091cb7Spk 	    (NCRCFG2_SCSI2 | NCRCFG2_RPE)) {
182e4091cb7Spk 		sc->sc_rev = NCR_VARIANT_ESP100;
183e4091cb7Spk 	} else {
184e4091cb7Spk 		sc->sc_cfg2 = NCRCFG2_SCSI2;
185e4091cb7Spk 		NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
186e4091cb7Spk 		sc->sc_cfg3 = 0;
187e4091cb7Spk 		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
188e4091cb7Spk 		sc->sc_cfg3 = (NCRCFG3_CDB | NCRCFG3_FCLK);
189e4091cb7Spk 		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
190e4091cb7Spk 		if (NCR_READ_REG(sc, NCR_CFG3) !=
191e4091cb7Spk 		    (NCRCFG3_CDB | NCRCFG3_FCLK)) {
192e4091cb7Spk 			sc->sc_rev = NCR_VARIANT_ESP100A;
193e4091cb7Spk 		} else {
194e4091cb7Spk 			/* NCRCFG2_FE enables > 64K transfers */
195e4091cb7Spk 			sc->sc_cfg2 |= NCRCFG2_FE;
196e4091cb7Spk 			sc->sc_cfg3 = 0;
197e4091cb7Spk 			NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
198e4091cb7Spk 			sc->sc_rev = NCR_VARIANT_ESP200;
199e4091cb7Spk 		}
200e4091cb7Spk 	}
201e4091cb7Spk 
202e4091cb7Spk 	/*
203e4091cb7Spk 	 * XXX minsync and maxxfer _should_ be set up in MI code,
204e4091cb7Spk 	 * XXX but it appears to have some dependency on what sort
205e4091cb7Spk 	 * XXX of DMA we're hooked up to, etc.
206e4091cb7Spk 	 */
207e4091cb7Spk 
208e4091cb7Spk 	/*
209e4091cb7Spk 	 * This is the value used to start sync negotiations
210e4091cb7Spk 	 * Note that the NCR register "SYNCTP" is programmed
211e4091cb7Spk 	 * in "clocks per byte", and has a minimum value of 4.
212e4091cb7Spk 	 * The SCSI period used in negotiation is one-fourth
213e4091cb7Spk 	 * of the time (in nanoseconds) needed to transfer one byte.
214e4091cb7Spk 	 * Since the chip's clock is given in MHz, we have the following
215e4091cb7Spk 	 * formula: 4 * period = (1000 / freq) * 4
216e4091cb7Spk 	 */
217e4091cb7Spk 	sc->sc_minsync = 1000 / sc->sc_freq;
218e4091cb7Spk 
219e4091cb7Spk 	/*
220e4091cb7Spk 	 * Alas, we must now modify the value a bit, because it's
221e4091cb7Spk 	 * only valid when can switch on FASTCLK and FASTSCSI bits
222e4091cb7Spk 	 * in config register 3...
223e4091cb7Spk 	 */
224e4091cb7Spk 	switch (sc->sc_rev) {
225e4091cb7Spk 	case NCR_VARIANT_ESP100:
226e4091cb7Spk 		sc->sc_maxxfer = 64 * 1024;
227e4091cb7Spk 		sc->sc_minsync = 0;	/* No synch on old chip? */
228e4091cb7Spk 		break;
229e4091cb7Spk 
230e4091cb7Spk 	case NCR_VARIANT_ESP100A:
231e4091cb7Spk 		sc->sc_maxxfer = 64 * 1024;
232e4091cb7Spk 		/* Min clocks/byte is 5 */
233e4091cb7Spk 		sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5);
234e4091cb7Spk 		break;
235e4091cb7Spk 
236e4091cb7Spk 	case NCR_VARIANT_ESP200:
237e4091cb7Spk 		sc->sc_maxxfer = 16 * 1024 * 1024;
238e4091cb7Spk 		/* XXX - do actually set FAST* bits */
239e4091cb7Spk 		break;
240e4091cb7Spk 	}
241e4091cb7Spk 
242e4091cb7Spk 	/* Establish interrupt channel */
243725a6aebSpk 	bus_intr_establish(esc->sc_bustag, oba->oba_pri, IPL_BIO,
244406e0f77Spk 	    ncr53c9x_intr, sc);
245e4091cb7Spk 
246e4091cb7Spk 	/* register interrupt stats */
247cffb5808Scgd 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
24878a1d236Stsutsui 	    device_xname(self), "intr");
249e4091cb7Spk 
250e4091cb7Spk 	/* Do the common parts of attachment. */
251937a7a3eSbouyer 	sc->sc_adapter.adapt_minphys = minphys;
252937a7a3eSbouyer 	sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request;
253937a7a3eSbouyer 	ncr53c9x_attach(sc);
2541c9cc1b0Spetrov 	sc->sc_features |= NCR_F_DMASELECT;
255e4091cb7Spk }
256e4091cb7Spk 
257e4091cb7Spk /*
258e4091cb7Spk  * Glue functions.
259e4091cb7Spk  */
260e4091cb7Spk 
26178a1d236Stsutsui static uint8_t
esp_read_reg(struct ncr53c9x_softc * sc,int reg)26260ed1ea4Suwe esp_read_reg(struct ncr53c9x_softc *sc, int reg)
263e4091cb7Spk {
264e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
265e4091cb7Spk 
26678a1d236Stsutsui 	return bus_space_read_1(esc->sc_bustag, esc->sc_reg, reg * 4);
267e4091cb7Spk }
268e4091cb7Spk 
26960ed1ea4Suwe static void
esp_write_reg(struct ncr53c9x_softc * sc,int reg,uint8_t v)27078a1d236Stsutsui esp_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t v)
271e4091cb7Spk {
272e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
273e4091cb7Spk 
274e4091cb7Spk 	bus_space_write_1(esc->sc_bustag, esc->sc_reg, reg * 4, v);
275e4091cb7Spk }
276e4091cb7Spk 
27760ed1ea4Suwe static int
esp_dma_isintr(struct ncr53c9x_softc * sc)27860ed1ea4Suwe esp_dma_isintr(struct ncr53c9x_softc *sc)
279e4091cb7Spk {
280e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
281e4091cb7Spk 
28278a1d236Stsutsui 	return DMA_ISINTR(esc->sc_dma);
283e4091cb7Spk }
284e4091cb7Spk 
28560ed1ea4Suwe static void
esp_dma_reset(struct ncr53c9x_softc * sc)28660ed1ea4Suwe esp_dma_reset(struct ncr53c9x_softc *sc)
287e4091cb7Spk {
288e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
289e4091cb7Spk 
290e4091cb7Spk 	DMA_RESET(esc->sc_dma);
291e4091cb7Spk }
292e4091cb7Spk 
29360ed1ea4Suwe static int
esp_dma_intr(struct ncr53c9x_softc * sc)29460ed1ea4Suwe esp_dma_intr(struct ncr53c9x_softc *sc)
295e4091cb7Spk {
296e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
297e4091cb7Spk 
29878a1d236Stsutsui 	return DMA_INTR(esc->sc_dma);
299e4091cb7Spk }
300e4091cb7Spk 
30160ed1ea4Suwe static int
esp_dma_setup(struct ncr53c9x_softc * sc,uint8_t ** addr,size_t * len,int datain,size_t * dmasize)30278a1d236Stsutsui esp_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len,
30360ed1ea4Suwe     int datain, size_t *dmasize)
304e4091cb7Spk {
305e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
306e4091cb7Spk 
30778a1d236Stsutsui 	return DMA_SETUP(esc->sc_dma, addr, len, datain, dmasize);
308e4091cb7Spk }
309e4091cb7Spk 
31060ed1ea4Suwe static void
esp_dma_go(struct ncr53c9x_softc * sc)31160ed1ea4Suwe esp_dma_go(struct ncr53c9x_softc *sc)
312e4091cb7Spk {
313e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
314e4091cb7Spk 
315e4091cb7Spk 	DMA_GO(esc->sc_dma);
316e4091cb7Spk }
317e4091cb7Spk 
31860ed1ea4Suwe static void
esp_dma_stop(struct ncr53c9x_softc * sc)31960ed1ea4Suwe esp_dma_stop(struct ncr53c9x_softc *sc)
320e4091cb7Spk {
321e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
32260ed1ea4Suwe 	uint32_t csr;
323e4091cb7Spk 
324e4091cb7Spk 	csr = L64854_GCSR(esc->sc_dma);
325e4091cb7Spk 	csr &= ~D_EN_DMA;
326e4091cb7Spk 	L64854_SCSR(esc->sc_dma, csr);
327e4091cb7Spk }
328e4091cb7Spk 
32960ed1ea4Suwe static int
esp_dma_isactive(struct ncr53c9x_softc * sc)33060ed1ea4Suwe esp_dma_isactive(struct ncr53c9x_softc *sc)
331e4091cb7Spk {
332e4091cb7Spk 	struct esp_softc *esc = (struct esp_softc *)sc;
333e4091cb7Spk 
33478a1d236Stsutsui 	return DMA_ISACTIVE(esc->sc_dma);
335e4091cb7Spk }
336