1 /* $NetBSD: njs_cardbus.c,v 1.10 2008/07/09 19:08:44 joerg Exp $ */
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: njs_cardbus.c,v 1.10 2008/07/09 19:08:44 joerg Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
43 #include <dev/scsipi/scsi_all.h>
44 #include <dev/scsipi/scsipi_all.h>
45 #include <dev/scsipi/scsiconf.h>
47 #include <dev/cardbus/cardbusvar.h>
48 #include <dev/pci/pcidevs.h>
50 #include <dev/ic/ninjascsi32reg.h>
51 #include <dev/ic/ninjascsi32var.h>
53 #define NJSC32_CARDBUS_BASEADDR_IO CARDBUS_BASE0_REG
54 #define NJSC32_CARDBUS_BASEADDR_MEM CARDBUS_BASE1_REG
56 struct njsc32_cardbus_softc
{
57 struct njsc32_softc sc_njsc32
;
59 /* CardBus-specific goo */
60 cardbus_devfunc_t sc_ct
; /* our CardBus devfuncs */
61 cardbus_intr_line_t sc_intrline
; /* our interrupt line */
64 bus_space_handle_t sc_regmaph
;
65 bus_size_t sc_regmap_size
;
68 static int njs_cardbus_match(device_t
, cfdata_t
, void *);
69 static void njs_cardbus_attach(device_t
, device_t
, void *);
70 static int njs_cardbus_detach(device_t
, int);
72 CFATTACH_DECL_NEW(njs_cardbus
, sizeof(struct njsc32_cardbus_softc
),
73 njs_cardbus_match
, njs_cardbus_attach
, njs_cardbus_detach
, NULL
);
75 static const struct njsc32_cardbus_product
{
76 cardbus_vendor_id_t p_vendor
;
77 cardbus_product_id_t p_product
;
78 njsc32_model_t p_model
;
79 int p_clk
; /* one of NJSC32_CLK_* */
80 } njsc32_cardbus_products
[] = {
81 { PCI_VENDOR_IODATA
, PCI_PRODUCT_IODATA_CBSCII
,
82 NJSC32_MODEL_32BI
, NJSC32_CLK_40M
},
83 { PCI_VENDOR_WORKBIT
, PCI_PRODUCT_WORKBIT_NJSC32BI
,
84 NJSC32_MODEL_32BI
, NJSC32_CLK_40M
},
85 { PCI_VENDOR_WORKBIT
, PCI_PRODUCT_WORKBIT_NJSC32UDE
,
86 NJSC32_MODEL_32UDE
| NJSC32_FLAG_DUALEDGE
, NJSC32_CLK_40M
},
87 { PCI_VENDOR_WORKBIT
, PCI_PRODUCT_WORKBIT_NJSC32BI_KME
,
88 NJSC32_MODEL_32BI
, NJSC32_CLK_40M
},
91 NJSC32_MODEL_INVALID
, 0 },
94 static const struct njsc32_cardbus_product
*
95 njs_cardbus_lookup(const struct cardbus_attach_args
*ca
)
97 const struct njsc32_cardbus_product
*p
;
99 for (p
= njsc32_cardbus_products
;
100 p
->p_model
!= NJSC32_MODEL_INVALID
; p
++) {
101 if (CARDBUS_VENDOR(ca
->ca_id
) == p
->p_vendor
&&
102 CARDBUS_PRODUCT(ca
->ca_id
) == p
->p_product
)
110 njs_cardbus_match(device_t parent
, cfdata_t match
, void *aux
)
112 struct cardbus_attach_args
*ca
= aux
;
114 if (njs_cardbus_lookup(ca
))
121 njs_cardbus_attach(device_t parent
, device_t self
, void *aux
)
123 struct cardbus_attach_args
*ca
= aux
;
124 struct njsc32_cardbus_softc
*csc
= device_private(self
);
125 struct njsc32_softc
*sc
= &csc
->sc_njsc32
;
126 const struct njsc32_cardbus_product
*prod
;
127 cardbus_devfunc_t ct
= ca
->ca_ct
;
128 cardbus_chipset_tag_t cc
= ct
->ct_cc
;
129 cardbus_function_tag_t cf
= ct
->ct_cf
;
132 u_int8_t latency
= 0x20;
134 if ((prod
= njs_cardbus_lookup(ca
)) == NULL
)
135 panic("njs_cardbus_attach");
137 printf(": Workbit NinjaSCSI-32 SCSI adapter\n");
139 sc
->sc_model
= prod
->p_model
;
140 sc
->sc_clk
= prod
->p_clk
;
143 csc
->sc_tag
= ca
->ca_tag
;
144 csc
->sc_intrline
= ca
->ca_intrline
;
149 csr
= PCI_COMMAND_MASTER_ENABLE
;
153 * Try memory map first, and then try I/O.
155 if (Cardbus_mapreg_map(csc
->sc_ct
, NJSC32_CARDBUS_BASEADDR_MEM
,
156 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT
, 0,
157 &sc
->sc_regt
, &csc
->sc_regmaph
, NULL
, &csc
->sc_regmap_size
) == 0) {
158 if (bus_space_subregion(sc
->sc_regt
, csc
->sc_regmaph
,
159 NJSC32_MEMOFFSET_REG
, NJSC32_REGSIZE
, &sc
->sc_regh
) != 0) {
160 /* failed -- undo map and try I/O */
161 Cardbus_mapreg_unmap(csc
->sc_ct
,
162 NJSC32_CARDBUS_BASEADDR_MEM
,
163 sc
->sc_regt
, csc
->sc_regmaph
, csc
->sc_regmap_size
);
167 printf("%s: memory space mapped\n", device_xname(self
));
169 csr
|= PCI_COMMAND_MEM_ENABLE
;
170 sc
->sc_flags
= NJSC32_MEM_MAPPED
;
171 (*ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_MEM_ENABLE
);
174 if (Cardbus_mapreg_map(csc
->sc_ct
, NJSC32_CARDBUS_BASEADDR_IO
,
175 PCI_MAPREG_TYPE_IO
, 0, &sc
->sc_regt
, &sc
->sc_regh
,
176 NULL
, &csc
->sc_regmap_size
) == 0) {
178 printf("%s: io space mapped\n", device_xname(self
));
180 csr
|= PCI_COMMAND_IO_ENABLE
;
181 sc
->sc_flags
= NJSC32_IO_MAPPED
;
182 (*ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_IO_ENABLE
);
184 aprint_error_dev(self
, "unable to map device registers\n");
189 /* Make sure the right access type is on the CardBus bridge. */
190 (*ct
->ct_cf
->cardbus_ctrl
)(cc
, CARDBUS_BM_ENABLE
);
192 /* Enable the appropriate bits in the PCI CSR. */
193 reg
= cardbus_conf_read(cc
, cf
, ca
->ca_tag
, PCI_COMMAND_STATUS_REG
);
194 reg
&= ~(PCI_COMMAND_IO_ENABLE
|PCI_COMMAND_MEM_ENABLE
);
196 cardbus_conf_write(cc
, cf
, ca
->ca_tag
, PCI_COMMAND_STATUS_REG
, reg
);
199 * Make sure the latency timer is set to some reasonable
202 reg
= cardbus_conf_read(cc
, cf
, ca
->ca_tag
, CARDBUS_BHLC_REG
);
203 if (CARDBUS_LATTIMER(reg
) < latency
) {
204 reg
&= ~(CARDBUS_LATTIMER_MASK
<< CARDBUS_LATTIMER_SHIFT
);
205 reg
|= (latency
<< CARDBUS_LATTIMER_SHIFT
);
206 cardbus_conf_write(cc
, cf
, ca
->ca_tag
, CARDBUS_BHLC_REG
, reg
);
209 sc
->sc_dmat
= ca
->ca_dmat
;
212 * Establish the interrupt.
214 sc
->sc_ih
= cardbus_intr_establish(cc
, cf
, ca
->ca_intrline
, IPL_BIO
,
216 if (sc
->sc_ih
== NULL
) {
217 aprint_error_dev(self
,
218 "unable to establish interrupt\n");
222 /* CardBus device cannot supply termination power. */
223 sc
->sc_flags
|= NJSC32_CANNOT_SUPPLY_TERMPWR
;
230 njs_cardbus_detach(device_t self
, int flags
)
232 struct njsc32_cardbus_softc
*csc
= device_private(self
);
233 struct njsc32_softc
*sc
= &csc
->sc_njsc32
;
236 rv
= njsc32_detach(sc
, flags
);
241 cardbus_intr_disestablish(csc
->sc_ct
->ct_cc
,
242 csc
->sc_ct
->ct_cf
, sc
->sc_ih
);
244 if (sc
->sc_flags
& NJSC32_IO_MAPPED
)
245 Cardbus_mapreg_unmap(csc
->sc_ct
, NJSC32_CARDBUS_BASEADDR_IO
,
246 sc
->sc_regt
, sc
->sc_regh
, csc
->sc_regmap_size
);
247 if (sc
->sc_flags
& NJSC32_MEM_MAPPED
)
248 Cardbus_mapreg_unmap(csc
->sc_ct
, NJSC32_CARDBUS_BASEADDR_MEM
,
249 sc
->sc_regt
, csc
->sc_regmaph
, csc
->sc_regmap_size
);