xref: /netbsd/sys/dev/cardbus/adv_cardbus.c (revision c4a72b64)
1 /*	$NetBSD: adv_cardbus.c,v 1.8 2002/10/02 16:33:39 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * this file was brought from ahc_cardbus.c and adv_pci.c
42  * and modified by YAMAMOTO Takashi.
43  */
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: adv_cardbus.c,v 1.8 2002/10/02 16:33:39 thorpej Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/malloc.h>
51 #include <sys/kernel.h>
52 #include <sys/queue.h>
53 #include <sys/device.h>
54 
55 #include <machine/bus.h>
56 #include <machine/intr.h>
57 
58 #include <dev/scsipi/scsi_all.h>
59 #include <dev/scsipi/scsipi_all.h>
60 #include <dev/scsipi/scsiconf.h>
61 
62 #include <dev/pci/pcireg.h>
63 #include <dev/pci/pcidevs.h>
64 
65 #include <dev/cardbus/cardbusvar.h>
66 #include <dev/cardbus/cardbusdevs.h>
67 
68 #include <dev/ic/advlib.h>
69 #include <dev/ic/adv.h>
70 
71 #define ADV_CARDBUS_IOBA CARDBUS_BASE0_REG
72 #define ADV_CARDBUS_MMBA CARDBUS_BASE1_REG
73 
74 #define ADV_CARDBUS_DEBUG
75 #define ADV_CARDBUS_ALLOW_MEMIO
76 
77 #define DEVNAME(sc) sc->sc_dev.dv_xname
78 
79 struct adv_cardbus_softc {
80 	struct asc_softc sc_adv;	/* real ADV */
81 
82 	/* CardBus-specific goo. */
83 	cardbus_devfunc_t sc_ct;	/* our CardBus devfuncs */
84 	int	sc_intrline;		/* our interrupt line */
85 	cardbustag_t sc_tag;
86 
87 	int	sc_cbenable;		/* what CardBus access type to enable */
88 	int	sc_csr;			/* CSR bits */
89 	bus_size_t sc_size;
90 };
91 
92 int	adv_cardbus_match __P((struct device *, struct cfdata *, void *));
93 void	adv_cardbus_attach __P((struct device *, struct device *, void *));
94 int	adv_cardbus_detach __P((struct device *, int));
95 
96 CFATTACH_DECL(adv_cardbus, sizeof(struct adv_cardbus_softc),
97     adv_cardbus_match, adv_cardbus_attach, adv_cardbus_detach, NULL);
98 
99 int
100 adv_cardbus_match(parent, match, aux)
101 	struct device *parent;
102 	struct cfdata *match;
103 	void *aux;
104 {
105 	struct cardbus_attach_args *ca = aux;
106 
107 	if (CARDBUS_VENDOR(ca->ca_id) == CARDBUS_VENDOR_ADVSYS &&
108 	    CARDBUS_PRODUCT(ca->ca_id) == CARDBUS_PRODUCT_ADVSYS_ULTRA)
109 		return (1);
110 
111 	return (0);
112 }
113 
114 void
115 adv_cardbus_attach(parent, self, aux)
116 	struct device *parent, *self;
117 	void *aux;
118 {
119 	struct cardbus_attach_args *ca = aux;
120 	struct adv_cardbus_softc *csc = (void *) self;
121 	struct asc_softc *sc = &csc->sc_adv;
122 	cardbus_devfunc_t ct = ca->ca_ct;
123 	cardbus_chipset_tag_t cc = ct->ct_cc;
124 	cardbus_function_tag_t cf = ct->ct_cf;
125 	bus_space_tag_t iot;
126 	bus_space_handle_t ioh;
127 	pcireg_t reg;
128 	u_int8_t latency = 0x20;
129 
130 	sc->sc_flags = 0;
131 
132 	if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_ADVSYS) {
133 		switch (PCI_PRODUCT(ca->ca_id)) {
134 		case PCI_PRODUCT_ADVSYS_1200A:
135 			printf(": AdvanSys ASC1200A SCSI adapter\n");
136 			latency = 0;
137 			break;
138 
139 		case PCI_PRODUCT_ADVSYS_1200B:
140 			printf(": AdvanSys ASC1200B SCSI adapter\n");
141 			latency = 0;
142 			break;
143 
144 		case PCI_PRODUCT_ADVSYS_ULTRA:
145 			switch (PCI_REVISION(ca->ca_class)) {
146 			case ASC_PCI_REVISION_3050:
147 				printf(": AdvanSys ABP-9xxUA SCSI adapter\n");
148 				break;
149 
150 			case ASC_PCI_REVISION_3150:
151 				printf(": AdvanSys ABP-9xxU SCSI adapter\n");
152 				break;
153 			}
154 			break;
155 
156 		default:
157 			printf(": unknown model!\n");
158 			return;
159 		}
160 	}
161 
162 	csc->sc_ct = ct;
163 	csc->sc_tag = ca->ca_tag;
164 	csc->sc_intrline = ca->ca_intrline;
165 	csc->sc_cbenable = 0;
166 
167 	/*
168 	 * Map the device.
169 	 */
170 	csc->sc_csr = PCI_COMMAND_MASTER_ENABLE;
171 
172 #ifdef ADV_CARDBUS_ALLOW_MEMIO
173 	if (Cardbus_mapreg_map(csc->sc_ct, ADV_CARDBUS_MMBA,
174 	    PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
175 	    &iot, &ioh, NULL, &csc->sc_size) == 0) {
176 #ifdef ADV_CARDBUS_DEBUG
177 		printf("%s: memio enabled\n", DEVNAME(sc));
178 #endif
179 		csc->sc_cbenable = CARDBUS_MEM_ENABLE;
180 		csc->sc_csr |= PCI_COMMAND_MEM_ENABLE;
181 	} else
182 #endif
183 	if (Cardbus_mapreg_map(csc->sc_ct, ADV_CARDBUS_IOBA,
184 	    PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, &csc->sc_size) == 0) {
185 #ifdef ADV_CARDBUS_DEBUG
186 		printf("%s: io enabled\n", DEVNAME(sc));
187 #endif
188 		csc->sc_cbenable = CARDBUS_IO_ENABLE;
189 		csc->sc_csr |= PCI_COMMAND_IO_ENABLE;
190 	} else {
191 		printf("%s: unable to map device registers\n",
192 		    DEVNAME(sc));
193 		return;
194 	}
195 
196 	/* Make sure the right access type is on the CardBus bridge. */
197 	(*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cbenable);
198 	(*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
199 
200 	/* Enable the appropriate bits in the PCI CSR. */
201 	reg = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG);
202 	reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE);
203 	reg |= csc->sc_csr;
204 	cardbus_conf_write(cc, cf, ca->ca_tag, PCI_COMMAND_STATUS_REG, reg);
205 
206 	/*
207 	 * Make sure the latency timer is set to some reasonable
208 	 * value.
209 	 */
210 	reg = cardbus_conf_read(cc, cf, ca->ca_tag, PCI_BHLC_REG);
211 	if (PCI_LATTIMER(reg) < latency) {
212 		reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT);
213 		reg |= (latency << PCI_LATTIMER_SHIFT);
214 		cardbus_conf_write(cc, cf, ca->ca_tag, PCI_BHLC_REG, reg);
215 	}
216 
217 	ASC_SET_CHIP_CONTROL(iot, ioh, ASC_CC_HALT);
218 	ASC_SET_CHIP_STATUS(iot, ioh, 0);
219 
220 	sc->sc_iot = iot;
221 	sc->sc_ioh = ioh;
222 	sc->sc_dmat = ca->ca_dmat;
223 	sc->pci_device_id = ca->ca_id;
224 	sc->bus_type = ASC_IS_PCI;
225 	sc->chip_version = ASC_GET_CHIP_VER_NO(iot, ioh);
226 
227 	/*
228 	 * Initialize the board
229 	 */
230 	if (adv_init(sc)) {
231 		printf("adv_init failed\n");
232 		return;
233 	}
234 
235 	/*
236 	 * Establish the interrupt.
237 	 */
238 	sc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline, IPL_BIO,
239 	    adv_intr, sc);
240 	if (sc->sc_ih == NULL) {
241 		printf("%s: unable to establish interrupt at %d\n",
242 		    DEVNAME(sc), ca->ca_intrline);
243 		return;
244 	}
245 	printf("%s: interrupting at %d\n", DEVNAME(sc), ca->ca_intrline);
246 
247 	/*
248 	 * Attach.
249 	 */
250 	adv_attach(sc);
251 }
252 
253 int
254 adv_cardbus_detach(self, flags)
255 	struct device *self;
256 	int flags;
257 {
258 	struct adv_cardbus_softc *csc = (void*)self;
259 	struct asc_softc *sc = &csc->sc_adv;
260 
261 	int rv;
262 
263 	rv = adv_detach(sc, flags);
264 	if (rv)
265 		return rv;
266 
267 	if (sc->sc_ih) {
268 		cardbus_intr_disestablish(csc->sc_ct->ct_cc,
269 		    csc->sc_ct->ct_cf, sc->sc_ih);
270 		sc->sc_ih = 0;
271 	}
272 
273 	if (csc->sc_cbenable) {
274 #ifdef ADV_CARDBUS_ALLOW_MEMIO
275 		if (csc->sc_cbenable == CARDBUS_MEM_ENABLE) {
276 			Cardbus_mapreg_unmap(csc->sc_ct, ADV_CARDBUS_MMBA,
277 			    sc->sc_iot, sc->sc_ioh, csc->sc_size);
278 		} else {
279 #endif
280 			Cardbus_mapreg_unmap(csc->sc_ct, ADV_CARDBUS_IOBA,
281 			    sc->sc_iot, sc->sc_ioh, csc->sc_size);
282 #ifdef ADV_CARDBUS_ALLOW_MEMIO
283 		}
284 #endif
285 		csc->sc_cbenable = 0;
286 	}
287 
288 	return 0;
289 }
290