| @@ -1,294 +1,294 @@ | | | @@ -1,294 +1,294 @@ |
1 | /* $NetBSD: sdhc_pci.c,v 1.2 2009/06/29 11:05:12 hubertf Exp $ */ | | 1 | /* $NetBSD: sdhc_pci.c,v 1.3 2009/10/02 04:38:47 uebayasi Exp $ */ |
2 | /* $OpenBSD: sdhc_pci.c,v 1.7 2007/10/30 18:13:45 chl Exp $ */ | | 2 | /* $OpenBSD: sdhc_pci.c,v 1.7 2007/10/30 18:13:45 chl Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> | | 5 | * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | */ | | 18 | */ |
19 | | | 19 | |
20 | #include <sys/cdefs.h> | | 20 | #include <sys/cdefs.h> |
21 | __KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.2 2009/06/29 11:05:12 hubertf Exp $"); | | 21 | __KERNEL_RCSID(0, "$NetBSD: sdhc_pci.c,v 1.3 2009/10/02 04:38:47 uebayasi Exp $"); |
22 | | | 22 | |
23 | #include <sys/param.h> | | 23 | #include <sys/param.h> |
24 | #include <sys/device.h> | | 24 | #include <sys/device.h> |
25 | #include <sys/systm.h> | | 25 | #include <sys/systm.h> |
26 | #include <sys/malloc.h> | | 26 | #include <sys/malloc.h> |
27 | #include <sys/pmf.h> | | 27 | #include <sys/pmf.h> |
28 | | | 28 | |
29 | #include <dev/pci/pcivar.h> | | 29 | #include <dev/pci/pcivar.h> |
30 | #include <dev/pci/pcidevs.h> | | 30 | #include <dev/pci/pcidevs.h> |
31 | | | 31 | |
32 | #include <dev/sdmmc/sdhcreg.h> | | 32 | #include <dev/sdmmc/sdhcreg.h> |
33 | #include <dev/sdmmc/sdhcvar.h> | | 33 | #include <dev/sdmmc/sdhcvar.h> |
34 | #include <dev/sdmmc/sdmmcvar.h> | | 34 | #include <dev/sdmmc/sdmmcvar.h> |
35 | | | 35 | |
36 | /* PCI base address registers */ | | 36 | /* PCI base address registers */ |
37 | #define SDHC_PCI_BAR_START PCI_MAPREG_START | | 37 | #define SDHC_PCI_BAR_START PCI_MAPREG_START |
38 | #define SDHC_PCI_BAR_END PCI_MAPREG_END | | 38 | #define SDHC_PCI_BAR_END PCI_MAPREG_END |
39 | | | 39 | |
40 | /* PCI interface classes */ | | 40 | /* PCI interface classes */ |
41 | #define SDHC_PCI_INTERFACE_NO_DMA 0x00 | | 41 | #define SDHC_PCI_INTERFACE_NO_DMA 0x00 |
42 | #define SDHC_PCI_INTERFACE_DMA 0x01 | | 42 | #define SDHC_PCI_INTERFACE_DMA 0x01 |
43 | #define SDHC_PCI_INTERFACE_VENDOR 0x02 | | 43 | #define SDHC_PCI_INTERFACE_VENDOR 0x02 |
44 | | | 44 | |
45 | /* | | 45 | /* |
46 | * 8-bit PCI configuration register that tells us how many slots there | | 46 | * 8-bit PCI configuration register that tells us how many slots there |
47 | * are and which BAR entry corresponds to the first slot. | | 47 | * are and which BAR entry corresponds to the first slot. |
48 | */ | | 48 | */ |
49 | #define SDHC_PCI_CONF_SLOT_INFO 0x40 | | 49 | #define SDHC_PCI_CONF_SLOT_INFO 0x40 |
50 | #define SDHC_PCI_NUM_SLOTS(info) ((((info) >> 4) & 0x7) + 1) | | 50 | #define SDHC_PCI_NUM_SLOTS(info) ((((info) >> 4) & 0x7) + 1) |
51 | #define SDHC_PCI_FIRST_BAR(info) ((info) & 0x7) | | 51 | #define SDHC_PCI_FIRST_BAR(info) ((info) & 0x7) |
52 | | | 52 | |
53 | struct sdhc_pci_softc { | | 53 | struct sdhc_pci_softc { |
54 | struct sdhc_softc sc; | | 54 | struct sdhc_softc sc; |
55 | void *sc_ih; | | 55 | void *sc_ih; |
56 | }; | | 56 | }; |
57 | | | 57 | |
58 | static int sdhc_pci_match(device_t, cfdata_t, void *); | | 58 | static int sdhc_pci_match(device_t, cfdata_t, void *); |
59 | static void sdhc_pci_attach(device_t, device_t, void *); | | 59 | static void sdhc_pci_attach(device_t, device_t, void *); |
60 | | | 60 | |
61 | CFATTACH_DECL_NEW(sdhc_pci, sizeof(struct sdhc_pci_softc), | | 61 | CFATTACH_DECL_NEW(sdhc_pci, sizeof(struct sdhc_pci_softc), |
62 | sdhc_pci_match, sdhc_pci_attach, NULL, NULL); | | 62 | sdhc_pci_match, sdhc_pci_attach, NULL, NULL); |
63 | | | 63 | |
64 | #ifdef SDHC_DEBUG | | 64 | #ifdef SDHC_DEBUG |
65 | #define DPRINTF(s) printf s | | 65 | #define DPRINTF(s) printf s |
66 | #else | | 66 | #else |
67 | #define DPRINTF(s) /**/ | | 67 | #define DPRINTF(s) /**/ |
68 | #endif | | 68 | #endif |
69 | | | 69 | |
70 | static const struct sdhc_pci_quirk { | | 70 | static const struct sdhc_pci_quirk { |
71 | pci_vendor_id_t vendor; | | 71 | pci_vendor_id_t vendor; |
72 | pci_product_id_t product; | | 72 | pci_product_id_t product; |
73 | pci_vendor_id_t subvendor; | | 73 | pci_vendor_id_t subvendor; |
74 | pci_product_id_t subproduct; | | 74 | pci_product_id_t subproduct; |
75 | u_int function; | | 75 | u_int function; |
76 | | | 76 | |
77 | uint32_t flags; | | 77 | uint32_t flags; |
78 | #define SDHC_PCI_QUIRK_FORCE_DMA (1U << 0) | | 78 | #define SDHC_PCI_QUIRK_FORCE_DMA (1U << 0) |
79 | #define SDHC_PCI_QUIRK_TI_HACK (1U << 1) | | 79 | #define SDHC_PCI_QUIRK_TI_HACK (1U << 1) |
80 | #define SDHC_PCI_QUIRK_NO_PWR0 (1U << 2) | | 80 | #define SDHC_PCI_QUIRK_NO_PWR0 (1U << 2) |
81 | } sdhc_pci_quirk_table[] = { | | 81 | } sdhc_pci_quirk_table[] = { |
82 | { | | 82 | { |
83 | PCI_VENDOR_TI, | | 83 | PCI_VENDOR_TI, |
84 | PCI_PRODUCT_TI_PCI72111SD, | | 84 | PCI_PRODUCT_TI_PCI72111SD, |
85 | 0xffff, | | 85 | 0xffff, |
86 | 0xffff, | | 86 | 0xffff, |
87 | 4, | | 87 | 4, |
88 | SDHC_PCI_QUIRK_TI_HACK | | 88 | SDHC_PCI_QUIRK_TI_HACK |
89 | }, | | 89 | }, |
90 | | | 90 | |
91 | { | | 91 | { |
92 | PCI_VENDOR_ENE, | | 92 | PCI_VENDOR_ENE, |
93 | PCI_PRODUCT_ENE_CB712, | | 93 | PCI_PRODUCT_ENE_CB712, |
94 | 0xffff, | | 94 | 0xffff, |
95 | 0xffff, | | 95 | 0xffff, |
96 | 0, | | 96 | 0, |
97 | SDHC_PCI_QUIRK_NO_PWR0 | | 97 | SDHC_PCI_QUIRK_NO_PWR0 |
98 | }, | | 98 | }, |
99 | }; | | 99 | }; |
100 | | | 100 | |
101 | static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *); | | 101 | static void sdhc_pci_quirk_ti_hack(struct pci_attach_args *); |
102 | | | 102 | |
103 | static uint32_t | | 103 | static uint32_t |
104 | sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa) | | 104 | sdhc_pci_lookup_quirk_flags(struct pci_attach_args *pa) |
105 | { | | 105 | { |
106 | const struct sdhc_pci_quirk *q; | | 106 | const struct sdhc_pci_quirk *q; |
107 | pcireg_t id; | | 107 | pcireg_t id; |
108 | pci_vendor_id_t vendor; | | 108 | pci_vendor_id_t vendor; |
109 | pci_product_id_t product; | | 109 | pci_product_id_t product; |
110 | int i; | | 110 | int i; |
111 | | | 111 | |
112 | for (i = 0; i < __arraycount(sdhc_pci_quirk_table); i++) { | | 112 | for (i = 0; i < __arraycount(sdhc_pci_quirk_table); i++) { |
113 | q = &sdhc_pci_quirk_table[i]; | | 113 | q = &sdhc_pci_quirk_table[i]; |
114 | | | 114 | |
115 | if ((PCI_VENDOR(pa->pa_id) == q->vendor) | | 115 | if ((PCI_VENDOR(pa->pa_id) == q->vendor) |
116 | && (PCI_PRODUCT(pa->pa_id) == q->product)) { | | 116 | && (PCI_PRODUCT(pa->pa_id) == q->product)) { |
117 | if ((q->function != ~0) | | 117 | if ((q->function != ~0) |
118 | && (pa->pa_function != q->function)) | | 118 | && (pa->pa_function != q->function)) |
119 | continue; | | 119 | continue; |
120 | | | 120 | |
121 | if ((q->subvendor == 0xffff) | | 121 | if ((q->subvendor == 0xffff) |
122 | && (q->subproduct == 0xffff)) | | 122 | && (q->subproduct == 0xffff)) |
123 | return q->flags; | | 123 | return q->flags; |
124 | | | 124 | |
125 | id = pci_conf_read(pa->pa_pc, pa->pa_tag, | | 125 | id = pci_conf_read(pa->pa_pc, pa->pa_tag, |
126 | PCI_SUBSYS_ID_REG); | | 126 | PCI_SUBSYS_ID_REG); |
127 | vendor = PCI_VENDOR(id); | | 127 | vendor = PCI_VENDOR(id); |
128 | product = PCI_PRODUCT(id); | | 128 | product = PCI_PRODUCT(id); |
129 | | | 129 | |
130 | if ((q->subvendor != 0xffff) | | 130 | if ((q->subvendor != 0xffff) |
131 | && (q->subproduct != 0xffff)) { | | 131 | && (q->subproduct != 0xffff)) { |
132 | if ((vendor == q->subvendor) | | 132 | if ((vendor == q->subvendor) |
133 | && (product == q->subproduct)) | | 133 | && (product == q->subproduct)) |
134 | return q->flags; | | 134 | return q->flags; |
135 | } else if (q->subvendor != 0xffff) { | | 135 | } else if (q->subvendor != 0xffff) { |
136 | if (product == q->subproduct) | | 136 | if (product == q->subproduct) |
137 | return q->flags; | | 137 | return q->flags; |
138 | } else { | | 138 | } else { |
139 | if (vendor == q->subvendor) | | 139 | if (vendor == q->subvendor) |
140 | return q->flags; | | 140 | return q->flags; |
141 | } | | 141 | } |
142 | } | | 142 | } |
143 | } | | 143 | } |
144 | | | 144 | |
145 | return 0; | | 145 | return 0; |
146 | } | | 146 | } |
147 | | | 147 | |
148 | static int | | 148 | static int |
149 | sdhc_pci_match(device_t parent, cfdata_t cf, void *aux) | | 149 | sdhc_pci_match(device_t parent, cfdata_t cf, void *aux) |
150 | { | | 150 | { |
151 | struct pci_attach_args *pa = aux; | | 151 | struct pci_attach_args *pa = aux; |
152 | | | 152 | |
153 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM && | | 153 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SYSTEM && |
154 | PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC) | | 154 | PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SYSTEM_SDHC) |
155 | return 1; | | 155 | return 1; |
156 | | | 156 | |
157 | return 0; | | 157 | return 0; |
158 | } | | 158 | } |
159 | | | 159 | |
160 | static void | | 160 | static void |
161 | sdhc_pci_attach(device_t parent, device_t self, void *aux) | | 161 | sdhc_pci_attach(device_t parent, device_t self, void *aux) |
162 | { | | 162 | { |
163 | struct sdhc_pci_softc *sc = device_private(self); | | 163 | struct sdhc_pci_softc *sc = device_private(self); |
164 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; | | 164 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; |
165 | pci_chipset_tag_t pc = pa->pa_pc; | | 165 | pci_chipset_tag_t pc = pa->pa_pc; |
166 | pcitag_t tag = pa->pa_tag; | | 166 | pcitag_t tag = pa->pa_tag; |
167 | pci_intr_handle_t ih; | | 167 | pci_intr_handle_t ih; |
168 | pcireg_t csr; | | 168 | pcireg_t csr; |
169 | pcireg_t slotinfo; | | 169 | pcireg_t slotinfo; |
170 | char devinfo[256]; | | 170 | char devinfo[256]; |
171 | char const *intrstr; | | 171 | char const *intrstr; |
172 | int nslots; | | 172 | int nslots; |
173 | int reg; | | 173 | int reg; |
174 | int cnt; | | 174 | int cnt; |
175 | bus_space_tag_t iot; | | 175 | bus_space_tag_t iot; |
176 | bus_space_handle_t ioh; | | 176 | bus_space_handle_t ioh; |
177 | bus_size_t size; | | 177 | bus_size_t size; |
178 | uint32_t flags; | | 178 | uint32_t flags; |
179 | | | 179 | |
180 | sc->sc.sc_dev = self; | | 180 | sc->sc.sc_dev = self; |
181 | sc->sc.sc_dmat = pa->pa_dmat; | | 181 | sc->sc.sc_dmat = pa->pa_dmat; |
182 | sc->sc.sc_host = NULL; | | 182 | sc->sc.sc_host = NULL; |
183 | | | 183 | |
184 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); | | 184 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); |
185 | aprint_normal(": %s (rev. 0x%02x)\n", devinfo, | | 185 | aprint_normal(": %s (rev. 0x%02x)\n", devinfo, |
186 | PCI_REVISION(pa->pa_class)); | | 186 | PCI_REVISION(pa->pa_class)); |
187 | aprint_naive("\n"); | | 187 | aprint_naive("\n"); |
188 | | | 188 | |
189 | /* Some controllers needs special treatment. */ | | 189 | /* Some controllers needs special treatment. */ |
190 | flags = sdhc_pci_lookup_quirk_flags(pa); | | 190 | flags = sdhc_pci_lookup_quirk_flags(pa); |
191 | if (ISSET(flags, SDHC_PCI_QUIRK_TI_HACK)) | | 191 | if (ISSET(flags, SDHC_PCI_QUIRK_TI_HACK)) |
192 | sdhc_pci_quirk_ti_hack(pa); | | 192 | sdhc_pci_quirk_ti_hack(pa); |
193 | if (ISSET(flags, SDHC_PCI_QUIRK_FORCE_DMA)) | | 193 | if (ISSET(flags, SDHC_PCI_QUIRK_FORCE_DMA)) |
194 | SET(sc->sc.sc_flags, SDHC_FLAG_FORCE_DMA); | | 194 | SET(sc->sc.sc_flags, SDHC_FLAG_FORCE_DMA); |
195 | if (ISSET(flags, SDHC_PCI_QUIRK_NO_PWR0)) | | 195 | if (ISSET(flags, SDHC_PCI_QUIRK_NO_PWR0)) |
196 | SET(sc->sc.sc_flags, SDHC_FLAG_NO_PWR0); | | 196 | SET(sc->sc.sc_flags, SDHC_FLAG_NO_PWR0); |
197 | | | 197 | |
198 | /* | | 198 | /* |
199 | * Map and attach all hosts supported by the host controller. | | 199 | * Map and attach all hosts supported by the host controller. |
200 | */ | | 200 | */ |
201 | slotinfo = pci_conf_read(pc, tag, SDHC_PCI_CONF_SLOT_INFO); | | 201 | slotinfo = pci_conf_read(pc, tag, SDHC_PCI_CONF_SLOT_INFO); |
202 | nslots = SDHC_PCI_NUM_SLOTS(slotinfo); | | 202 | nslots = SDHC_PCI_NUM_SLOTS(slotinfo); |
203 | | | 203 | |
204 | /* Allocate an array big enough to hold all the possible hosts */ | | 204 | /* Allocate an array big enough to hold all the possible hosts */ |
205 | sc->sc.sc_host = malloc(sizeof(struct sdhc_host *) * nslots, | | 205 | sc->sc.sc_host = malloc(sizeof(struct sdhc_host *) * nslots, |
206 | M_DEVBUF, M_NOWAIT | M_ZERO); | | 206 | M_DEVBUF, M_NOWAIT | M_ZERO); |
207 | if (sc->sc.sc_host == NULL) { | | 207 | if (sc->sc.sc_host == NULL) { |
208 | aprint_error_dev(self, "couldn't alloc memory\n"); | | 208 | aprint_error_dev(self, "couldn't alloc memory\n"); |
209 | goto err; | | 209 | goto err; |
210 | } | | 210 | } |
211 | | | 211 | |
212 | /* Enable the device. */ | | 212 | /* Enable the device. */ |
213 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 213 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
214 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, | | 214 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, |
215 | csr | PCI_COMMAND_MASTER_ENABLE); | | 215 | csr | PCI_COMMAND_MASTER_ENABLE); |
216 | | | 216 | |
217 | /* Map and establish the interrupt. */ | | 217 | /* Map and establish the interrupt. */ |
218 | if (pci_intr_map(pa, &ih)) { | | 218 | if (pci_intr_map(pa, &ih)) { |
219 | aprint_error_dev(self, "couldn't map interrupt\n"); | | 219 | aprint_error_dev(self, "couldn't map interrupt\n"); |
220 | goto err; | | 220 | goto err; |
221 | } | | 221 | } |
222 | | | 222 | |
223 | intrstr = pci_intr_string(pc, ih); | | 223 | intrstr = pci_intr_string(pc, ih); |
224 | sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, sdhc_intr, sc); | | 224 | sc->sc_ih = pci_intr_establish(pc, ih, IPL_SDMMC, sdhc_intr, &sc->sc); |
225 | if (sc->sc_ih == NULL) { | | 225 | if (sc->sc_ih == NULL) { |
226 | aprint_error_dev(self, "couldn't establish interrupt\n"); | | 226 | aprint_error_dev(self, "couldn't establish interrupt\n"); |
227 | goto err; | | 227 | goto err; |
228 | } | | 228 | } |
229 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); | | 229 | aprint_normal_dev(self, "interrupting at %s\n", intrstr); |
230 | | | 230 | |
231 | /* Enable use of DMA if supported by the interface. */ | | 231 | /* Enable use of DMA if supported by the interface. */ |
232 | if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA)) | | 232 | if ((PCI_INTERFACE(pa->pa_class) == SDHC_PCI_INTERFACE_DMA)) |
233 | SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA); | | 233 | SET(sc->sc.sc_flags, SDHC_FLAG_USE_DMA); |
234 | | | 234 | |
235 | /* XXX: handle 64-bit BARs */ | | 235 | /* XXX: handle 64-bit BARs */ |
236 | cnt = 0; | | 236 | cnt = 0; |
237 | for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * | | 237 | for (reg = SDHC_PCI_BAR_START + SDHC_PCI_FIRST_BAR(slotinfo) * |
238 | sizeof(uint32_t); | | 238 | sizeof(uint32_t); |
239 | reg < SDHC_PCI_BAR_END && nslots > 0; | | 239 | reg < SDHC_PCI_BAR_END && nslots > 0; |
240 | reg += sizeof(uint32_t), nslots--) { | | 240 | reg += sizeof(uint32_t), nslots--) { |
241 | if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0, | | 241 | if (pci_mapreg_map(pa, reg, PCI_MAPREG_TYPE_MEM, 0, |
242 | &iot, &ioh, NULL, &size)) { | | 242 | &iot, &ioh, NULL, &size)) { |
243 | continue; | | 243 | continue; |
244 | } | | 244 | } |
245 | | | 245 | |
246 | cnt++; | | 246 | cnt++; |
247 | if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) { | | 247 | if (sdhc_host_found(&sc->sc, iot, ioh, size) != 0) { |
248 | /* XXX: sc->sc_host leak */ | | 248 | /* XXX: sc->sc_host leak */ |
249 | aprint_error_dev(self, | | 249 | aprint_error_dev(self, |
250 | "couldn't initialize host (0x%x)\n", reg); | | 250 | "couldn't initialize host (0x%x)\n", reg); |
251 | } | | 251 | } |
252 | } | | 252 | } |
253 | if (cnt == 0) { | | 253 | if (cnt == 0) { |
254 | aprint_error_dev(self, "couldn't map register\n"); | | 254 | aprint_error_dev(self, "couldn't map register\n"); |
255 | goto err; | | 255 | goto err; |
256 | } | | 256 | } |
257 | | | 257 | |
258 | if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume, | | 258 | if (!pmf_device_register1(self, sdhc_suspend, sdhc_resume, |
259 | sdhc_shutdown)) { | | 259 | sdhc_shutdown)) { |
260 | aprint_error_dev(self, "couldn't establish powerhook\n"); | | 260 | aprint_error_dev(self, "couldn't establish powerhook\n"); |
261 | } | | 261 | } |
262 | | | 262 | |
263 | return; | | 263 | return; |
264 | | | 264 | |
265 | err: | | 265 | err: |
266 | if (sc->sc.sc_host != NULL) | | 266 | if (sc->sc.sc_host != NULL) |
267 | free(sc->sc.sc_host, M_DEVBUF); | | 267 | free(sc->sc.sc_host, M_DEVBUF); |
268 | } | | 268 | } |
269 | | | 269 | |
270 | /* TI specific register */ | | 270 | /* TI specific register */ |
271 | #define SDHC_PCI_GENERAL_CTL 0x4c | | 271 | #define SDHC_PCI_GENERAL_CTL 0x4c |
272 | #define MMC_SD_DIS 0x02 | | 272 | #define MMC_SD_DIS 0x02 |
273 | | | 273 | |
274 | static void | | 274 | static void |
275 | sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa) | | 275 | sdhc_pci_quirk_ti_hack(struct pci_attach_args *pa) |
276 | { | | 276 | { |
277 | pci_chipset_tag_t pc = pa->pa_pc; | | 277 | pci_chipset_tag_t pc = pa->pa_pc; |
278 | pcitag_t tag; | | 278 | pcitag_t tag; |
279 | pcireg_t id, reg; | | 279 | pcireg_t id, reg; |
280 | | | 280 | |
281 | /* Look at func 3 for the flash device */ | | 281 | /* Look at func 3 for the flash device */ |
282 | tag = pci_make_tag(pc, pa->pa_bus, pa->pa_device, 3); | | 282 | tag = pci_make_tag(pc, pa->pa_bus, pa->pa_device, 3); |
283 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 283 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
284 | if (PCI_PRODUCT(id) != PCI_PRODUCT_TI_PCI72111FM) | | 284 | if (PCI_PRODUCT(id) != PCI_PRODUCT_TI_PCI72111FM) |
285 | return; | | 285 | return; |
286 | | | 286 | |
287 | /* | | 287 | /* |
288 | * Disable MMC/SD on the flash media controller so the | | 288 | * Disable MMC/SD on the flash media controller so the |
289 | * SD host takes over. | | 289 | * SD host takes over. |
290 | */ | | 290 | */ |
291 | reg = pci_conf_read(pc, tag, SDHC_PCI_GENERAL_CTL); | | 291 | reg = pci_conf_read(pc, tag, SDHC_PCI_GENERAL_CTL); |
292 | reg |= MMC_SD_DIS; | | 292 | reg |= MMC_SD_DIS; |
293 | pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg); | | 293 | pci_conf_write(pc, tag, SDHC_PCI_GENERAL_CTL, reg); |
294 | } | | 294 | } |