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