| @@ -1,1004 +1,1007 @@ | | | @@ -1,1004 +1,1007 @@ |
1 | /* $NetBSD: awin_mmc.c,v 1.21 2015/08/08 17:21:19 jmcneill Exp $ */ | | 1 | /* $NetBSD: awin_mmc.c,v 1.22 2015/10/16 14:22:25 bouyer Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> | | 4 | * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include "locators.h" | | 29 | #include "locators.h" |
30 | | | 30 | |
31 | #include <sys/cdefs.h> | | 31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v 1.21 2015/08/08 17:21:19 jmcneill Exp $"); | | 32 | __KERNEL_RCSID(0, "$NetBSD: awin_mmc.c,v 1.22 2015/10/16 14:22:25 bouyer Exp $"); |
33 | | | 33 | |
34 | #include <sys/param.h> | | 34 | #include <sys/param.h> |
35 | #include <sys/bus.h> | | 35 | #include <sys/bus.h> |
36 | #include <sys/device.h> | | 36 | #include <sys/device.h> |
37 | #include <sys/intr.h> | | 37 | #include <sys/intr.h> |
38 | #include <sys/systm.h> | | 38 | #include <sys/systm.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | | | 40 | |
41 | #include <dev/sdmmc/sdmmcvar.h> | | 41 | #include <dev/sdmmc/sdmmcvar.h> |
42 | #include <dev/sdmmc/sdmmcchip.h> | | 42 | #include <dev/sdmmc/sdmmcchip.h> |
43 | #include <dev/sdmmc/sdmmc_ioreg.h> | | 43 | #include <dev/sdmmc/sdmmc_ioreg.h> |
44 | | | 44 | |
45 | #include <arm/allwinner/awin_reg.h> | | 45 | #include <arm/allwinner/awin_reg.h> |
46 | #include <arm/allwinner/awin_var.h> | | 46 | #include <arm/allwinner/awin_var.h> |
47 | | | 47 | |
48 | #define AWIN_MMC_NDESC 16 | | 48 | #define AWIN_MMC_NDESC 16 |
49 | #define AWIN_MMC_DMA_FTRGLEVEL_A20 0x20070008 | | 49 | #define AWIN_MMC_DMA_FTRGLEVEL_A20 0x20070008 |
50 | #define AWIN_MMC_DMA_FTRGLEVEL_A80 0x200f0010 | | 50 | #define AWIN_MMC_DMA_FTRGLEVEL_A80 0x200f0010 |
51 | | | 51 | |
52 | static const struct awin_gpio_pinset awin_mmc_pinsets_a80[4] = { | | 52 | static const struct awin_gpio_pinset awin_mmc_pinsets_a80[4] = { |
53 | [0] = { 'F', AWIN_A80_PIO_PF_SDMMC0_FUNC, AWIN_A80_PIO_PF_SDMMC0_PINS, | | 53 | [0] = { 'F', AWIN_A80_PIO_PF_SDMMC0_FUNC, AWIN_A80_PIO_PF_SDMMC0_PINS, |
54 | GPIO_PIN_PULLUP, 2 }, | | 54 | GPIO_PIN_PULLUP, 2 }, |
55 | [1] = { 'G', AWIN_A80_PIO_PG_SDMMC1_FUNC, AWIN_A80_PIO_PG_SDMMC1_PINS, | | 55 | [1] = { 'G', AWIN_A80_PIO_PG_SDMMC1_FUNC, AWIN_A80_PIO_PG_SDMMC1_PINS, |
56 | GPIO_PIN_PULLUP, 2 }, | | 56 | GPIO_PIN_PULLUP, 2 }, |
57 | [2] = { 'C', AWIN_A80_PIO_PC_SDMMC2_FUNC, AWIN_A80_PIO_PC_SDMMC2_PINS, | | 57 | [2] = { 'C', AWIN_A80_PIO_PC_SDMMC2_FUNC, AWIN_A80_PIO_PC_SDMMC2_PINS, |
58 | GPIO_PIN_PULLUP, 2 }, | | 58 | GPIO_PIN_PULLUP, 2 }, |
59 | }; | | 59 | }; |
60 | | | 60 | |
61 | static int awin_mmc_match(device_t, cfdata_t, void *); | | 61 | static int awin_mmc_match(device_t, cfdata_t, void *); |
62 | static void awin_mmc_attach(device_t, device_t, void *); | | 62 | static void awin_mmc_attach(device_t, device_t, void *); |
63 | static void awin_mmc_attach_i(device_t); | | 63 | static void awin_mmc_attach_i(device_t); |
64 | | | 64 | |
65 | static int awin_mmc_intr(void *); | | 65 | static int awin_mmc_intr(void *); |
66 | | | 66 | |
67 | static int awin_mmc_host_reset(sdmmc_chipset_handle_t); | | 67 | static int awin_mmc_host_reset(sdmmc_chipset_handle_t); |
68 | static uint32_t awin_mmc_host_ocr(sdmmc_chipset_handle_t); | | 68 | static uint32_t awin_mmc_host_ocr(sdmmc_chipset_handle_t); |
69 | static int awin_mmc_host_maxblklen(sdmmc_chipset_handle_t); | | 69 | static int awin_mmc_host_maxblklen(sdmmc_chipset_handle_t); |
70 | static int awin_mmc_card_detect(sdmmc_chipset_handle_t); | | 70 | static int awin_mmc_card_detect(sdmmc_chipset_handle_t); |
71 | static int awin_mmc_write_protect(sdmmc_chipset_handle_t); | | 71 | static int awin_mmc_write_protect(sdmmc_chipset_handle_t); |
72 | static int awin_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); | | 72 | static int awin_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); |
73 | static int awin_mmc_bus_clock(sdmmc_chipset_handle_t, int); | | 73 | static int awin_mmc_bus_clock(sdmmc_chipset_handle_t, int); |
74 | static int awin_mmc_bus_width(sdmmc_chipset_handle_t, int); | | 74 | static int awin_mmc_bus_width(sdmmc_chipset_handle_t, int); |
75 | static int awin_mmc_bus_rod(sdmmc_chipset_handle_t, int); | | 75 | static int awin_mmc_bus_rod(sdmmc_chipset_handle_t, int); |
76 | static void awin_mmc_exec_command(sdmmc_chipset_handle_t, | | 76 | static void awin_mmc_exec_command(sdmmc_chipset_handle_t, |
77 | struct sdmmc_command *); | | 77 | struct sdmmc_command *); |
78 | static void awin_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); | | 78 | static void awin_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); |
79 | static void awin_mmc_card_intr_ack(sdmmc_chipset_handle_t); | | 79 | static void awin_mmc_card_intr_ack(sdmmc_chipset_handle_t); |
80 | | | 80 | |
81 | static struct sdmmc_chip_functions awin_mmc_chip_functions = { | | 81 | static struct sdmmc_chip_functions awin_mmc_chip_functions = { |
82 | .host_reset = awin_mmc_host_reset, | | 82 | .host_reset = awin_mmc_host_reset, |
83 | .host_ocr = awin_mmc_host_ocr, | | 83 | .host_ocr = awin_mmc_host_ocr, |
84 | .host_maxblklen = awin_mmc_host_maxblklen, | | 84 | .host_maxblklen = awin_mmc_host_maxblklen, |
85 | .card_detect = awin_mmc_card_detect, | | 85 | .card_detect = awin_mmc_card_detect, |
86 | .write_protect = awin_mmc_write_protect, | | 86 | .write_protect = awin_mmc_write_protect, |
87 | .bus_power = awin_mmc_bus_power, | | 87 | .bus_power = awin_mmc_bus_power, |
88 | .bus_clock = awin_mmc_bus_clock, | | 88 | .bus_clock = awin_mmc_bus_clock, |
89 | .bus_width = awin_mmc_bus_width, | | 89 | .bus_width = awin_mmc_bus_width, |
90 | .bus_rod = awin_mmc_bus_rod, | | 90 | .bus_rod = awin_mmc_bus_rod, |
91 | .exec_command = awin_mmc_exec_command, | | 91 | .exec_command = awin_mmc_exec_command, |
92 | .card_enable_intr = awin_mmc_card_enable_intr, | | 92 | .card_enable_intr = awin_mmc_card_enable_intr, |
93 | .card_intr_ack = awin_mmc_card_intr_ack, | | 93 | .card_intr_ack = awin_mmc_card_intr_ack, |
94 | }; | | 94 | }; |
95 | | | 95 | |
96 | struct awin_mmc_softc { | | 96 | struct awin_mmc_softc { |
97 | device_t sc_dev; | | 97 | device_t sc_dev; |
98 | bus_space_tag_t sc_bst; | | 98 | bus_space_tag_t sc_bst; |
99 | bus_space_handle_t sc_bsh; | | 99 | bus_space_handle_t sc_bsh; |
100 | bus_space_handle_t sc_clk_bsh; | | 100 | bus_space_handle_t sc_clk_bsh; |
101 | bus_dma_tag_t sc_dmat; | | 101 | bus_dma_tag_t sc_dmat; |
102 | | | 102 | |
103 | bool sc_use_dma; | | 103 | bool sc_use_dma; |
104 | | | 104 | |
105 | void *sc_ih; | | 105 | void *sc_ih; |
106 | kmutex_t sc_intr_lock; | | 106 | kmutex_t sc_intr_lock; |
107 | kcondvar_t sc_intr_cv; | | 107 | kcondvar_t sc_intr_cv; |
108 | kcondvar_t sc_idst_cv; | | 108 | kcondvar_t sc_idst_cv; |
109 | | | 109 | |
110 | int sc_mmc_width; | | 110 | int sc_mmc_width; |
111 | int sc_mmc_present; | | 111 | int sc_mmc_present; |
112 | int sc_mmc_port; | | 112 | int sc_mmc_port; |
113 | | | 113 | |
114 | device_t sc_sdmmc_dev; | | 114 | device_t sc_sdmmc_dev; |
115 | | | 115 | |
116 | uint32_t sc_fifo_reg; | | 116 | uint32_t sc_fifo_reg; |
117 | uint32_t sc_dma_ftrglevel; | | 117 | uint32_t sc_dma_ftrglevel; |
118 | | | 118 | |
119 | uint32_t sc_idma_xferlen; | | 119 | uint32_t sc_idma_xferlen; |
120 | bus_dma_segment_t sc_idma_segs[1]; | | 120 | bus_dma_segment_t sc_idma_segs[1]; |
121 | int sc_idma_nsegs; | | 121 | int sc_idma_nsegs; |
122 | bus_size_t sc_idma_size; | | 122 | bus_size_t sc_idma_size; |
123 | bus_dmamap_t sc_idma_map; | | 123 | bus_dmamap_t sc_idma_map; |
124 | int sc_idma_ndesc; | | 124 | int sc_idma_ndesc; |
125 | void *sc_idma_desc; | | 125 | void *sc_idma_desc; |
126 | | | 126 | |
127 | uint32_t sc_intr_rint; | | 127 | uint32_t sc_intr_rint; |
128 | uint32_t sc_intr_mint; | | 128 | uint32_t sc_intr_mint; |
129 | uint32_t sc_idma_idst; | | 129 | uint32_t sc_idma_idst; |
130 | | | 130 | |
131 | bool sc_has_gpio_detect; | | 131 | bool sc_has_gpio_detect; |
132 | struct awin_gpio_pindata sc_gpio_detect; /* card detect */ | | 132 | struct awin_gpio_pindata sc_gpio_detect; /* card detect */ |
133 | bool sc_has_gpio_wp; | | 133 | bool sc_has_gpio_wp; |
134 | struct awin_gpio_pindata sc_gpio_wp; /* write protect */ | | 134 | struct awin_gpio_pindata sc_gpio_wp; /* write protect */ |
135 | bool sc_has_gpio_led; | | 135 | bool sc_has_gpio_led; |
136 | struct awin_gpio_pindata sc_gpio_led; /* LED */ | | 136 | struct awin_gpio_pindata sc_gpio_led; /* LED */ |
137 | }; | | 137 | }; |
138 | | | 138 | |
139 | CFATTACH_DECL_NEW(awin_mmc, sizeof(struct awin_mmc_softc), | | 139 | CFATTACH_DECL_NEW(awin_mmc, sizeof(struct awin_mmc_softc), |
140 | awin_mmc_match, awin_mmc_attach, NULL, NULL); | | 140 | awin_mmc_match, awin_mmc_attach, NULL, NULL); |
141 | | | 141 | |
142 | #define MMC_WRITE(sc, reg, val) \ | | 142 | #define MMC_WRITE(sc, reg, val) \ |
143 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) | | 143 | bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) |
144 | #define MMC_READ(sc, reg) \ | | 144 | #define MMC_READ(sc, reg) \ |
145 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) | | 145 | bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) |
146 | | | 146 | |
147 | static int | | 147 | static int |
148 | awin_mmc_match(device_t parent, cfdata_t cf, void *aux) | | 148 | awin_mmc_match(device_t parent, cfdata_t cf, void *aux) |
149 | { | | 149 | { |
150 | struct awinio_attach_args * const aio = aux; | | 150 | struct awinio_attach_args * const aio = aux; |
151 | const struct awin_locators * const loc = &aio->aio_loc; | | 151 | const struct awin_locators * const loc = &aio->aio_loc; |
152 | const int port = cf->cf_loc[AWINIOCF_PORT]; | | 152 | const int port = cf->cf_loc[AWINIOCF_PORT]; |
153 | | | 153 | |
154 | if (strcmp(cf->cf_name, loc->loc_name)) | | 154 | if (strcmp(cf->cf_name, loc->loc_name)) |
155 | return 0; | | 155 | return 0; |
156 | | | 156 | |
157 | if (port != AWINIOCF_PORT_DEFAULT && port != loc->loc_port) | | 157 | if (port != AWINIOCF_PORT_DEFAULT && port != loc->loc_port) |
158 | return 0; | | 158 | return 0; |
159 | | | 159 | |
160 | return 1; | | 160 | return 1; |
161 | } | | 161 | } |
162 | | | 162 | |
163 | static int | | 163 | static int |
164 | awin_mmc_idma_setup(struct awin_mmc_softc *sc) | | 164 | awin_mmc_idma_setup(struct awin_mmc_softc *sc) |
165 | { | | 165 | { |
166 | int error; | | 166 | int error; |
167 | | | 167 | |
168 | if (awin_chip_id() == AWIN_CHIP_ID_A10) { | | 168 | if (awin_chip_id() == AWIN_CHIP_ID_A10) { |
169 | sc->sc_idma_xferlen = 0x2000; | | 169 | sc->sc_idma_xferlen = 0x2000; |
170 | } else { | | 170 | } else { |
171 | sc->sc_idma_xferlen = 0x10000; | | 171 | sc->sc_idma_xferlen = 0x10000; |
172 | } | | 172 | } |
173 | | | 173 | |
174 | sc->sc_idma_ndesc = AWIN_MMC_NDESC; | | 174 | sc->sc_idma_ndesc = AWIN_MMC_NDESC; |
175 | sc->sc_idma_size = sizeof(struct awin_mmc_idma_descriptor) * | | 175 | sc->sc_idma_size = sizeof(struct awin_mmc_idma_descriptor) * |
176 | sc->sc_idma_ndesc; | | 176 | sc->sc_idma_ndesc; |
177 | error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_idma_size, 0, | | 177 | error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_idma_size, 0, |
178 | sc->sc_idma_size, sc->sc_idma_segs, 1, | | 178 | sc->sc_idma_size, sc->sc_idma_segs, 1, |
179 | &sc->sc_idma_nsegs, BUS_DMA_WAITOK); | | 179 | &sc->sc_idma_nsegs, BUS_DMA_WAITOK); |
180 | if (error) | | 180 | if (error) |
181 | return error; | | 181 | return error; |
182 | error = bus_dmamem_map(sc->sc_dmat, sc->sc_idma_segs, | | 182 | error = bus_dmamem_map(sc->sc_dmat, sc->sc_idma_segs, |
183 | sc->sc_idma_nsegs, sc->sc_idma_size, | | 183 | sc->sc_idma_nsegs, sc->sc_idma_size, |
184 | &sc->sc_idma_desc, BUS_DMA_WAITOK); | | 184 | &sc->sc_idma_desc, BUS_DMA_WAITOK); |
185 | if (error) | | 185 | if (error) |
186 | goto free; | | 186 | goto free; |
187 | error = bus_dmamap_create(sc->sc_dmat, sc->sc_idma_size, 1, | | 187 | error = bus_dmamap_create(sc->sc_dmat, sc->sc_idma_size, 1, |
188 | sc->sc_idma_size, 0, BUS_DMA_WAITOK, &sc->sc_idma_map); | | 188 | sc->sc_idma_size, 0, BUS_DMA_WAITOK, &sc->sc_idma_map); |
189 | if (error) | | 189 | if (error) |
190 | goto unmap; | | 190 | goto unmap; |
191 | error = bus_dmamap_load(sc->sc_dmat, sc->sc_idma_map, | | 191 | error = bus_dmamap_load(sc->sc_dmat, sc->sc_idma_map, |
192 | sc->sc_idma_desc, sc->sc_idma_size, NULL, BUS_DMA_WAITOK); | | 192 | sc->sc_idma_desc, sc->sc_idma_size, NULL, BUS_DMA_WAITOK); |
193 | if (error) | | 193 | if (error) |
194 | goto destroy; | | 194 | goto destroy; |
195 | return 0; | | 195 | return 0; |
196 | | | 196 | |
197 | destroy: | | 197 | destroy: |
198 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_idma_map); | | 198 | bus_dmamap_destroy(sc->sc_dmat, sc->sc_idma_map); |
199 | unmap: | | 199 | unmap: |
200 | bus_dmamem_unmap(sc->sc_dmat, sc->sc_idma_desc, sc->sc_idma_size); | | 200 | bus_dmamem_unmap(sc->sc_dmat, sc->sc_idma_desc, sc->sc_idma_size); |
201 | free: | | 201 | free: |
202 | bus_dmamem_free(sc->sc_dmat, sc->sc_idma_segs, sc->sc_idma_nsegs); | | 202 | bus_dmamem_free(sc->sc_dmat, sc->sc_idma_segs, sc->sc_idma_nsegs); |
203 | return error; | | 203 | return error; |
204 | } | | 204 | } |
205 | | | 205 | |
206 | static void | | 206 | static void |
207 | awin_mmc_attach(device_t parent, device_t self, void *aux) | | 207 | awin_mmc_attach(device_t parent, device_t self, void *aux) |
208 | { | | 208 | { |
209 | struct awin_mmc_softc * const sc = device_private(self); | | 209 | struct awin_mmc_softc * const sc = device_private(self); |
210 | struct awinio_attach_args * const aio = aux; | | 210 | struct awinio_attach_args * const aio = aux; |
211 | const struct awin_locators * const loc = &aio->aio_loc; | | 211 | const struct awin_locators * const loc = &aio->aio_loc; |
212 | prop_dictionary_t cfg = device_properties(self); | | 212 | prop_dictionary_t cfg = device_properties(self); |
213 | const char *pin_name; | | 213 | const char *pin_name; |
214 | | | 214 | |
215 | sc->sc_dev = self; | | 215 | sc->sc_dev = self; |
216 | sc->sc_bst = aio->aio_core_bst; | | 216 | sc->sc_bst = aio->aio_core_bst; |
217 | sc->sc_dmat = aio->aio_dmat; | | 217 | sc->sc_dmat = aio->aio_dmat; |
218 | sc->sc_mmc_port = loc->loc_port; | | 218 | sc->sc_mmc_port = loc->loc_port; |
219 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); | | 219 | mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); |
220 | cv_init(&sc->sc_intr_cv, "awinmmcirq"); | | 220 | cv_init(&sc->sc_intr_cv, "awinmmcirq"); |
221 | cv_init(&sc->sc_idst_cv, "awinmmcdma"); | | 221 | cv_init(&sc->sc_idst_cv, "awinmmcdma"); |
222 | bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, | | 222 | bus_space_subregion(sc->sc_bst, aio->aio_core_bsh, |
223 | loc->loc_offset, loc->loc_size, &sc->sc_bsh); | | 223 | loc->loc_offset, loc->loc_size, &sc->sc_bsh); |
224 | | | 224 | |
225 | sc->sc_use_dma = true; | | 225 | sc->sc_use_dma = true; |
226 | prop_dictionary_get_bool(cfg, "dma", &sc->sc_use_dma); | | 226 | prop_dictionary_get_bool(cfg, "dma", &sc->sc_use_dma); |
227 | | | 227 | |
228 | aprint_naive("\n"); | | 228 | aprint_naive("\n"); |
229 | aprint_normal(": SD3.0 (%s)\n", sc->sc_use_dma ? "DMA" : "PIO"); | | 229 | aprint_normal(": SD3.0 (%s)\n", sc->sc_use_dma ? "DMA" : "PIO"); |
230 | | | 230 | |
231 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { | | 231 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { |
232 | if (awin_mmc_pinsets_a80[loc->loc_port].pinset_group) { | | 232 | if (awin_mmc_pinsets_a80[loc->loc_port].pinset_group) { |
233 | awin_gpio_pinset_acquire( | | 233 | awin_gpio_pinset_acquire( |
234 | &awin_mmc_pinsets_a80[loc->loc_port]); | | 234 | &awin_mmc_pinsets_a80[loc->loc_port]); |
235 | } | | 235 | } |
236 | | | 236 | |
237 | bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, | | 237 | bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, |
238 | AWIN_A80_CCU_SCLK_SDMMC0_CLK_REG + (loc->loc_port * 4), 4, | | 238 | AWIN_A80_CCU_SCLK_SDMMC0_CLK_REG + (loc->loc_port * 4), 4, |
239 | &sc->sc_clk_bsh); | | 239 | &sc->sc_clk_bsh); |
240 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, | | 240 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, |
241 | AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_REG, | | 241 | AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_REG, |
242 | AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_SD, 0); | | 242 | AWIN_A80_CCU_SCLK_BUS_CLK_GATING0_SD, 0); |
243 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, | | 243 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, |
244 | AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_REG, | | 244 | AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_REG, |
245 | AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_SD, 0); | | 245 | AWIN_A80_CCU_SCLK_BUS_SOFT_RST0_SD, 0); |
246 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_core_bsh, | | 246 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_core_bsh, |
247 | AWIN_A80_SDMMC_COMM_OFFSET + (loc->loc_port * 4), | | 247 | AWIN_A80_SDMMC_COMM_OFFSET + (loc->loc_port * 4), |
248 | AWIN_A80_SDMMC_COMM_SDC_RESET_SW | | | 248 | AWIN_A80_SDMMC_COMM_SDC_RESET_SW | |
249 | AWIN_A80_SDMMC_COMM_SDC_CLOCK_SW, 0); | | 249 | AWIN_A80_SDMMC_COMM_SDC_CLOCK_SW, 0); |
250 | delay(1000); | | 250 | delay(1000); |
251 | } else { | | 251 | } else { |
252 | bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, | | 252 | bus_space_subregion(sc->sc_bst, aio->aio_ccm_bsh, |
253 | AWIN_SD0_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_clk_bsh); | | 253 | AWIN_SD0_CLK_REG + (loc->loc_port * 4), 4, &sc->sc_clk_bsh); |
254 | | | 254 | |
255 | awin_pll6_enable(); | | 255 | awin_pll6_enable(); |
256 | | | 256 | |
257 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, | | 257 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, |
258 | AWIN_AHB_GATING0_REG, | | 258 | AWIN_AHB_GATING0_REG, |
259 | AWIN_AHB_GATING0_SDMMC0 << loc->loc_port, 0); | | 259 | AWIN_AHB_GATING0_SDMMC0 << loc->loc_port, 0); |
260 | if (awin_chip_id() == AWIN_CHIP_ID_A31) { | | 260 | if (awin_chip_id() == AWIN_CHIP_ID_A31) { |
261 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, | | 261 | awin_reg_set_clear(aio->aio_core_bst, aio->aio_ccm_bsh, |
262 | AWIN_A31_AHB_RESET0_REG, | | 262 | AWIN_A31_AHB_RESET0_REG, |
263 | AWIN_A31_AHB_RESET0_SD0_RST << loc->loc_port, 0); | | 263 | AWIN_A31_AHB_RESET0_SD0_RST << loc->loc_port, 0); |
264 | } | | 264 | } |
265 | } | | 265 | } |
266 | | | 266 | |
267 | if (prop_dictionary_get_cstring_nocopy(cfg, "detect-gpio", &pin_name)) { | | 267 | if (prop_dictionary_get_cstring_nocopy(cfg, "detect-gpio", &pin_name)) { |
268 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_detect)) { | | 268 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_detect)) { |
269 | aprint_error_dev(self, | | 269 | aprint_error_dev(self, |
270 | "failed to reserve GPIO \"%s\"\n", pin_name); | | 270 | "failed to reserve GPIO \"%s\"\n", pin_name); |
271 | } else { | | 271 | } else { |
272 | sc->sc_has_gpio_detect = true; | | 272 | sc->sc_has_gpio_detect = true; |
273 | } | | 273 | } |
274 | } | | 274 | } |
275 | if (prop_dictionary_get_cstring_nocopy(cfg, "wp-gpio", &pin_name)) { | | 275 | if (prop_dictionary_get_cstring_nocopy(cfg, "wp-gpio", &pin_name)) { |
276 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_wp)) { | | 276 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_wp)) { |
277 | aprint_error_dev(self, | | 277 | aprint_error_dev(self, |
278 | "failed to reserve GPIO \"%s\"\n", pin_name); | | 278 | "failed to reserve GPIO \"%s\"\n", pin_name); |
279 | } else { | | 279 | } else { |
280 | sc->sc_has_gpio_wp = true; | | 280 | sc->sc_has_gpio_wp = true; |
281 | } | | 281 | } |
282 | } | | 282 | } |
283 | if (prop_dictionary_get_cstring_nocopy(cfg, "led-gpio", &pin_name)) { | | 283 | if (prop_dictionary_get_cstring_nocopy(cfg, "led-gpio", &pin_name)) { |
284 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_led)) { | | 284 | if (!awin_gpio_pin_reserve(pin_name, &sc->sc_gpio_led)) { |
285 | aprint_error_dev(self, | | 285 | aprint_error_dev(self, |
286 | "failed to reserve GPIO \"%s\"\n", pin_name); | | 286 | "failed to reserve GPIO \"%s\"\n", pin_name); |
287 | } else { | | 287 | } else { |
288 | sc->sc_has_gpio_led = true; | | 288 | sc->sc_has_gpio_led = true; |
289 | } | | 289 | } |
290 | } | | 290 | } |
291 | | | 291 | |
292 | switch (awin_chip_id()) { | | 292 | switch (awin_chip_id()) { |
293 | case AWIN_CHIP_ID_A80: | | 293 | case AWIN_CHIP_ID_A80: |
294 | sc->sc_fifo_reg = AWIN_A31_MMC_FIFO; | | 294 | sc->sc_fifo_reg = AWIN_A31_MMC_FIFO; |
295 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A80; | | 295 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A80; |
296 | break; | | 296 | break; |
297 | case AWIN_CHIP_ID_A31: | | 297 | case AWIN_CHIP_ID_A31: |
298 | sc->sc_fifo_reg = AWIN_A31_MMC_FIFO; | | 298 | sc->sc_fifo_reg = AWIN_A31_MMC_FIFO; |
299 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A20; | | 299 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A20; |
300 | break; | | 300 | break; |
301 | default: | | 301 | default: |
302 | sc->sc_fifo_reg = AWIN_MMC_FIFO; | | 302 | sc->sc_fifo_reg = AWIN_MMC_FIFO; |
303 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A20; | | 303 | sc->sc_dma_ftrglevel = AWIN_MMC_DMA_FTRGLEVEL_A20; |
304 | break; | | 304 | break; |
305 | } | | 305 | } |
306 | | | 306 | |
307 | if (sc->sc_use_dma) { | | 307 | if (sc->sc_use_dma) { |
308 | if (awin_mmc_idma_setup(sc) != 0) { | | 308 | if (awin_mmc_idma_setup(sc) != 0) { |
309 | aprint_error_dev(self, "failed to setup DMA\n"); | | 309 | aprint_error_dev(self, "failed to setup DMA\n"); |
310 | return; | | 310 | return; |
311 | } | | 311 | } |
312 | } | | 312 | } |
313 | | | 313 | |
314 | sc->sc_ih = intr_establish(loc->loc_intr, IPL_BIO, IST_LEVEL, | | 314 | sc->sc_ih = intr_establish(loc->loc_intr, IPL_BIO, IST_LEVEL, |
315 | awin_mmc_intr, sc); | | 315 | awin_mmc_intr, sc); |
316 | if (sc->sc_ih == NULL) { | | 316 | if (sc->sc_ih == NULL) { |
317 | aprint_error_dev(self, "couldn't establish interrupt %d\n", | | 317 | aprint_error_dev(self, "couldn't establish interrupt %d\n", |
318 | loc->loc_intr); | | 318 | loc->loc_intr); |
319 | return; | | 319 | return; |
320 | } | | 320 | } |
321 | aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr); | | 321 | aprint_normal_dev(self, "interrupting at irq %d\n", loc->loc_intr); |
322 | | | 322 | |
323 | config_interrupts(self, awin_mmc_attach_i); | | 323 | config_interrupts(self, awin_mmc_attach_i); |
324 | } | | 324 | } |
325 | | | 325 | |
326 | static int | | 326 | static int |
327 | awin_mmc_set_clock(struct awin_mmc_softc *sc, u_int freq) | | 327 | awin_mmc_set_clock(struct awin_mmc_softc *sc, u_int freq) |
328 | { | | 328 | { |
329 | uint32_t odly, sdly, clksrc, n, m, clk; | | 329 | uint32_t odly, sdly, clksrc, n, m, clk; |
330 | u_int osc24m_freq = AWIN_REF_FREQ / 1000; | | 330 | u_int osc24m_freq = AWIN_REF_FREQ / 1000; |
331 | u_int pll_freq; | | 331 | u_int pll_freq; |
332 | | | 332 | |
333 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { | | 333 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { |
334 | pll_freq = awin_periph0_get_rate() / 1000; | | 334 | pll_freq = awin_periph0_get_rate() / 1000; |
335 | } else { | | 335 | } else { |
336 | pll_freq = awin_pll6_get_rate() / 1000; | | 336 | pll_freq = awin_pll6_get_rate() / 1000; |
337 | } | | 337 | } |
338 | | | 338 | |
339 | #ifdef AWIN_MMC_DEBUG | | 339 | #ifdef AWIN_MMC_DEBUG |
340 | aprint_normal_dev(sc->sc_dev, "freq = %d, pll_freq = %d\n", | | 340 | aprint_normal_dev(sc->sc_dev, "freq = %d, pll_freq = %d\n", |
341 | freq, pll_freq); | | 341 | freq, pll_freq); |
342 | #endif | | 342 | #endif |
343 | | | 343 | |
344 | if (freq <= 400) { | | 344 | if (freq <= 400) { |
345 | odly = 0; | | 345 | odly = 0; |
346 | sdly = 0; | | 346 | sdly = 0; |
347 | clksrc = AWIN_SD_CLK_SRC_SEL_OSC24M; | | 347 | clksrc = AWIN_SD_CLK_SRC_SEL_OSC24M; |
348 | n = 2; | | 348 | n = 2; |
349 | m = ((osc24m_freq / (1 << n)) / freq) - 1; | | 349 | if (freq > 0) |
| | | 350 | m = ((osc24m_freq / (1 << n)) / freq) - 1; |
| | | 351 | else |
| | | 352 | m = 15; |
350 | } else if (freq <= 25000) { | | 353 | } else if (freq <= 25000) { |
351 | odly = 0; | | 354 | odly = 0; |
352 | sdly = 5; | | 355 | sdly = 5; |
353 | clksrc = AWIN_SD_CLK_SRC_SEL_PLL6; | | 356 | clksrc = AWIN_SD_CLK_SRC_SEL_PLL6; |
354 | n = awin_chip_id() == AWIN_CHIP_ID_A80 ? 2 : 0; | | 357 | n = awin_chip_id() == AWIN_CHIP_ID_A80 ? 2 : 0; |
355 | m = ((pll_freq / freq) / (1 << n)) - 1; | | 358 | m = ((pll_freq / freq) / (1 << n)) - 1; |
356 | } else if (freq <= 50000) { | | 359 | } else if (freq <= 50000) { |
357 | odly = awin_chip_id() == AWIN_CHIP_ID_A80 ? 5 : 3; | | 360 | odly = awin_chip_id() == AWIN_CHIP_ID_A80 ? 5 : 3; |
358 | sdly = awin_chip_id() == AWIN_CHIP_ID_A80 ? 4 : 5; | | 361 | sdly = awin_chip_id() == AWIN_CHIP_ID_A80 ? 4 : 5; |
359 | clksrc = AWIN_SD_CLK_SRC_SEL_PLL6; | | 362 | clksrc = AWIN_SD_CLK_SRC_SEL_PLL6; |
360 | n = awin_chip_id() == AWIN_CHIP_ID_A80 ? 2 : 0; | | 363 | n = awin_chip_id() == AWIN_CHIP_ID_A80 ? 2 : 0; |
361 | m = ((pll_freq / freq) / (1 << n)) - 1; | | 364 | m = ((pll_freq / freq) / (1 << n)) - 1; |
362 | } else { | | 365 | } else { |
363 | /* UHS speeds not implemented yet */ | | 366 | /* UHS speeds not implemented yet */ |
364 | return EIO; | | 367 | return EIO; |
365 | } | | 368 | } |
366 | | | 369 | |
367 | clk = bus_space_read_4(sc->sc_bst, sc->sc_clk_bsh, 0); | | 370 | clk = bus_space_read_4(sc->sc_bst, sc->sc_clk_bsh, 0); |
368 | clk &= ~AWIN_SD_CLK_SRC_SEL; | | 371 | clk &= ~AWIN_SD_CLK_SRC_SEL; |
369 | clk |= __SHIFTIN(clksrc, AWIN_SD_CLK_SRC_SEL); | | 372 | clk |= __SHIFTIN(clksrc, AWIN_SD_CLK_SRC_SEL); |
370 | clk &= ~AWIN_SD_CLK_DIV_RATIO_N; | | 373 | clk &= ~AWIN_SD_CLK_DIV_RATIO_N; |
371 | clk |= __SHIFTIN(n, AWIN_SD_CLK_DIV_RATIO_N); | | 374 | clk |= __SHIFTIN(n, AWIN_SD_CLK_DIV_RATIO_N); |
372 | clk &= ~AWIN_SD_CLK_DIV_RATIO_M; | | 375 | clk &= ~AWIN_SD_CLK_DIV_RATIO_M; |
373 | clk |= __SHIFTIN(m, AWIN_SD_CLK_DIV_RATIO_M); | | 376 | clk |= __SHIFTIN(m, AWIN_SD_CLK_DIV_RATIO_M); |
374 | clk &= ~AWIN_SD_CLK_OUTPUT_PHASE_CTR; | | 377 | clk &= ~AWIN_SD_CLK_OUTPUT_PHASE_CTR; |
375 | clk |= __SHIFTIN(odly, AWIN_SD_CLK_OUTPUT_PHASE_CTR); | | 378 | clk |= __SHIFTIN(odly, AWIN_SD_CLK_OUTPUT_PHASE_CTR); |
376 | clk &= ~AWIN_SD_CLK_PHASE_CTR; | | 379 | clk &= ~AWIN_SD_CLK_PHASE_CTR; |
377 | clk |= __SHIFTIN(sdly, AWIN_SD_CLK_PHASE_CTR); | | 380 | clk |= __SHIFTIN(sdly, AWIN_SD_CLK_PHASE_CTR); |
378 | clk |= AWIN_PLL_CFG_ENABLE; | | 381 | clk |= AWIN_PLL_CFG_ENABLE; |
379 | bus_space_write_4(sc->sc_bst, sc->sc_clk_bsh, 0, clk); | | 382 | bus_space_write_4(sc->sc_bst, sc->sc_clk_bsh, 0, clk); |
380 | | | 383 | |
381 | return 0; | | 384 | return 0; |
382 | } | | 385 | } |
383 | | | 386 | |
384 | static void | | 387 | static void |
385 | awin_mmc_attach_i(device_t self) | | 388 | awin_mmc_attach_i(device_t self) |
386 | { | | 389 | { |
387 | struct awin_mmc_softc *sc = device_private(self); | | 390 | struct awin_mmc_softc *sc = device_private(self); |
388 | struct sdmmcbus_attach_args saa; | | 391 | struct sdmmcbus_attach_args saa; |
389 | | | 392 | |
390 | awin_mmc_host_reset(sc); | | 393 | awin_mmc_host_reset(sc); |
391 | awin_mmc_bus_width(sc, 1); | | 394 | awin_mmc_bus_width(sc, 1); |
392 | awin_mmc_set_clock(sc, 400); | | 395 | awin_mmc_set_clock(sc, 400); |
393 | | | 396 | |
394 | memset(&saa, 0, sizeof(saa)); | | 397 | memset(&saa, 0, sizeof(saa)); |
395 | saa.saa_busname = "sdmmc"; | | 398 | saa.saa_busname = "sdmmc"; |
396 | saa.saa_sct = &awin_mmc_chip_functions; | | 399 | saa.saa_sct = &awin_mmc_chip_functions; |
397 | saa.saa_sch = sc; | | 400 | saa.saa_sch = sc; |
398 | saa.saa_clkmin = 400; | | 401 | saa.saa_clkmin = 400; |
399 | saa.saa_clkmax = awin_chip_id() == AWIN_CHIP_ID_A80 ? 48000 : 50000; | | 402 | saa.saa_clkmax = awin_chip_id() == AWIN_CHIP_ID_A80 ? 48000 : 50000; |
400 | saa.saa_caps = SMC_CAPS_4BIT_MODE| | | 403 | saa.saa_caps = SMC_CAPS_4BIT_MODE| |
401 | SMC_CAPS_8BIT_MODE| | | 404 | SMC_CAPS_8BIT_MODE| |
402 | SMC_CAPS_SD_HIGHSPEED| | | 405 | SMC_CAPS_SD_HIGHSPEED| |
403 | SMC_CAPS_MMC_HIGHSPEED| | | 406 | SMC_CAPS_MMC_HIGHSPEED| |
404 | SMC_CAPS_AUTO_STOP; | | 407 | SMC_CAPS_AUTO_STOP; |
405 | if (sc->sc_use_dma) { | | 408 | if (sc->sc_use_dma) { |
406 | saa.saa_dmat = sc->sc_dmat; | | 409 | saa.saa_dmat = sc->sc_dmat; |
407 | saa.saa_caps |= SMC_CAPS_DMA| | | 410 | saa.saa_caps |= SMC_CAPS_DMA| |
408 | SMC_CAPS_MULTI_SEG_DMA; | | 411 | SMC_CAPS_MULTI_SEG_DMA; |
409 | } | | 412 | } |
410 | if (sc->sc_has_gpio_detect) { | | 413 | if (sc->sc_has_gpio_detect) { |
411 | saa.saa_caps |= SMC_CAPS_POLL_CARD_DET; | | 414 | saa.saa_caps |= SMC_CAPS_POLL_CARD_DET; |
412 | } | | 415 | } |
413 | | | 416 | |
414 | sc->sc_sdmmc_dev = config_found(self, &saa, NULL); | | 417 | sc->sc_sdmmc_dev = config_found(self, &saa, NULL); |
415 | } | | 418 | } |
416 | | | 419 | |
417 | static int | | 420 | static int |
418 | awin_mmc_intr(void *priv) | | 421 | awin_mmc_intr(void *priv) |
419 | { | | 422 | { |
420 | struct awin_mmc_softc *sc = priv; | | 423 | struct awin_mmc_softc *sc = priv; |
421 | uint32_t idst, rint, mint; | | 424 | uint32_t idst, rint, mint; |
422 | | | 425 | |
423 | mutex_enter(&sc->sc_intr_lock); | | 426 | mutex_enter(&sc->sc_intr_lock); |
424 | idst = MMC_READ(sc, AWIN_MMC_IDST); | | 427 | idst = MMC_READ(sc, AWIN_MMC_IDST); |
425 | rint = MMC_READ(sc, AWIN_MMC_RINT); | | 428 | rint = MMC_READ(sc, AWIN_MMC_RINT); |
426 | mint = MMC_READ(sc, AWIN_MMC_MINT); | | 429 | mint = MMC_READ(sc, AWIN_MMC_MINT); |
427 | if (!idst && !rint && !mint) { | | 430 | if (!idst && !rint && !mint) { |
428 | mutex_exit(&sc->sc_intr_lock); | | 431 | mutex_exit(&sc->sc_intr_lock); |
429 | return 0; | | 432 | return 0; |
430 | } | | 433 | } |
431 | MMC_WRITE(sc, AWIN_MMC_IDST, idst); | | 434 | MMC_WRITE(sc, AWIN_MMC_IDST, idst); |
432 | MMC_WRITE(sc, AWIN_MMC_RINT, rint); | | 435 | MMC_WRITE(sc, AWIN_MMC_RINT, rint); |
433 | MMC_WRITE(sc, AWIN_MMC_MINT, mint); | | 436 | MMC_WRITE(sc, AWIN_MMC_MINT, mint); |
434 | | | 437 | |
435 | #ifdef AWIN_MMC_DEBUG | | 438 | #ifdef AWIN_MMC_DEBUG |
436 | device_printf(sc->sc_dev, "mmc intr idst=%08X rint=%08X mint=%08X\n", | | 439 | device_printf(sc->sc_dev, "mmc intr idst=%08X rint=%08X mint=%08X\n", |
437 | idst, rint, mint); | | 440 | idst, rint, mint); |
438 | #endif | | 441 | #endif |
439 | | | 442 | |
440 | if (idst) { | | 443 | if (idst) { |
441 | sc->sc_idma_idst |= idst; | | 444 | sc->sc_idma_idst |= idst; |
442 | cv_broadcast(&sc->sc_idst_cv); | | 445 | cv_broadcast(&sc->sc_idst_cv); |
443 | } | | 446 | } |
444 | | | 447 | |
445 | if (rint) { | | 448 | if (rint) { |
446 | sc->sc_intr_rint |= rint; | | 449 | sc->sc_intr_rint |= rint; |
447 | cv_broadcast(&sc->sc_intr_cv); | | 450 | cv_broadcast(&sc->sc_intr_cv); |
448 | } | | 451 | } |
449 | | | 452 | |
450 | mutex_exit(&sc->sc_intr_lock); | | 453 | mutex_exit(&sc->sc_intr_lock); |
451 | | | 454 | |
452 | return 1; | | 455 | return 1; |
453 | } | | 456 | } |
454 | | | 457 | |
455 | static int | | 458 | static int |
456 | awin_mmc_wait_rint(struct awin_mmc_softc *sc, uint32_t mask, int timeout) | | 459 | awin_mmc_wait_rint(struct awin_mmc_softc *sc, uint32_t mask, int timeout) |
457 | { | | 460 | { |
458 | int retry; | | 461 | int retry; |
459 | int error; | | 462 | int error; |
460 | | | 463 | |
461 | KASSERT(mutex_owned(&sc->sc_intr_lock)); | | 464 | KASSERT(mutex_owned(&sc->sc_intr_lock)); |
462 | | | 465 | |
463 | if (sc->sc_intr_rint & mask) | | 466 | if (sc->sc_intr_rint & mask) |
464 | return 0; | | 467 | return 0; |
465 | | | 468 | |
466 | retry = sc->sc_use_dma ? (timeout / hz) : 10000; | | 469 | retry = sc->sc_use_dma ? (timeout / hz) : 10000; |
467 | | | 470 | |
468 | while (retry > 0) { | | 471 | while (retry > 0) { |
469 | if (sc->sc_use_dma) { | | 472 | if (sc->sc_use_dma) { |
470 | error = cv_timedwait(&sc->sc_intr_cv, | | 473 | error = cv_timedwait(&sc->sc_intr_cv, |
471 | &sc->sc_intr_lock, hz); | | 474 | &sc->sc_intr_lock, hz); |
472 | if (error && error != EWOULDBLOCK) | | 475 | if (error && error != EWOULDBLOCK) |
473 | return error; | | 476 | return error; |
474 | if (sc->sc_intr_rint & mask) | | 477 | if (sc->sc_intr_rint & mask) |
475 | return 0; | | 478 | return 0; |
476 | } else { | | 479 | } else { |
477 | sc->sc_intr_rint |= MMC_READ(sc, AWIN_MMC_RINT); | | 480 | sc->sc_intr_rint |= MMC_READ(sc, AWIN_MMC_RINT); |
478 | if (sc->sc_intr_rint & mask) | | 481 | if (sc->sc_intr_rint & mask) |
479 | return 0; | | 482 | return 0; |
480 | delay(1000); | | 483 | delay(1000); |
481 | } | | 484 | } |
482 | --retry; | | 485 | --retry; |
483 | } | | 486 | } |
484 | | | 487 | |
485 | return ETIMEDOUT; | | 488 | return ETIMEDOUT; |
486 | } | | 489 | } |
487 | | | 490 | |
488 | static void | | 491 | static void |
489 | awin_mmc_led(struct awin_mmc_softc *sc, int on) | | 492 | awin_mmc_led(struct awin_mmc_softc *sc, int on) |
490 | { | | 493 | { |
491 | if (!sc->sc_has_gpio_led) | | 494 | if (!sc->sc_has_gpio_led) |
492 | return; | | 495 | return; |
493 | awin_gpio_pindata_write(&sc->sc_gpio_led, on); | | 496 | awin_gpio_pindata_write(&sc->sc_gpio_led, on); |
494 | } | | 497 | } |
495 | | | 498 | |
496 | static int | | 499 | static int |
497 | awin_mmc_host_reset(sdmmc_chipset_handle_t sch) | | 500 | awin_mmc_host_reset(sdmmc_chipset_handle_t sch) |
498 | { | | 501 | { |
499 | struct awin_mmc_softc *sc = sch; | | 502 | struct awin_mmc_softc *sc = sch; |
500 | int retry = 1000; | | 503 | int retry = 1000; |
501 | | | 504 | |
502 | #ifdef AWIN_MMC_DEBUG | | 505 | #ifdef AWIN_MMC_DEBUG |
503 | aprint_normal_dev(sc->sc_dev, "host reset\n"); | | 506 | aprint_normal_dev(sc->sc_dev, "host reset\n"); |
504 | #endif | | 507 | #endif |
505 | | | 508 | |
506 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { | | 509 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { |
507 | if (sc->sc_mmc_port == 2 || sc->sc_mmc_port == 3) { | | 510 | if (sc->sc_mmc_port == 2 || sc->sc_mmc_port == 3) { |
508 | MMC_WRITE(sc, AWIN_MMC_HWRST, 0); | | 511 | MMC_WRITE(sc, AWIN_MMC_HWRST, 0); |
509 | delay(10); | | 512 | delay(10); |
510 | MMC_WRITE(sc, AWIN_MMC_HWRST, 1); | | 513 | MMC_WRITE(sc, AWIN_MMC_HWRST, 1); |
511 | delay(300); | | 514 | delay(300); |
512 | } | | 515 | } |
513 | } | | 516 | } |
514 | | | 517 | |
515 | MMC_WRITE(sc, AWIN_MMC_GCTRL, | | 518 | MMC_WRITE(sc, AWIN_MMC_GCTRL, |
516 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_RESET); | | 519 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_RESET); |
517 | while (--retry > 0) { | | 520 | while (--retry > 0) { |
518 | if (!(MMC_READ(sc, AWIN_MMC_GCTRL) & AWIN_MMC_GCTRL_RESET)) | | 521 | if (!(MMC_READ(sc, AWIN_MMC_GCTRL) & AWIN_MMC_GCTRL_RESET)) |
519 | break; | | 522 | break; |
520 | delay(100); | | 523 | delay(100); |
521 | } | | 524 | } |
522 | | | 525 | |
523 | MMC_WRITE(sc, AWIN_MMC_TIMEOUT, 0xffffffff); | | 526 | MMC_WRITE(sc, AWIN_MMC_TIMEOUT, 0xffffffff); |
524 | | | 527 | |
525 | MMC_WRITE(sc, AWIN_MMC_IMASK, | | 528 | MMC_WRITE(sc, AWIN_MMC_IMASK, |
526 | AWIN_MMC_INT_CMD_DONE | AWIN_MMC_INT_ERROR | | | 529 | AWIN_MMC_INT_CMD_DONE | AWIN_MMC_INT_ERROR | |
527 | AWIN_MMC_INT_DATA_OVER | AWIN_MMC_INT_AUTO_CMD_DONE); | | 530 | AWIN_MMC_INT_DATA_OVER | AWIN_MMC_INT_AUTO_CMD_DONE); |
528 | | | 531 | |
529 | MMC_WRITE(sc, AWIN_MMC_GCTRL, | | 532 | MMC_WRITE(sc, AWIN_MMC_GCTRL, |
530 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_INTEN); | | 533 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_INTEN); |
531 | | | 534 | |
532 | | | 535 | |
533 | return 0; | | 536 | return 0; |
534 | } | | 537 | } |
535 | | | 538 | |
536 | static uint32_t | | 539 | static uint32_t |
537 | awin_mmc_host_ocr(sdmmc_chipset_handle_t sch) | | 540 | awin_mmc_host_ocr(sdmmc_chipset_handle_t sch) |
538 | { | | 541 | { |
539 | return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V | MMC_OCR_HCS; | | 542 | return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V | MMC_OCR_HCS; |
540 | } | | 543 | } |
541 | | | 544 | |
542 | static int | | 545 | static int |
543 | awin_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) | | 546 | awin_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) |
544 | { | | 547 | { |
545 | return 8192; | | 548 | return 8192; |
546 | } | | 549 | } |
547 | | | 550 | |
548 | static int | | 551 | static int |
549 | awin_mmc_card_detect(sdmmc_chipset_handle_t sch) | | 552 | awin_mmc_card_detect(sdmmc_chipset_handle_t sch) |
550 | { | | 553 | { |
551 | struct awin_mmc_softc *sc = sch; | | 554 | struct awin_mmc_softc *sc = sch; |
552 | | | 555 | |
553 | if (sc->sc_has_gpio_detect == false) { | | 556 | if (sc->sc_has_gpio_detect == false) { |
554 | return 1; /* no card detect pin, assume present */ | | 557 | return 1; /* no card detect pin, assume present */ |
555 | } else { | | 558 | } else { |
556 | int v = 0, i; | | 559 | int v = 0, i; |
557 | for (i = 0; i < 5; i++) { | | 560 | for (i = 0; i < 5; i++) { |
558 | v += awin_gpio_pindata_read(&sc->sc_gpio_detect); | | 561 | v += awin_gpio_pindata_read(&sc->sc_gpio_detect); |
559 | delay(1000); | | 562 | delay(1000); |
560 | } | | 563 | } |
561 | if (v == 5) | | 564 | if (v == 5) |
562 | sc->sc_mmc_present = 0; | | 565 | sc->sc_mmc_present = 0; |
563 | else if (v == 0) | | 566 | else if (v == 0) |
564 | sc->sc_mmc_present = 1; | | 567 | sc->sc_mmc_present = 1; |
565 | return sc->sc_mmc_present; | | 568 | return sc->sc_mmc_present; |
566 | } | | 569 | } |
567 | } | | 570 | } |
568 | | | 571 | |
569 | static int | | 572 | static int |
570 | awin_mmc_write_protect(sdmmc_chipset_handle_t sch) | | 573 | awin_mmc_write_protect(sdmmc_chipset_handle_t sch) |
571 | { | | 574 | { |
572 | struct awin_mmc_softc *sc = sch; | | 575 | struct awin_mmc_softc *sc = sch; |
573 | | | 576 | |
574 | if (sc->sc_has_gpio_wp == false) { | | 577 | if (sc->sc_has_gpio_wp == false) { |
575 | return 0; /* no write protect pin, assume rw */ | | 578 | return 0; /* no write protect pin, assume rw */ |
576 | } else { | | 579 | } else { |
577 | return awin_gpio_pindata_read(&sc->sc_gpio_wp); | | 580 | return awin_gpio_pindata_read(&sc->sc_gpio_wp); |
578 | } | | 581 | } |
579 | } | | 582 | } |
580 | | | 583 | |
581 | static int | | 584 | static int |
582 | awin_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) | | 585 | awin_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) |
583 | { | | 586 | { |
584 | return 0; | | 587 | return 0; |
585 | } | | 588 | } |
586 | | | 589 | |
587 | static int | | 590 | static int |
588 | awin_mmc_update_clock(struct awin_mmc_softc *sc) | | 591 | awin_mmc_update_clock(struct awin_mmc_softc *sc) |
589 | { | | 592 | { |
590 | uint32_t cmd; | | 593 | uint32_t cmd; |
591 | int retry; | | 594 | int retry; |
592 | | | 595 | |
593 | #ifdef AWIN_MMC_DEBUG | | 596 | #ifdef AWIN_MMC_DEBUG |
594 | aprint_normal_dev(sc->sc_dev, "update clock\n"); | | 597 | aprint_normal_dev(sc->sc_dev, "update clock\n"); |
595 | #endif | | 598 | #endif |
596 | | | 599 | |
597 | cmd = AWIN_MMC_CMD_START | | | 600 | cmd = AWIN_MMC_CMD_START | |
598 | AWIN_MMC_CMD_UPCLK_ONLY | | | 601 | AWIN_MMC_CMD_UPCLK_ONLY | |
599 | AWIN_MMC_CMD_WAIT_PRE_OVER; | | 602 | AWIN_MMC_CMD_WAIT_PRE_OVER; |
600 | MMC_WRITE(sc, AWIN_MMC_CMD, cmd); | | 603 | MMC_WRITE(sc, AWIN_MMC_CMD, cmd); |
601 | retry = 0xfffff; | | 604 | retry = 0xfffff; |
602 | while (--retry > 0) { | | 605 | while (--retry > 0) { |
603 | if (!(MMC_READ(sc, AWIN_MMC_CMD) & AWIN_MMC_CMD_START)) | | 606 | if (!(MMC_READ(sc, AWIN_MMC_CMD) & AWIN_MMC_CMD_START)) |
604 | break; | | 607 | break; |
605 | delay(10); | | 608 | delay(10); |
606 | } | | 609 | } |
607 | | | 610 | |
608 | if (retry == 0) { | | 611 | if (retry == 0) { |
609 | aprint_error_dev(sc->sc_dev, "timeout updating clock\n"); | | 612 | aprint_error_dev(sc->sc_dev, "timeout updating clock\n"); |
610 | #ifdef AWIN_MMC_DEBUG | | 613 | #ifdef AWIN_MMC_DEBUG |
611 | device_printf(sc->sc_dev, "GCTRL: 0x%08x\n", | | 614 | device_printf(sc->sc_dev, "GCTRL: 0x%08x\n", |
612 | MMC_READ(sc, AWIN_MMC_GCTRL)); | | 615 | MMC_READ(sc, AWIN_MMC_GCTRL)); |
613 | device_printf(sc->sc_dev, "CLKCR: 0x%08x\n", | | 616 | device_printf(sc->sc_dev, "CLKCR: 0x%08x\n", |
614 | MMC_READ(sc, AWIN_MMC_CLKCR)); | | 617 | MMC_READ(sc, AWIN_MMC_CLKCR)); |
615 | device_printf(sc->sc_dev, "TIMEOUT: 0x%08x\n", | | 618 | device_printf(sc->sc_dev, "TIMEOUT: 0x%08x\n", |
616 | MMC_READ(sc, AWIN_MMC_TIMEOUT)); | | 619 | MMC_READ(sc, AWIN_MMC_TIMEOUT)); |
617 | device_printf(sc->sc_dev, "WIDTH: 0x%08x\n", | | 620 | device_printf(sc->sc_dev, "WIDTH: 0x%08x\n", |
618 | MMC_READ(sc, AWIN_MMC_WIDTH)); | | 621 | MMC_READ(sc, AWIN_MMC_WIDTH)); |
619 | device_printf(sc->sc_dev, "CMD: 0x%08x\n", | | 622 | device_printf(sc->sc_dev, "CMD: 0x%08x\n", |
620 | MMC_READ(sc, AWIN_MMC_CMD)); | | 623 | MMC_READ(sc, AWIN_MMC_CMD)); |
621 | device_printf(sc->sc_dev, "MINT: 0x%08x\n", | | 624 | device_printf(sc->sc_dev, "MINT: 0x%08x\n", |
622 | MMC_READ(sc, AWIN_MMC_MINT)); | | 625 | MMC_READ(sc, AWIN_MMC_MINT)); |
623 | device_printf(sc->sc_dev, "RINT: 0x%08x\n", | | 626 | device_printf(sc->sc_dev, "RINT: 0x%08x\n", |
624 | MMC_READ(sc, AWIN_MMC_RINT)); | | 627 | MMC_READ(sc, AWIN_MMC_RINT)); |
625 | device_printf(sc->sc_dev, "STATUS: 0x%08x\n", | | 628 | device_printf(sc->sc_dev, "STATUS: 0x%08x\n", |
626 | MMC_READ(sc, AWIN_MMC_STATUS)); | | 629 | MMC_READ(sc, AWIN_MMC_STATUS)); |
627 | #endif | | 630 | #endif |
628 | return ETIMEDOUT; | | 631 | return ETIMEDOUT; |
629 | } | | 632 | } |
630 | | | 633 | |
631 | return 0; | | 634 | return 0; |
632 | } | | 635 | } |
633 | | | 636 | |
634 | static int | | 637 | static int |
635 | awin_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) | | 638 | awin_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) |
636 | { | | 639 | { |
637 | struct awin_mmc_softc *sc = sch; | | 640 | struct awin_mmc_softc *sc = sch; |
638 | uint32_t clkcr; | | 641 | uint32_t clkcr; |
639 | | | 642 | |
640 | clkcr = MMC_READ(sc, AWIN_MMC_CLKCR); | | 643 | clkcr = MMC_READ(sc, AWIN_MMC_CLKCR); |
641 | if (clkcr & AWIN_MMC_CLKCR_CARDCLKON) { | | 644 | if (clkcr & AWIN_MMC_CLKCR_CARDCLKON) { |
642 | clkcr &= ~AWIN_MMC_CLKCR_CARDCLKON; | | 645 | clkcr &= ~AWIN_MMC_CLKCR_CARDCLKON; |
643 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); | | 646 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); |
644 | if (awin_mmc_update_clock(sc) != 0) | | 647 | if (awin_mmc_update_clock(sc) != 0) |
645 | return 1; | | 648 | return 1; |
646 | } | | 649 | } |
647 | | | 650 | |
648 | if (freq) { | | 651 | if (freq) { |
649 | | | 652 | |
650 | clkcr &= ~AWIN_MMC_CLKCR_DIV; | | 653 | clkcr &= ~AWIN_MMC_CLKCR_DIV; |
651 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); | | 654 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); |
652 | if (awin_mmc_update_clock(sc) != 0) | | 655 | if (awin_mmc_update_clock(sc) != 0) |
653 | return 1; | | 656 | return 1; |
654 | | | 657 | |
655 | if (awin_mmc_set_clock(sc, freq) != 0) | | 658 | if (awin_mmc_set_clock(sc, freq) != 0) |
656 | return 1; | | 659 | return 1; |
657 | | | 660 | |
658 | clkcr |= AWIN_MMC_CLKCR_CARDCLKON; | | 661 | clkcr |= AWIN_MMC_CLKCR_CARDCLKON; |
659 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); | | 662 | MMC_WRITE(sc, AWIN_MMC_CLKCR, clkcr); |
660 | if (awin_mmc_update_clock(sc) != 0) | | 663 | if (awin_mmc_update_clock(sc) != 0) |
661 | return 1; | | 664 | return 1; |
662 | } | | 665 | } |
663 | | | 666 | |
664 | return 0; | | 667 | return 0; |
665 | } | | 668 | } |
666 | | | 669 | |
667 | static int | | 670 | static int |
668 | awin_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) | | 671 | awin_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) |
669 | { | | 672 | { |
670 | struct awin_mmc_softc *sc = sch; | | 673 | struct awin_mmc_softc *sc = sch; |
671 | | | 674 | |
672 | #ifdef AWIN_MMC_DEBUG | | 675 | #ifdef AWIN_MMC_DEBUG |
673 | aprint_normal_dev(sc->sc_dev, "width = %d\n", width); | | 676 | aprint_normal_dev(sc->sc_dev, "width = %d\n", width); |
674 | #endif | | 677 | #endif |
675 | | | 678 | |
676 | switch (width) { | | 679 | switch (width) { |
677 | case 1: | | 680 | case 1: |
678 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_1); | | 681 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_1); |
679 | break; | | 682 | break; |
680 | case 4: | | 683 | case 4: |
681 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_4); | | 684 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_4); |
682 | break; | | 685 | break; |
683 | case 8: | | 686 | case 8: |
684 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_8); | | 687 | MMC_WRITE(sc, AWIN_MMC_WIDTH, AWIN_MMC_WIDTH_8); |
685 | break; | | 688 | break; |
686 | default: | | 689 | default: |
687 | return 1; | | 690 | return 1; |
688 | } | | 691 | } |
689 | | | 692 | |
690 | sc->sc_mmc_width = width; | | 693 | sc->sc_mmc_width = width; |
691 | | | 694 | |
692 | return 0; | | 695 | return 0; |
693 | } | | 696 | } |
694 | | | 697 | |
695 | static int | | 698 | static int |
696 | awin_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) | | 699 | awin_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) |
697 | { | | 700 | { |
698 | return -1; | | 701 | return -1; |
699 | } | | 702 | } |
700 | | | 703 | |
701 | | | 704 | |
702 | static int | | 705 | static int |
703 | awin_mmc_pio_wait(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) | | 706 | awin_mmc_pio_wait(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) |
704 | { | | 707 | { |
705 | int retry = 0xfffff; | | 708 | int retry = 0xfffff; |
706 | uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ? | | 709 | uint32_t bit = (cmd->c_flags & SCF_CMD_READ) ? |
707 | AWIN_MMC_STATUS_FIFO_EMPTY : AWIN_MMC_STATUS_FIFO_FULL; | | 710 | AWIN_MMC_STATUS_FIFO_EMPTY : AWIN_MMC_STATUS_FIFO_FULL; |
708 | | | 711 | |
709 | while (--retry > 0) { | | 712 | while (--retry > 0) { |
710 | uint32_t status = MMC_READ(sc, AWIN_MMC_STATUS); | | 713 | uint32_t status = MMC_READ(sc, AWIN_MMC_STATUS); |
711 | if (!(status & bit)) | | 714 | if (!(status & bit)) |
712 | return 0; | | 715 | return 0; |
713 | delay(10); | | 716 | delay(10); |
714 | } | | 717 | } |
715 | | | 718 | |
716 | return ETIMEDOUT; | | 719 | return ETIMEDOUT; |
717 | } | | 720 | } |
718 | | | 721 | |
719 | static int | | 722 | static int |
720 | awin_mmc_pio_transfer(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) | | 723 | awin_mmc_pio_transfer(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) |
721 | { | | 724 | { |
722 | uint32_t *datap = (uint32_t *)cmd->c_data; | | 725 | uint32_t *datap = (uint32_t *)cmd->c_data; |
723 | int i; | | 726 | int i; |
724 | | | 727 | |
725 | for (i = 0; i < (cmd->c_resid >> 2); i++) { | | 728 | for (i = 0; i < (cmd->c_resid >> 2); i++) { |
726 | if (awin_mmc_pio_wait(sc, cmd)) | | 729 | if (awin_mmc_pio_wait(sc, cmd)) |
727 | return ETIMEDOUT; | | 730 | return ETIMEDOUT; |
728 | if (cmd->c_flags & SCF_CMD_READ) { | | 731 | if (cmd->c_flags & SCF_CMD_READ) { |
729 | datap[i] = MMC_READ(sc, sc->sc_fifo_reg); | | 732 | datap[i] = MMC_READ(sc, sc->sc_fifo_reg); |
730 | } else { | | 733 | } else { |
731 | MMC_WRITE(sc, sc->sc_fifo_reg, datap[i]); | | 734 | MMC_WRITE(sc, sc->sc_fifo_reg, datap[i]); |
732 | } | | 735 | } |
733 | } | | 736 | } |
734 | | | 737 | |
735 | return 0; | | 738 | return 0; |
736 | } | | 739 | } |
737 | | | 740 | |
738 | static int | | 741 | static int |
739 | awin_mmc_dma_prepare(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) | | 742 | awin_mmc_dma_prepare(struct awin_mmc_softc *sc, struct sdmmc_command *cmd) |
740 | { | | 743 | { |
741 | struct awin_mmc_idma_descriptor *dma = sc->sc_idma_desc; | | 744 | struct awin_mmc_idma_descriptor *dma = sc->sc_idma_desc; |
742 | bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr; | | 745 | bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr; |
743 | bus_size_t off; | | 746 | bus_size_t off; |
744 | int desc, resid, seg; | | 747 | int desc, resid, seg; |
745 | uint32_t val; | | 748 | uint32_t val; |
746 | | | 749 | |
747 | desc = 0; | | 750 | desc = 0; |
748 | for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { | | 751 | for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { |
749 | bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr; | | 752 | bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr; |
750 | bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; | | 753 | bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; |
751 | resid = min(len, cmd->c_resid); | | 754 | resid = min(len, cmd->c_resid); |
752 | off = 0; | | 755 | off = 0; |
753 | while (resid > 0) { | | 756 | while (resid > 0) { |
754 | if (desc == sc->sc_idma_ndesc) | | 757 | if (desc == sc->sc_idma_ndesc) |
755 | break; | | 758 | break; |
756 | len = min(sc->sc_idma_xferlen, resid); | | 759 | len = min(sc->sc_idma_xferlen, resid); |
757 | dma[desc].dma_buf_size = htole32(len); | | 760 | dma[desc].dma_buf_size = htole32(len); |
758 | dma[desc].dma_buf_addr = htole32(paddr + off); | | 761 | dma[desc].dma_buf_addr = htole32(paddr + off); |
759 | dma[desc].dma_config = htole32(AWIN_MMC_IDMA_CONFIG_CH | | | 762 | dma[desc].dma_config = htole32(AWIN_MMC_IDMA_CONFIG_CH | |
760 | AWIN_MMC_IDMA_CONFIG_OWN); | | 763 | AWIN_MMC_IDMA_CONFIG_OWN); |
761 | cmd->c_resid -= len; | | 764 | cmd->c_resid -= len; |
762 | resid -= len; | | 765 | resid -= len; |
763 | off += len; | | 766 | off += len; |
764 | if (desc == 0) { | | 767 | if (desc == 0) { |
765 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_FD); | | 768 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_FD); |
766 | } | | 769 | } |
767 | if (cmd->c_resid == 0) { | | 770 | if (cmd->c_resid == 0) { |
768 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_LD); | | 771 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_LD); |
769 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_ER); | | 772 | dma[desc].dma_config |= htole32(AWIN_MMC_IDMA_CONFIG_ER); |
770 | dma[desc].dma_next = 0; | | 773 | dma[desc].dma_next = 0; |
771 | } else { | | 774 | } else { |
772 | dma[desc].dma_config |= | | 775 | dma[desc].dma_config |= |
773 | htole32(AWIN_MMC_IDMA_CONFIG_DIC); | | 776 | htole32(AWIN_MMC_IDMA_CONFIG_DIC); |
774 | dma[desc].dma_next = htole32( | | 777 | dma[desc].dma_next = htole32( |
775 | desc_paddr + ((desc+1) * | | 778 | desc_paddr + ((desc+1) * |
776 | sizeof(struct awin_mmc_idma_descriptor))); | | 779 | sizeof(struct awin_mmc_idma_descriptor))); |
777 | } | | 780 | } |
778 | ++desc; | | 781 | ++desc; |
779 | } | | 782 | } |
780 | } | | 783 | } |
781 | if (desc == sc->sc_idma_ndesc) { | | 784 | if (desc == sc->sc_idma_ndesc) { |
782 | aprint_error_dev(sc->sc_dev, | | 785 | aprint_error_dev(sc->sc_dev, |
783 | "not enough descriptors for %d byte transfer!\n", | | 786 | "not enough descriptors for %d byte transfer!\n", |
784 | cmd->c_datalen); | | 787 | cmd->c_datalen); |
785 | return EIO; | | 788 | return EIO; |
786 | } | | 789 | } |
787 | | | 790 | |
788 | bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, | | 791 | bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, |
789 | sc->sc_idma_size, BUS_DMASYNC_PREWRITE); | | 792 | sc->sc_idma_size, BUS_DMASYNC_PREWRITE); |
790 | | | 793 | |
791 | sc->sc_idma_idst = 0; | | 794 | sc->sc_idma_idst = 0; |
792 | | | 795 | |
793 | val = MMC_READ(sc, AWIN_MMC_GCTRL); | | 796 | val = MMC_READ(sc, AWIN_MMC_GCTRL); |
794 | val |= AWIN_MMC_GCTRL_DMAEN; | | 797 | val |= AWIN_MMC_GCTRL_DMAEN; |
795 | val |= AWIN_MMC_GCTRL_INTEN; | | 798 | val |= AWIN_MMC_GCTRL_INTEN; |
796 | MMC_WRITE(sc, AWIN_MMC_GCTRL, val); | | 799 | MMC_WRITE(sc, AWIN_MMC_GCTRL, val); |
797 | val |= AWIN_MMC_GCTRL_DMARESET; | | 800 | val |= AWIN_MMC_GCTRL_DMARESET; |
798 | MMC_WRITE(sc, AWIN_MMC_GCTRL, val); | | 801 | MMC_WRITE(sc, AWIN_MMC_GCTRL, val); |
799 | MMC_WRITE(sc, AWIN_MMC_DMAC, AWIN_MMC_DMAC_SOFTRESET); | | 802 | MMC_WRITE(sc, AWIN_MMC_DMAC, AWIN_MMC_DMAC_SOFTRESET); |
800 | MMC_WRITE(sc, AWIN_MMC_DMAC, | | 803 | MMC_WRITE(sc, AWIN_MMC_DMAC, |
801 | AWIN_MMC_DMAC_IDMA_ON|AWIN_MMC_DMAC_FIX_BURST); | | 804 | AWIN_MMC_DMAC_IDMA_ON|AWIN_MMC_DMAC_FIX_BURST); |
802 | val = MMC_READ(sc, AWIN_MMC_IDIE); | | 805 | val = MMC_READ(sc, AWIN_MMC_IDIE); |
803 | val &= ~(AWIN_MMC_IDST_RECEIVE_INT|AWIN_MMC_IDST_TRANSMIT_INT); | | 806 | val &= ~(AWIN_MMC_IDST_RECEIVE_INT|AWIN_MMC_IDST_TRANSMIT_INT); |
804 | if (cmd->c_flags & SCF_CMD_READ) | | 807 | if (cmd->c_flags & SCF_CMD_READ) |
805 | val |= AWIN_MMC_IDST_RECEIVE_INT; | | 808 | val |= AWIN_MMC_IDST_RECEIVE_INT; |
806 | else | | 809 | else |
807 | val |= AWIN_MMC_IDST_TRANSMIT_INT; | | 810 | val |= AWIN_MMC_IDST_TRANSMIT_INT; |
808 | MMC_WRITE(sc, AWIN_MMC_IDIE, val); | | 811 | MMC_WRITE(sc, AWIN_MMC_IDIE, val); |
809 | MMC_WRITE(sc, AWIN_MMC_DLBA, desc_paddr); | | 812 | MMC_WRITE(sc, AWIN_MMC_DLBA, desc_paddr); |
810 | MMC_WRITE(sc, AWIN_MMC_FTRGLEVEL, sc->sc_dma_ftrglevel); | | 813 | MMC_WRITE(sc, AWIN_MMC_FTRGLEVEL, sc->sc_dma_ftrglevel); |
811 | | | 814 | |
812 | return 0; | | 815 | return 0; |
813 | } | | 816 | } |
814 | | | 817 | |
815 | static void | | 818 | static void |
816 | awin_mmc_dma_complete(struct awin_mmc_softc *sc) | | 819 | awin_mmc_dma_complete(struct awin_mmc_softc *sc) |
817 | { | | 820 | { |
818 | bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, | | 821 | bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, |
819 | sc->sc_idma_size, BUS_DMASYNC_POSTWRITE); | | 822 | sc->sc_idma_size, BUS_DMASYNC_POSTWRITE); |
820 | } | | 823 | } |
821 | | | 824 | |
822 | static void | | 825 | static void |
823 | awin_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) | | 826 | awin_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) |
824 | { | | 827 | { |
825 | struct awin_mmc_softc *sc = sch; | | 828 | struct awin_mmc_softc *sc = sch; |
826 | uint32_t cmdval = AWIN_MMC_CMD_START; | | 829 | uint32_t cmdval = AWIN_MMC_CMD_START; |
827 | | | 830 | |
828 | #ifdef AWIN_MMC_DEBUG | | 831 | #ifdef AWIN_MMC_DEBUG |
829 | aprint_normal_dev(sc->sc_dev, | | 832 | aprint_normal_dev(sc->sc_dev, |
830 | "opcode %d flags 0x%x data %p datalen %d blklen %d\n", | | 833 | "opcode %d flags 0x%x data %p datalen %d blklen %d\n", |
831 | cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen, | | 834 | cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen, |
832 | cmd->c_blklen); | | 835 | cmd->c_blklen); |
833 | #endif | | 836 | #endif |
834 | | | 837 | |
835 | mutex_enter(&sc->sc_intr_lock); | | 838 | mutex_enter(&sc->sc_intr_lock); |
836 | | | 839 | |
837 | if (cmd->c_opcode == 0) | | 840 | if (cmd->c_opcode == 0) |
838 | cmdval |= AWIN_MMC_CMD_SEND_INIT_SEQ; | | 841 | cmdval |= AWIN_MMC_CMD_SEND_INIT_SEQ; |
839 | if (cmd->c_flags & SCF_RSP_PRESENT) | | 842 | if (cmd->c_flags & SCF_RSP_PRESENT) |
840 | cmdval |= AWIN_MMC_CMD_RSP_EXP; | | 843 | cmdval |= AWIN_MMC_CMD_RSP_EXP; |
841 | if (cmd->c_flags & SCF_RSP_136) | | 844 | if (cmd->c_flags & SCF_RSP_136) |
842 | cmdval |= AWIN_MMC_CMD_LONG_RSP; | | 845 | cmdval |= AWIN_MMC_CMD_LONG_RSP; |
843 | if (cmd->c_flags & SCF_RSP_CRC) | | 846 | if (cmd->c_flags & SCF_RSP_CRC) |
844 | cmdval |= AWIN_MMC_CMD_CHECK_RSP_CRC; | | 847 | cmdval |= AWIN_MMC_CMD_CHECK_RSP_CRC; |
845 | | | 848 | |
846 | if (cmd->c_datalen > 0) { | | 849 | if (cmd->c_datalen > 0) { |
847 | unsigned int nblks; | | 850 | unsigned int nblks; |
848 | | | 851 | |
849 | cmdval |= AWIN_MMC_CMD_DATA_EXP | AWIN_MMC_CMD_WAIT_PRE_OVER; | | 852 | cmdval |= AWIN_MMC_CMD_DATA_EXP | AWIN_MMC_CMD_WAIT_PRE_OVER; |
850 | if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { | | 853 | if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { |
851 | cmdval |= AWIN_MMC_CMD_WRITE; | | 854 | cmdval |= AWIN_MMC_CMD_WRITE; |
852 | } | | 855 | } |
853 | | | 856 | |
854 | nblks = cmd->c_datalen / cmd->c_blklen; | | 857 | nblks = cmd->c_datalen / cmd->c_blklen; |
855 | if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) | | 858 | if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) |
856 | ++nblks; | | 859 | ++nblks; |
857 | | | 860 | |
858 | if (nblks > 1) { | | 861 | if (nblks > 1) { |
859 | cmdval |= AWIN_MMC_CMD_SEND_AUTO_STOP; | | 862 | cmdval |= AWIN_MMC_CMD_SEND_AUTO_STOP; |
860 | } | | 863 | } |
861 | | | 864 | |
862 | MMC_WRITE(sc, AWIN_MMC_BLKSZ, cmd->c_blklen); | | 865 | MMC_WRITE(sc, AWIN_MMC_BLKSZ, cmd->c_blklen); |
863 | MMC_WRITE(sc, AWIN_MMC_BYTECNT, nblks * cmd->c_blklen); | | 866 | MMC_WRITE(sc, AWIN_MMC_BYTECNT, nblks * cmd->c_blklen); |
864 | } | | 867 | } |
865 | | | 868 | |
866 | sc->sc_intr_rint = 0; | | 869 | sc->sc_intr_rint = 0; |
867 | | | 870 | |
868 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { | | 871 | if (awin_chip_id() == AWIN_CHIP_ID_A80) { |
869 | MMC_WRITE(sc, AWIN_MMC_A12A, | | 872 | MMC_WRITE(sc, AWIN_MMC_A12A, |
870 | (cmdval & AWIN_MMC_CMD_SEND_AUTO_STOP) ? 0 : 0xffff); | | 873 | (cmdval & AWIN_MMC_CMD_SEND_AUTO_STOP) ? 0 : 0xffff); |
871 | } | | 874 | } |
872 | | | 875 | |
873 | MMC_WRITE(sc, AWIN_MMC_ARG, cmd->c_arg); | | 876 | MMC_WRITE(sc, AWIN_MMC_ARG, cmd->c_arg); |
874 | | | 877 | |
875 | #ifdef AWIN_MMC_DEBUG | | 878 | #ifdef AWIN_MMC_DEBUG |
876 | aprint_normal_dev(sc->sc_dev, "cmdval = %08x\n", cmdval); | | 879 | aprint_normal_dev(sc->sc_dev, "cmdval = %08x\n", cmdval); |
877 | #endif | | 880 | #endif |
878 | | | 881 | |
879 | if (cmd->c_datalen == 0) { | | 882 | if (cmd->c_datalen == 0) { |
880 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); | | 883 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); |
881 | } else { | | 884 | } else { |
882 | cmd->c_resid = cmd->c_datalen; | | 885 | cmd->c_resid = cmd->c_datalen; |
883 | awin_mmc_led(sc, 0); | | 886 | awin_mmc_led(sc, 0); |
884 | if (sc->sc_use_dma) { | | 887 | if (sc->sc_use_dma) { |
885 | cmd->c_error = awin_mmc_dma_prepare(sc, cmd); | | 888 | cmd->c_error = awin_mmc_dma_prepare(sc, cmd); |
886 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); | | 889 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); |
887 | if (cmd->c_error == 0) { | | 890 | if (cmd->c_error == 0) { |
888 | cmd->c_error = cv_timedwait(&sc->sc_idst_cv, | | 891 | cmd->c_error = cv_timedwait(&sc->sc_idst_cv, |
889 | &sc->sc_intr_lock, hz*10); | | 892 | &sc->sc_intr_lock, hz*10); |
890 | } | | 893 | } |
891 | awin_mmc_dma_complete(sc); | | 894 | awin_mmc_dma_complete(sc); |
892 | if (sc->sc_idma_idst & AWIN_MMC_IDST_ERROR) { | | 895 | if (sc->sc_idma_idst & AWIN_MMC_IDST_ERROR) { |
893 | cmd->c_error = EIO; | | 896 | cmd->c_error = EIO; |
894 | } else if (!(sc->sc_idma_idst & AWIN_MMC_IDST_COMPLETE)) { | | 897 | } else if (!(sc->sc_idma_idst & AWIN_MMC_IDST_COMPLETE)) { |
895 | cmd->c_error = ETIMEDOUT; | | 898 | cmd->c_error = ETIMEDOUT; |
896 | } | | 899 | } |
897 | } else { | | 900 | } else { |
898 | mutex_exit(&sc->sc_intr_lock); | | 901 | mutex_exit(&sc->sc_intr_lock); |
899 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); | | 902 | MMC_WRITE(sc, AWIN_MMC_CMD, cmdval | cmd->c_opcode); |
900 | cmd->c_error = awin_mmc_pio_transfer(sc, cmd); | | 903 | cmd->c_error = awin_mmc_pio_transfer(sc, cmd); |
901 | mutex_enter(&sc->sc_intr_lock); | | 904 | mutex_enter(&sc->sc_intr_lock); |
902 | } | | 905 | } |
903 | awin_mmc_led(sc, 1); | | 906 | awin_mmc_led(sc, 1); |
904 | if (cmd->c_error) { | | 907 | if (cmd->c_error) { |
905 | #ifdef AWIN_MMC_DEBUG | | 908 | #ifdef AWIN_MMC_DEBUG |
906 | aprint_error_dev(sc->sc_dev, | | 909 | aprint_error_dev(sc->sc_dev, |
907 | "xfer failed, error %d\n", cmd->c_error); | | 910 | "xfer failed, error %d\n", cmd->c_error); |
908 | #endif | | 911 | #endif |
909 | goto done; | | 912 | goto done; |
910 | } | | 913 | } |
911 | } | | 914 | } |
912 | | | 915 | |
913 | cmd->c_error = awin_mmc_wait_rint(sc, | | 916 | cmd->c_error = awin_mmc_wait_rint(sc, |
914 | AWIN_MMC_INT_ERROR|AWIN_MMC_INT_CMD_DONE, hz * 10); | | 917 | AWIN_MMC_INT_ERROR|AWIN_MMC_INT_CMD_DONE, hz * 10); |
915 | if (cmd->c_error == 0 && (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) { | | 918 | if (cmd->c_error == 0 && (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) { |
916 | if (sc->sc_intr_rint & AWIN_MMC_INT_RESP_TIMEOUT) { | | 919 | if (sc->sc_intr_rint & AWIN_MMC_INT_RESP_TIMEOUT) { |
917 | cmd->c_error = ETIMEDOUT; | | 920 | cmd->c_error = ETIMEDOUT; |
918 | } else { | | 921 | } else { |
919 | cmd->c_error = EIO; | | 922 | cmd->c_error = EIO; |
920 | } | | 923 | } |
921 | } | | 924 | } |
922 | if (cmd->c_error) { | | 925 | if (cmd->c_error) { |
923 | #ifdef AWIN_MMC_DEBUG | | 926 | #ifdef AWIN_MMC_DEBUG |
924 | aprint_error_dev(sc->sc_dev, | | 927 | aprint_error_dev(sc->sc_dev, |
925 | "cmd failed, error %d\n", cmd->c_error); | | 928 | "cmd failed, error %d\n", cmd->c_error); |
926 | #endif | | 929 | #endif |
927 | goto done; | | 930 | goto done; |
928 | } | | 931 | } |
929 | | | 932 | |
930 | if (cmd->c_datalen > 0) { | | 933 | if (cmd->c_datalen > 0) { |
931 | cmd->c_error = awin_mmc_wait_rint(sc, | | 934 | cmd->c_error = awin_mmc_wait_rint(sc, |
932 | AWIN_MMC_INT_ERROR| | | 935 | AWIN_MMC_INT_ERROR| |
933 | AWIN_MMC_INT_AUTO_CMD_DONE| | | 936 | AWIN_MMC_INT_AUTO_CMD_DONE| |
934 | AWIN_MMC_INT_DATA_OVER, | | 937 | AWIN_MMC_INT_DATA_OVER, |
935 | hz*10); | | 938 | hz*10); |
936 | if (cmd->c_error == 0 && | | 939 | if (cmd->c_error == 0 && |
937 | (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) { | | 940 | (sc->sc_intr_rint & AWIN_MMC_INT_ERROR)) { |
938 | cmd->c_error = ETIMEDOUT; | | 941 | cmd->c_error = ETIMEDOUT; |
939 | } | | 942 | } |
940 | if (cmd->c_error) { | | 943 | if (cmd->c_error) { |
941 | #ifdef AWIN_MMC_DEBUG | | 944 | #ifdef AWIN_MMC_DEBUG |
942 | aprint_error_dev(sc->sc_dev, | | 945 | aprint_error_dev(sc->sc_dev, |
943 | "data timeout, rint = %08x\n", | | 946 | "data timeout, rint = %08x\n", |
944 | sc->sc_intr_rint); | | 947 | sc->sc_intr_rint); |
945 | #endif | | 948 | #endif |
946 | cmd->c_error = ETIMEDOUT; | | 949 | cmd->c_error = ETIMEDOUT; |
947 | goto done; | | 950 | goto done; |
948 | } | | 951 | } |
949 | } | | 952 | } |
950 | | | 953 | |
951 | if (cmd->c_flags & SCF_RSP_PRESENT) { | | 954 | if (cmd->c_flags & SCF_RSP_PRESENT) { |
952 | if (cmd->c_flags & SCF_RSP_136) { | | 955 | if (cmd->c_flags & SCF_RSP_136) { |
953 | cmd->c_resp[0] = MMC_READ(sc, AWIN_MMC_RESP0); | | 956 | cmd->c_resp[0] = MMC_READ(sc, AWIN_MMC_RESP0); |
954 | cmd->c_resp[1] = MMC_READ(sc, AWIN_MMC_RESP1); | | 957 | cmd->c_resp[1] = MMC_READ(sc, AWIN_MMC_RESP1); |
955 | cmd->c_resp[2] = MMC_READ(sc, AWIN_MMC_RESP2); | | 958 | cmd->c_resp[2] = MMC_READ(sc, AWIN_MMC_RESP2); |
956 | cmd->c_resp[3] = MMC_READ(sc, AWIN_MMC_RESP3); | | 959 | cmd->c_resp[3] = MMC_READ(sc, AWIN_MMC_RESP3); |
957 | if (cmd->c_flags & SCF_RSP_CRC) { | | 960 | if (cmd->c_flags & SCF_RSP_CRC) { |
958 | cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | | | 961 | cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | |
959 | (cmd->c_resp[1] << 24); | | 962 | (cmd->c_resp[1] << 24); |
960 | cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | | | 963 | cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | |
961 | (cmd->c_resp[2] << 24); | | 964 | (cmd->c_resp[2] << 24); |
962 | cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | | | 965 | cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | |
963 | (cmd->c_resp[3] << 24); | | 966 | (cmd->c_resp[3] << 24); |
964 | cmd->c_resp[3] = (cmd->c_resp[3] >> 8); | | 967 | cmd->c_resp[3] = (cmd->c_resp[3] >> 8); |
965 | } | | 968 | } |
966 | } else { | | 969 | } else { |
967 | cmd->c_resp[0] = MMC_READ(sc, AWIN_MMC_RESP0); | | 970 | cmd->c_resp[0] = MMC_READ(sc, AWIN_MMC_RESP0); |
968 | } | | 971 | } |
969 | } | | 972 | } |
970 | | | 973 | |
971 | done: | | 974 | done: |
972 | cmd->c_flags |= SCF_ITSDONE; | | 975 | cmd->c_flags |= SCF_ITSDONE; |
973 | mutex_exit(&sc->sc_intr_lock); | | 976 | mutex_exit(&sc->sc_intr_lock); |
974 | | | 977 | |
975 | if (cmd->c_error) { | | 978 | if (cmd->c_error) { |
976 | #ifdef AWIN_MMC_DEBUG | | 979 | #ifdef AWIN_MMC_DEBUG |
977 | aprint_error_dev(sc->sc_dev, "i/o error %d\n", cmd->c_error); | | 980 | aprint_error_dev(sc->sc_dev, "i/o error %d\n", cmd->c_error); |
978 | #endif | | 981 | #endif |
979 | MMC_WRITE(sc, AWIN_MMC_GCTRL, | | 982 | MMC_WRITE(sc, AWIN_MMC_GCTRL, |
980 | MMC_READ(sc, AWIN_MMC_GCTRL) | | | 983 | MMC_READ(sc, AWIN_MMC_GCTRL) | |
981 | AWIN_MMC_GCTRL_DMARESET | AWIN_MMC_GCTRL_FIFORESET); | | 984 | AWIN_MMC_GCTRL_DMARESET | AWIN_MMC_GCTRL_FIFORESET); |
982 | for (int retry = 0; retry < 1000; retry++) { | | 985 | for (int retry = 0; retry < 1000; retry++) { |
983 | if (!(MMC_READ(sc, AWIN_MMC_GCTRL) & AWIN_MMC_GCTRL_RESET)) | | 986 | if (!(MMC_READ(sc, AWIN_MMC_GCTRL) & AWIN_MMC_GCTRL_RESET)) |
984 | break; | | 987 | break; |
985 | delay(10); | | 988 | delay(10); |
986 | } | | 989 | } |
987 | awin_mmc_update_clock(sc); | | 990 | awin_mmc_update_clock(sc); |
988 | } | | 991 | } |
989 | | | 992 | |
990 | if (!sc->sc_use_dma) { | | 993 | if (!sc->sc_use_dma) { |
991 | MMC_WRITE(sc, AWIN_MMC_GCTRL, | | 994 | MMC_WRITE(sc, AWIN_MMC_GCTRL, |
992 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_FIFORESET); | | 995 | MMC_READ(sc, AWIN_MMC_GCTRL) | AWIN_MMC_GCTRL_FIFORESET); |
993 | } | | 996 | } |
994 | } | | 997 | } |
995 | | | 998 | |
996 | static void | | 999 | static void |
997 | awin_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) | | 1000 | awin_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) |
998 | { | | 1001 | { |
999 | } | | 1002 | } |
1000 | | | 1003 | |
1001 | static void | | 1004 | static void |
1002 | awin_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) | | 1005 | awin_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) |
1003 | { | | 1006 | { |
1004 | } | | 1007 | } |