1 | /* $Id: njata_cardbus.c,v 1.15 2011/08/01 11:20:28 drochner Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2006 ITOH Yasufumi. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
18 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
26 | * THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: njata_cardbus.c,v 1.15 2011/08/01 11:20:28 drochner Exp $" ); |
31 | |
32 | #include <sys/param.h> |
33 | #include <sys/systm.h> |
34 | #include <sys/kernel.h> |
35 | #include <sys/device.h> |
36 | |
37 | #include <sys/bus.h> |
38 | #include <sys/intr.h> |
39 | |
40 | #include <dev/cardbus/cardbusvar.h> |
41 | #include <dev/pci/pcidevs.h> |
42 | |
43 | #include <dev/ata/atavar.h> |
44 | #include <dev/ic/wdcreg.h> |
45 | #include <dev/ic/wdcvar.h> |
46 | |
47 | #include <dev/ic/ninjaata32reg.h> |
48 | #include <dev/ic/ninjaata32var.h> |
49 | |
50 | #define NJATA32_CARDBUS_BASEADDR_IO PCI_BAR0 |
51 | #define NJATA32_CARDBUS_BASEADDR_MEM PCI_BAR1 |
52 | |
53 | struct njata32_cardbus_softc { |
54 | struct njata32_softc sc_njata32; |
55 | |
56 | /* CardBus-specific goo */ |
57 | cardbus_devfunc_t sc_ct; /* our CardBus devfuncs */ |
58 | pcitag_t sc_tag; |
59 | |
60 | bus_space_handle_t sc_regmaph; |
61 | bus_size_t sc_regmap_size; |
62 | }; |
63 | |
64 | static const struct njata32_cardbus_product *njata_cardbus_lookup |
65 | (const struct cardbus_attach_args *); |
66 | static int njata_cardbus_match(device_t, cfdata_t, void *); |
67 | static void njata_cardbus_attach(device_t, device_t, void *); |
68 | static int njata_cardbus_detach(device_t, int); |
69 | |
70 | CFATTACH_DECL_NEW(njata_cardbus, sizeof(struct njata32_cardbus_softc), |
71 | njata_cardbus_match, njata_cardbus_attach, njata_cardbus_detach, NULL); |
72 | |
73 | static const struct njata32_cardbus_product { |
74 | pci_vendor_id_t p_vendor; |
75 | pci_product_id_t p_product; |
76 | uint8_t p_flags; |
77 | #define NJATA32_FL_IOMAP_ONLY 1 /* registers are only in the I/O map */ |
78 | } njata32_cardbus_products[] = { |
79 | { PCI_VENDOR_IODATA, PCI_PRODUCT_IODATA_CBIDE2, |
80 | 0 }, |
81 | { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NJATA32BI, |
82 | 0 }, |
83 | { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NJATA32BI_KME, |
84 | 0 }, |
85 | { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NPATA32_CF32A, |
86 | NJATA32_FL_IOMAP_ONLY }, |
87 | { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NPATA32_CF32A_BUFFALO, |
88 | NJATA32_FL_IOMAP_ONLY }, |
89 | { PCI_VENDOR_WORKBIT, PCI_PRODUCT_WORKBIT_NPATA32_KME, |
90 | NJATA32_FL_IOMAP_ONLY }, |
91 | |
92 | { PCI_VENDOR_INVALID, 0, |
93 | 0 } |
94 | }; |
95 | |
96 | static const struct njata32_cardbus_product * |
97 | njata_cardbus_lookup(const struct cardbus_attach_args *ca) |
98 | { |
99 | const struct njata32_cardbus_product *p; |
100 | |
101 | for (p = njata32_cardbus_products; |
102 | p->p_vendor != PCI_VENDOR_INVALID; p++) { |
103 | if (PCI_VENDOR(ca->ca_id) == p->p_vendor && |
104 | PCI_PRODUCT(ca->ca_id) == p->p_product) |
105 | return p; |
106 | } |
107 | |
108 | return NULL; |
109 | } |
110 | |
111 | static int |
112 | njata_cardbus_match(device_t parent, cfdata_t match, void *aux) |
113 | { |
114 | struct cardbus_attach_args *ca = aux; |
115 | |
116 | if (njata_cardbus_lookup(ca)) |
117 | return 1; |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | static void |
123 | njata_cardbus_attach(device_t parent, device_t self, void *aux) |
124 | { |
125 | struct cardbus_attach_args *ca = aux; |
126 | struct njata32_cardbus_softc *csc = device_private(self); |
127 | struct njata32_softc *sc = &csc->sc_njata32; |
128 | const struct njata32_cardbus_product *prod; |
129 | cardbus_devfunc_t ct = ca->ca_ct; |
130 | pcireg_t reg; |
131 | int csr; |
132 | uint8_t latency = 0x20; |
133 | |
134 | sc->sc_wdcdev.sc_atac.atac_dev = self; |
135 | if ((prod = njata_cardbus_lookup(ca)) == NULL) |
136 | panic("njata_cardbus_attach" ); |
137 | |
138 | aprint_normal(": Workbit NinjaATA-32 IDE controller\n" ); |
139 | |
140 | csc->sc_ct = ct; |
141 | csc->sc_tag = ca->ca_tag; |
142 | |
143 | /* |
144 | * Map the device. |
145 | */ |
146 | csr = PCI_COMMAND_MASTER_ENABLE; |
147 | |
148 | /* |
149 | * Map registers. |
150 | * Try memory map first, and then try I/O. |
151 | */ |
152 | if ((prod->p_flags & NJATA32_FL_IOMAP_ONLY) == 0 && |
153 | Cardbus_mapreg_map(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_MEM, |
154 | PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, |
155 | &NJATA32_REGT(sc), &csc->sc_regmaph, NULL, &csc->sc_regmap_size) |
156 | == 0) { |
157 | if (bus_space_subregion(NJATA32_REGT(sc), csc->sc_regmaph, |
158 | NJATA32_MEMOFFSET_REG, NJATA32_REGSIZE, &NJATA32_REGH(sc)) |
159 | != 0) { |
160 | /* failed -- undo map and try I/O */ |
161 | Cardbus_mapreg_unmap(csc->sc_ct, |
162 | NJATA32_CARDBUS_BASEADDR_MEM, NJATA32_REGT(sc), |
163 | csc->sc_regmaph, csc->sc_regmap_size); |
164 | goto try_io; |
165 | } |
166 | #ifdef NJATA32_DEBUG |
167 | aprint_normal("%s: memory space mapped, size %u\n" , |
168 | NJATA32NAME(sc), (unsigned)csc->sc_regmap_size); |
169 | #endif |
170 | csr |= PCI_COMMAND_MEM_ENABLE; |
171 | sc->sc_flags = NJATA32_MEM_MAPPED; |
172 | } else { |
173 | try_io: |
174 | if (Cardbus_mapreg_map(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_IO, |
175 | PCI_MAPREG_TYPE_IO, 0, &NJATA32_REGT(sc), |
176 | &NJATA32_REGH(sc), NULL, &csc->sc_regmap_size) == 0) { |
177 | #ifdef NJATA32_DEBUG |
178 | aprint_normal("%s: io space mapped, size %u\n" , |
179 | NJATA32NAME(sc), (unsigned)csc->sc_regmap_size); |
180 | #endif |
181 | csr |= PCI_COMMAND_IO_ENABLE; |
182 | sc->sc_flags = NJATA32_IO_MAPPED; |
183 | } else { |
184 | aprint_error("%s: unable to map device registers\n" , |
185 | NJATA32NAME(sc)); |
186 | return; |
187 | } |
188 | } |
189 | |
190 | /* Enable the appropriate bits in the PCI CSR. */ |
191 | reg = Cardbus_conf_read(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG); |
192 | reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); |
193 | reg |= csr; |
194 | Cardbus_conf_write(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG, reg); |
195 | |
196 | /* |
197 | * Make sure the latency timer is set to some reasonable |
198 | * value. |
199 | */ |
200 | reg = Cardbus_conf_read(ct, ca->ca_tag, PCI_BHLC_REG); |
201 | if (PCI_LATTIMER(reg) < latency) { |
202 | reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); |
203 | reg |= (latency << PCI_LATTIMER_SHIFT); |
204 | Cardbus_conf_write(ct, ca->ca_tag, PCI_BHLC_REG, reg); |
205 | } |
206 | |
207 | sc->sc_dmat = ca->ca_dmat; |
208 | |
209 | /* |
210 | * Establish the interrupt. |
211 | */ |
212 | sc->sc_ih = Cardbus_intr_establish(ct, IPL_BIO, njata32_intr, sc); |
213 | if (sc->sc_ih == NULL) { |
214 | aprint_error("%s: unable to establish interrupt\n" , |
215 | NJATA32NAME(sc)); |
216 | return; |
217 | } |
218 | |
219 | /* attach */ |
220 | njata32_attach(sc); |
221 | } |
222 | |
223 | static int |
224 | njata_cardbus_detach(device_t self, int flags) |
225 | { |
226 | struct njata32_cardbus_softc *csc = device_private(self); |
227 | struct njata32_softc *sc = &csc->sc_njata32; |
228 | int rv; |
229 | |
230 | rv = njata32_detach(sc, flags); |
231 | if (rv) |
232 | return rv; |
233 | |
234 | if (sc->sc_ih) |
235 | Cardbus_intr_disestablish(csc->sc_ct, sc->sc_ih); |
236 | |
237 | if (sc->sc_flags & NJATA32_IO_MAPPED) |
238 | Cardbus_mapreg_unmap(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_IO, |
239 | NJATA32_REGT(sc), NJATA32_REGH(sc), csc->sc_regmap_size); |
240 | if (sc->sc_flags & NJATA32_MEM_MAPPED) |
241 | Cardbus_mapreg_unmap(csc->sc_ct, NJATA32_CARDBUS_BASEADDR_MEM, |
242 | NJATA32_REGT(sc), csc->sc_regmaph, csc->sc_regmap_size); |
243 | |
244 | return 0; |
245 | } |
246 | |