| @@ -1,39 +1,39 @@ | | | @@ -1,39 +1,39 @@ |
1 | /* $NetBSD: sdhc.c,v 1.54 2015/02/27 15:53:09 nonaka Exp $ */ | | 1 | /* $NetBSD: sdhc.c,v 1.55 2015/04/14 18:34:29 bouyer Exp $ */ |
2 | /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ | | 2 | /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange 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 | /* | | 20 | /* |
21 | * SD Host Controller driver based on the SD Host Controller Standard | | 21 | * SD Host Controller driver based on the SD Host Controller Standard |
22 | * Simplified Specification Version 1.00 (www.sdcard.com). | | 22 | * Simplified Specification Version 1.00 (www.sdcard.com). |
23 | */ | | 23 | */ |
24 | | | 24 | |
25 | #include <sys/cdefs.h> | | 25 | #include <sys/cdefs.h> |
26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.54 2015/02/27 15:53:09 nonaka Exp $"); | | 26 | __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.55 2015/04/14 18:34:29 bouyer Exp $"); |
27 | | | 27 | |
28 | #ifdef _KERNEL_OPT | | 28 | #ifdef _KERNEL_OPT |
29 | #include "opt_sdmmc.h" | | 29 | #include "opt_sdmmc.h" |
30 | #endif | | 30 | #endif |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/device.h> | | 33 | #include <sys/device.h> |
34 | #include <sys/kernel.h> | | 34 | #include <sys/kernel.h> |
35 | #include <sys/kthread.h> | | 35 | #include <sys/kthread.h> |
36 | #include <sys/malloc.h> | | 36 | #include <sys/malloc.h> |
37 | #include <sys/systm.h> | | 37 | #include <sys/systm.h> |
38 | #include <sys/mutex.h> | | 38 | #include <sys/mutex.h> |
39 | #include <sys/condvar.h> | | 39 | #include <sys/condvar.h> |
| @@ -76,26 +76,27 @@ struct sdhc_host { | | | @@ -76,26 +76,27 @@ struct sdhc_host { |
76 | uint8_t regs[14]; /* host controller state */ | | 76 | uint8_t regs[14]; /* host controller state */ |
77 | | | 77 | |
78 | uint16_t intr_status; /* soft interrupt status */ | | 78 | uint16_t intr_status; /* soft interrupt status */ |
79 | uint16_t intr_error_status; /* soft error status */ | | 79 | uint16_t intr_error_status; /* soft error status */ |
80 | struct kmutex intr_mtx; | | 80 | struct kmutex intr_mtx; |
81 | struct kcondvar intr_cv; | | 81 | struct kcondvar intr_cv; |
82 | | | 82 | |
83 | int specver; /* spec. version */ | | 83 | int specver; /* spec. version */ |
84 | | | 84 | |
85 | uint32_t flags; /* flags for this host */ | | 85 | uint32_t flags; /* flags for this host */ |
86 | #define SHF_USE_DMA 0x0001 | | 86 | #define SHF_USE_DMA 0x0001 |
87 | #define SHF_USE_4BIT_MODE 0x0002 | | 87 | #define SHF_USE_4BIT_MODE 0x0002 |
88 | #define SHF_USE_8BIT_MODE 0x0004 | | 88 | #define SHF_USE_8BIT_MODE 0x0004 |
| | | 89 | #define SHF_MODE_DMAEN 0x0008 /* needs SDHC_DMA_ENABLE in mode */ |
89 | }; | | 90 | }; |
90 | | | 91 | |
91 | #define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev)) | | 92 | #define HDEVNAME(hp) (device_xname((hp)->sc->sc_dev)) |
92 | | | 93 | |
93 | static uint8_t | | 94 | static uint8_t |
94 | hread1(struct sdhc_host *hp, bus_size_t reg) | | 95 | hread1(struct sdhc_host *hp, bus_size_t reg) |
95 | { | | 96 | { |
96 | | | 97 | |
97 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) | | 98 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) |
98 | return bus_space_read_1(hp->iot, hp->ioh, reg); | | 99 | return bus_space_read_1(hp->iot, hp->ioh, reg); |
99 | return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 3)); | | 100 | return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 3)); |
100 | } | | 101 | } |
101 | | | 102 | |
| @@ -299,31 +300,39 @@ sdhc_host_found(struct sdhc_softc *sc, b | | | @@ -299,31 +300,39 @@ sdhc_host_found(struct sdhc_softc *sc, b |
299 | * Reset the host controller and enable interrupts. | | 300 | * Reset the host controller and enable interrupts. |
300 | */ | | 301 | */ |
301 | (void)sdhc_host_reset(hp); | | 302 | (void)sdhc_host_reset(hp); |
302 | | | 303 | |
303 | /* Determine host capabilities. */ | | 304 | /* Determine host capabilities. */ |
304 | if (ISSET(sc->sc_flags, SDHC_FLAG_HOSTCAPS)) { | | 305 | if (ISSET(sc->sc_flags, SDHC_FLAG_HOSTCAPS)) { |
305 | caps = sc->sc_caps; | | 306 | caps = sc->sc_caps; |
306 | } else { | | 307 | } else { |
307 | mutex_enter(&hp->host_mtx); | | 308 | mutex_enter(&hp->host_mtx); |
308 | caps = HREAD4(hp, SDHC_CAPABILITIES); | | 309 | caps = HREAD4(hp, SDHC_CAPABILITIES); |
309 | mutex_exit(&hp->host_mtx); | | 310 | mutex_exit(&hp->host_mtx); |
310 | } | | 311 | } |
311 | | | 312 | |
312 | /* Use DMA if the host system and the controller support it. */ | | 313 | /* |
| | | 314 | * Use DMA if the host system and the controller support it. |
| | | 315 | * Suports integrated or external DMA egine, with or without |
| | | 316 | * SDHC_DMA_ENABLE in the command. |
| | | 317 | */ |
313 | if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) || | | 318 | if (ISSET(sc->sc_flags, SDHC_FLAG_FORCE_DMA) || |
314 | (ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA && | | 319 | (ISSET(sc->sc_flags, SDHC_FLAG_USE_DMA && |
315 | ISSET(caps, SDHC_DMA_SUPPORT)))) { | | 320 | ISSET(caps, SDHC_DMA_SUPPORT)))) { |
316 | SET(hp->flags, SHF_USE_DMA); | | 321 | SET(hp->flags, SHF_USE_DMA); |
| | | 322 | if (!ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA) || |
| | | 323 | ISSET(sc->sc_flags, SDHC_FLAG_EXTDMA_DMAEN)) |
| | | 324 | SET(hp->flags, SHF_MODE_DMAEN); |
| | | 325 | |
317 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); | | 326 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); |
318 | } | | 327 | } |
319 | | | 328 | |
320 | /* | | 329 | /* |
321 | * Determine the base clock frequency. (2.2.24) | | 330 | * Determine the base clock frequency. (2.2.24) |
322 | */ | | 331 | */ |
323 | if (hp->specver == SDHC_SPEC_VERS_300) { | | 332 | if (hp->specver == SDHC_SPEC_VERS_300) { |
324 | hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps); | | 333 | hp->clkbase = SDHC_BASE_V3_FREQ_KHZ(caps); |
325 | } else { | | 334 | } else { |
326 | hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); | | 335 | hp->clkbase = SDHC_BASE_FREQ_KHZ(caps); |
327 | } | | 336 | } |
328 | if (hp->clkbase == 0) { | | 337 | if (hp->clkbase == 0) { |
329 | if (sc->sc_clkbase == 0) { | | 338 | if (sc->sc_clkbase == 0) { |
| @@ -1195,27 +1204,27 @@ sdhc_start_command(struct sdhc_host *hp, | | | @@ -1195,27 +1204,27 @@ sdhc_start_command(struct sdhc_host *hp, |
1195 | return EINVAL; | | 1204 | return EINVAL; |
1196 | } | | 1205 | } |
1197 | | | 1206 | |
1198 | /* Prepare transfer mode register value. (2.2.5) */ | | 1207 | /* Prepare transfer mode register value. (2.2.5) */ |
1199 | mode = SDHC_BLOCK_COUNT_ENABLE; | | 1208 | mode = SDHC_BLOCK_COUNT_ENABLE; |
1200 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) | | 1209 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) |
1201 | mode |= SDHC_READ_MODE; | | 1210 | mode |= SDHC_READ_MODE; |
1202 | if (blkcount > 1) { | | 1211 | if (blkcount > 1) { |
1203 | mode |= SDHC_MULTI_BLOCK_MODE; | | 1212 | mode |= SDHC_MULTI_BLOCK_MODE; |
1204 | /* XXX only for memory commands? */ | | 1213 | /* XXX only for memory commands? */ |
1205 | mode |= SDHC_AUTO_CMD12_ENABLE; | | 1214 | mode |= SDHC_AUTO_CMD12_ENABLE; |
1206 | } | | 1215 | } |
1207 | if (cmd->c_dmamap != NULL && cmd->c_datalen > 0 && | | 1216 | if (cmd->c_dmamap != NULL && cmd->c_datalen > 0 && |
1208 | !ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA)) { | | 1217 | ISSET(hp->flags, SHF_MODE_DMAEN)) { |
1209 | mode |= SDHC_DMA_ENABLE; | | 1218 | mode |= SDHC_DMA_ENABLE; |
1210 | } | | 1219 | } |
1211 | | | 1220 | |
1212 | /* | | 1221 | /* |
1213 | * Prepare command register value. (2.2.6) | | 1222 | * Prepare command register value. (2.2.6) |
1214 | */ | | 1223 | */ |
1215 | command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; | | 1224 | command = (cmd->c_opcode & SDHC_COMMAND_INDEX_MASK) << SDHC_COMMAND_INDEX_SHIFT; |
1216 | | | 1225 | |
1217 | if (ISSET(cmd->c_flags, SCF_RSP_CRC)) | | 1226 | if (ISSET(cmd->c_flags, SCF_RSP_CRC)) |
1218 | command |= SDHC_CRC_CHECK_ENABLE; | | 1227 | command |= SDHC_CRC_CHECK_ENABLE; |
1219 | if (ISSET(cmd->c_flags, SCF_RSP_IDX)) | | 1228 | if (ISSET(cmd->c_flags, SCF_RSP_IDX)) |
1220 | command |= SDHC_INDEX_CHECK_ENABLE; | | 1229 | command |= SDHC_INDEX_CHECK_ENABLE; |
1221 | if (cmd->c_data != NULL) | | 1230 | if (cmd->c_data != NULL) |
| @@ -1241,27 +1250,28 @@ sdhc_start_command(struct sdhc_host *hp, | | | @@ -1241,27 +1250,28 @@ sdhc_start_command(struct sdhc_host *hp, |
1241 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { | | 1250 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
1242 | blksize |= (MAX(0, PAGE_SHIFT - 12) & SDHC_DMA_BOUNDARY_MASK) << | | 1251 | blksize |= (MAX(0, PAGE_SHIFT - 12) & SDHC_DMA_BOUNDARY_MASK) << |
1243 | SDHC_DMA_BOUNDARY_SHIFT; /* PAGE_SIZE DMA boundary */ | | 1252 | SDHC_DMA_BOUNDARY_SHIFT; /* PAGE_SIZE DMA boundary */ |
1244 | } | | 1253 | } |
1245 | | | 1254 | |
1246 | mutex_enter(&hp->host_mtx); | | 1255 | mutex_enter(&hp->host_mtx); |
1247 | | | 1256 | |
1248 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { | | 1257 | if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) { |
1249 | /* Alert the user not to remove the card. */ | | 1258 | /* Alert the user not to remove the card. */ |
1250 | HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON); | | 1259 | HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON); |
1251 | } | | 1260 | } |
1252 | | | 1261 | |
1253 | /* Set DMA start address. */ | | 1262 | /* Set DMA start address. */ |
1254 | if (ISSET(mode, SDHC_DMA_ENABLE)) | | 1263 | if (ISSET(mode, SDHC_DMA_ENABLE) && |
| | | 1264 | !ISSET(sc->sc_flags, SDHC_FLAG_EXTERNAL_DMA)) |
1255 | HWRITE4(hp, SDHC_DMA_ADDR, cmd->c_dmamap->dm_segs[0].ds_addr); | | 1265 | HWRITE4(hp, SDHC_DMA_ADDR, cmd->c_dmamap->dm_segs[0].ds_addr); |
1256 | | | 1266 | |
1257 | /* | | 1267 | /* |
1258 | * Start a CPU data transfer. Writing to the high order byte | | 1268 | * Start a CPU data transfer. Writing to the high order byte |
1259 | * of the SDHC_COMMAND register triggers the SD command. (1.5) | | 1269 | * of the SDHC_COMMAND register triggers the SD command. (1.5) |
1260 | */ | | 1270 | */ |
1261 | if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { | | 1271 | if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) { |
1262 | HWRITE4(hp, SDHC_BLOCK_SIZE, blksize | (blkcount << 16)); | | 1272 | HWRITE4(hp, SDHC_BLOCK_SIZE, blksize | (blkcount << 16)); |
1263 | HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); | | 1273 | HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg); |
1264 | HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16)); | | 1274 | HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16)); |
1265 | } else { | | 1275 | } else { |
1266 | HWRITE2(hp, SDHC_BLOCK_SIZE, blksize); | | 1276 | HWRITE2(hp, SDHC_BLOCK_SIZE, blksize); |
1267 | HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount); | | 1277 | HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount); |