| @@ -1,34 +1,34 @@ | | | @@ -1,34 +1,34 @@ |
1 | /* $NetBSD: pxa2x0_mci.c,v 1.4 2010/03/13 12:28:44 nonaka Exp $ */ | | 1 | /* $NetBSD: pxa2x0_mci.c,v 1.5 2010/04/06 15:55:46 nonaka Exp $ */ |
2 | /* $OpenBSD: pxa2x0_mmc.c,v 1.5 2009/02/23 18:09:55 miod Exp $ */ | | 2 | /* $OpenBSD: pxa2x0_mmc.c,v 1.5 2009/02/23 18:09:55 miod Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> | | 5 | * Copyright (c) 2007 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 | * Copyright (c) 2007-2009 NONAKA Kimihiro <nonaka@netbsd.org> | | 21 | * Copyright (c) 2007-2010 NONAKA Kimihiro <nonaka@netbsd.org> |
22 | * All rights reserved. | | 22 | * All rights reserved. |
23 | * | | 23 | * |
24 | * Redistribution and use in source and binary forms, with or without | | 24 | * Redistribution and use in source and binary forms, with or without |
25 | * modification, are permitted provided that the following conditions | | 25 | * modification, are permitted provided that the following conditions |
26 | * are met: | | 26 | * are met: |
27 | * 1. Redistributions of source code must retain the above copyright | | 27 | * 1. Redistributions of source code must retain the above copyright |
28 | * notice, this list of conditions and the following disclaimer. | | 28 | * notice, this list of conditions and the following disclaimer. |
29 | * 2. Redistributions in binary form must reproduce the above copyright | | 29 | * 2. Redistributions in binary form must reproduce the above copyright |
30 | * notice, this list of conditions and the following disclaimer in the | | 30 | * notice, this list of conditions and the following disclaimer in the |
31 | * documentation and/or other materials provided with the distribution. | | 31 | * documentation and/or other materials provided with the distribution. |
32 | * | | 32 | * |
33 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 33 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| @@ -44,63 +44,63 @@ | | | @@ -44,63 +44,63 @@ |
44 | */ | | 44 | */ |
45 | | | 45 | |
46 | /* | | 46 | /* |
47 | * MMC/SD/SDIO controller driver for Intel PXA2xx processors | | 47 | * MMC/SD/SDIO controller driver for Intel PXA2xx processors |
48 | * | | 48 | * |
49 | * Power management is beyond control of the processor's SD/SDIO/MMC | | 49 | * Power management is beyond control of the processor's SD/SDIO/MMC |
50 | * block, so this driver depends on the attachment driver to provide | | 50 | * block, so this driver depends on the attachment driver to provide |
51 | * us with some callback functions via the "tag" member in our softc. | | 51 | * us with some callback functions via the "tag" member in our softc. |
52 | * Bus power management calls are then dispatched to the attachment | | 52 | * Bus power management calls are then dispatched to the attachment |
53 | * driver. | | 53 | * driver. |
54 | */ | | 54 | */ |
55 | | | 55 | |
56 | #include <sys/cdefs.h> | | 56 | #include <sys/cdefs.h> |
57 | __KERNEL_RCSID(0, "$NetBSD: pxa2x0_mci.c,v 1.4 2010/03/13 12:28:44 nonaka Exp $"); | | 57 | __KERNEL_RCSID(0, "$NetBSD: pxa2x0_mci.c,v 1.5 2010/04/06 15:55:46 nonaka Exp $"); |
58 | | | 58 | |
59 | #include <sys/param.h> | | 59 | #include <sys/param.h> |
60 | #include <sys/device.h> | | 60 | #include <sys/device.h> |
61 | #include <sys/systm.h> | | 61 | #include <sys/systm.h> |
62 | #include <sys/malloc.h> | | 62 | #include <sys/malloc.h> |
63 | #include <sys/kernel.h> | | 63 | #include <sys/kernel.h> |
64 | #include <sys/proc.h> | | 64 | #include <sys/proc.h> |
65 | #include <sys/bus.h> | | 65 | #include <sys/bus.h> |
66 | #include <sys/mutex.h> | | 66 | #include <sys/mutex.h> |
67 | #include <sys/condvar.h> | | 67 | #include <sys/condvar.h> |
68 | | | 68 | |
69 | #include <machine/intr.h> | | 69 | #include <machine/intr.h> |
70 | | | 70 | |
71 | #include <dev/sdmmc/sdmmcvar.h> | | 71 | #include <dev/sdmmc/sdmmcvar.h> |
72 | #include <dev/sdmmc/sdmmcchip.h> | | 72 | #include <dev/sdmmc/sdmmcchip.h> |
73 | | | 73 | |
74 | #include <arm/xscale/pxa2x0cpu.h> | | 74 | #include <arm/xscale/pxa2x0cpu.h> |
75 | #include <arm/xscale/pxa2x0reg.h> | | 75 | #include <arm/xscale/pxa2x0reg.h> |
76 | #include <arm/xscale/pxa2x0var.h> | | 76 | #include <arm/xscale/pxa2x0var.h> |
77 | #include <arm/xscale/pxa2x0_dmac.h> | | 77 | #include <arm/xscale/pxa2x0_dmac.h> |
78 | #include <arm/xscale/pxa2x0_gpio.h> | | 78 | #include <arm/xscale/pxa2x0_gpio.h> |
79 | #include <arm/xscale/pxa2x0_mci.h> | | 79 | #include <arm/xscale/pxa2x0_mci.h> |
80 | | | 80 | |
81 | #ifdef PXAMCI_DEBUG | | 81 | #ifdef PXAMCI_DEBUG |
82 | int pxamci_debug = 1; | | 82 | int pxamci_debug = 9; |
83 | #define DPRINTF(n,s) do { if ((n) <= pxamci_debug) printf s; } while (0) | | 83 | #define DPRINTF(n,s) do { if ((n) <= pxamci_debug) printf s; } while (0) |
84 | #else | | 84 | #else |
85 | #define DPRINTF(n,s) do {} while (0) | | 85 | #define DPRINTF(n,s) do {} while (0) |
86 | #endif | | 86 | #endif |
87 | | | 87 | |
88 | #ifndef DEBUG | | 88 | #ifndef PXAMCI_DEBUG |
89 | #define STOPCLK_TIMO 2 /* ms */ | | 89 | #define STOPCLK_TIMO 2 /* sec */ |
90 | #define EXECCMD_TIMO 2 /* ms */ | | 90 | #define EXECCMD_TIMO 2 /* sec */ |
91 | #else | | 91 | #else |
92 | #define STOPCLK_TIMO 2 /* ms */ | | 92 | #define STOPCLK_TIMO 2 /* sec */ |
93 | #define EXECCMD_TIMO 5 /* ms */ | | 93 | #define EXECCMD_TIMO 5 /* sec */ |
94 | #endif | | 94 | #endif |
95 | | | 95 | |
96 | static int pxamci_host_reset(sdmmc_chipset_handle_t); | | 96 | static int pxamci_host_reset(sdmmc_chipset_handle_t); |
97 | static uint32_t pxamci_host_ocr(sdmmc_chipset_handle_t); | | 97 | static uint32_t pxamci_host_ocr(sdmmc_chipset_handle_t); |
98 | static int pxamci_host_maxblklen(sdmmc_chipset_handle_t); | | 98 | static int pxamci_host_maxblklen(sdmmc_chipset_handle_t); |
99 | static int pxamci_card_detect(sdmmc_chipset_handle_t); | | 99 | static int pxamci_card_detect(sdmmc_chipset_handle_t); |
100 | static int pxamci_write_protect(sdmmc_chipset_handle_t); | | 100 | static int pxamci_write_protect(sdmmc_chipset_handle_t); |
101 | static int pxamci_bus_power(sdmmc_chipset_handle_t, uint32_t); | | 101 | static int pxamci_bus_power(sdmmc_chipset_handle_t, uint32_t); |
102 | static int pxamci_bus_clock(sdmmc_chipset_handle_t, int); | | 102 | static int pxamci_bus_clock(sdmmc_chipset_handle_t, int); |
103 | static int pxamci_bus_width(sdmmc_chipset_handle_t, int); | | 103 | static int pxamci_bus_width(sdmmc_chipset_handle_t, int); |
104 | static void pxamci_exec_command(sdmmc_chipset_handle_t, | | 104 | static void pxamci_exec_command(sdmmc_chipset_handle_t, |
105 | struct sdmmc_command *); | | 105 | struct sdmmc_command *); |
106 | static void pxamci_card_enable_intr(sdmmc_chipset_handle_t, int); | | 106 | static void pxamci_card_enable_intr(sdmmc_chipset_handle_t, int); |
| @@ -145,26 +145,34 @@ static void pxamci_stop_clock(struct pxa | | | @@ -145,26 +145,34 @@ static void pxamci_stop_clock(struct pxa |
145 | #define CSR_READ_1(sc, reg) \ | | 145 | #define CSR_READ_1(sc, reg) \ |
146 | bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg)) | | 146 | bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (reg)) |
147 | #define CSR_WRITE_1(sc, reg, val) \ | | 147 | #define CSR_WRITE_1(sc, reg, val) \ |
148 | bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) | | 148 | bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) |
149 | #define CSR_READ_4(sc, reg) \ | | 149 | #define CSR_READ_4(sc, reg) \ |
150 | bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) | | 150 | bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) |
151 | #define CSR_WRITE_4(sc, reg, val) \ | | 151 | #define CSR_WRITE_4(sc, reg, val) \ |
152 | bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) | | 152 | bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) |
153 | #define CSR_SET_4(sc, reg, val) \ | | 153 | #define CSR_SET_4(sc, reg, val) \ |
154 | CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (val)) | | 154 | CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (val)) |
155 | #define CSR_CLR_4(sc, reg, val) \ | | 155 | #define CSR_CLR_4(sc, reg, val) \ |
156 | CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(val)) | | 156 | CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(val)) |
157 | | | 157 | |
| | | 158 | #if 0 /* XXX */ |
| | | 159 | #define DMA_ALIGNED(addr) \ |
| | | 160 | (((u_long)(addr) & 0x7) == 0 || !CPU_IS_PXA250) |
| | | 161 | #else |
| | | 162 | #define DMA_ALIGNED(addr) \ |
| | | 163 | (((u_long)(addr) & 0x1f) == 0) |
| | | 164 | #endif |
| | | 165 | |
158 | static void | | 166 | static void |
159 | pxamci_enable_intr(struct pxamci_softc *sc, uint32_t mask) | | 167 | pxamci_enable_intr(struct pxamci_softc *sc, uint32_t mask) |
160 | { | | 168 | { |
161 | int s; | | 169 | int s; |
162 | | | 170 | |
163 | s = splsdmmc(); | | 171 | s = splsdmmc(); |
164 | sc->sc_imask &= ~mask; | | 172 | sc->sc_imask &= ~mask; |
165 | CSR_WRITE_4(sc, MMC_I_MASK, sc->sc_imask); | | 173 | CSR_WRITE_4(sc, MMC_I_MASK, sc->sc_imask); |
166 | splx(s); | | 174 | splx(s); |
167 | } | | 175 | } |
168 | | | 176 | |
169 | static void | | 177 | static void |
170 | pxamci_disable_intr(struct pxamci_softc *sc, uint32_t mask) | | 178 | pxamci_disable_intr(struct pxamci_softc *sc, uint32_t mask) |
| @@ -228,29 +236,26 @@ pxamci_attach_sub(device_t self, struct | | | @@ -228,29 +236,26 @@ pxamci_attach_sub(device_t self, struct |
228 | pxamci_bus_clock(sc, sc->sc_clkbase); | | 236 | pxamci_bus_clock(sc, sc->sc_clkbase); |
229 | | | 237 | |
230 | /* Setup max block length */ | | 238 | /* Setup max block length */ |
231 | if (CPU_IS_PXA270) { | | 239 | if (CPU_IS_PXA270) { |
232 | sc->sc_maxblklen = 2048; | | 240 | sc->sc_maxblklen = 2048; |
233 | } else { | | 241 | } else { |
234 | sc->sc_maxblklen = 512; | | 242 | sc->sc_maxblklen = 512; |
235 | } | | 243 | } |
236 | | | 244 | |
237 | /* Set default bus width */ | | 245 | /* Set default bus width */ |
238 | sc->sc_buswidth = 1; | | 246 | sc->sc_buswidth = 1; |
239 | | | 247 | |
240 | /* setting DMA */ | | 248 | /* setting DMA */ |
241 | #if 1 /* XXX */ | | | |
242 | SET(sc->sc_caps, PMC_CAPS_NO_DMA); /* disable DMA */ | | | |
243 | #endif | | | |
244 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { | | 249 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { |
245 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); | | 250 | aprint_normal_dev(sc->sc_dev, "using DMA transfer\n"); |
246 | | | 251 | |
247 | sc->sc_rxdr.ds_addr = PXA2X0_MMC_BASE + MMC_RXFIFO; | | 252 | sc->sc_rxdr.ds_addr = PXA2X0_MMC_BASE + MMC_RXFIFO; |
248 | sc->sc_rxdr.ds_len = 1; | | 253 | sc->sc_rxdr.ds_len = 1; |
249 | sc->sc_rxdx = pxa2x0_dmac_allocate_xfer(M_NOWAIT); | | 254 | sc->sc_rxdx = pxa2x0_dmac_allocate_xfer(M_NOWAIT); |
250 | if (sc->sc_rxdx == NULL) { | | 255 | if (sc->sc_rxdx == NULL) { |
251 | aprint_error_dev(sc->sc_dev, | | 256 | aprint_error_dev(sc->sc_dev, |
252 | "couldn't alloc rx dma xfer\n"); | | 257 | "couldn't alloc rx dma xfer\n"); |
253 | goto free_intr; | | 258 | goto free_intr; |
254 | } | | 259 | } |
255 | sc->sc_rxdx->dx_cookie = sc; | | 260 | sc->sc_rxdx->dx_cookie = sc; |
256 | sc->sc_rxdx->dx_priority = DMAC_PRIORITY_NORMAL; | | 261 | sc->sc_rxdx->dx_priority = DMAC_PRIORITY_NORMAL; |
| @@ -291,30 +296,28 @@ pxamci_attach_sub(device_t self, struct | | | @@ -291,30 +296,28 @@ pxamci_attach_sub(device_t self, struct |
291 | * Attach the generic SD/MMC bus driver. (The bus driver must | | 296 | * Attach the generic SD/MMC bus driver. (The bus driver must |
292 | * not invoke any chipset functions before it is attached.) | | 297 | * not invoke any chipset functions before it is attached.) |
293 | */ | | 298 | */ |
294 | memset(&saa, 0, sizeof(saa)); | | 299 | memset(&saa, 0, sizeof(saa)); |
295 | saa.saa_busname = "sdmmc"; | | 300 | saa.saa_busname = "sdmmc"; |
296 | saa.saa_sct = &pxamci_chip_functions; | | 301 | saa.saa_sct = &pxamci_chip_functions; |
297 | saa.saa_sch = sc; | | 302 | saa.saa_sch = sc; |
298 | saa.saa_dmat = pxa->pxa_dmat; | | 303 | saa.saa_dmat = pxa->pxa_dmat; |
299 | saa.saa_clkmin = sc->sc_clkmin; | | 304 | saa.saa_clkmin = sc->sc_clkmin; |
300 | saa.saa_clkmax = sc->sc_clkmax; | | 305 | saa.saa_clkmax = sc->sc_clkmax; |
301 | saa.saa_caps = 0; | | 306 | saa.saa_caps = 0; |
302 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) | | 307 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) |
303 | SET(saa.saa_caps, SMC_CAPS_DMA); | | 308 | SET(saa.saa_caps, SMC_CAPS_DMA); |
304 | #if notyet | | | |
305 | if (CPU_IS_PXA270 && ISSET(sc->sc_caps, PMC_CAPS_4BIT)) | | 309 | if (CPU_IS_PXA270 && ISSET(sc->sc_caps, PMC_CAPS_4BIT)) |
306 | SET(saa.saa_caps, SMC_CAPS_4BIT_MODE); | | 310 | SET(saa.saa_caps, SMC_CAPS_4BIT_MODE); |
307 | #endif | | | |
308 | | | 311 | |
309 | sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL); | | 312 | sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL); |
310 | if (sc->sc_sdmmc == NULL) { | | 313 | if (sc->sc_sdmmc == NULL) { |
311 | aprint_error_dev(sc->sc_dev, "couldn't attach bus\n"); | | 314 | aprint_error_dev(sc->sc_dev, "couldn't attach bus\n"); |
312 | goto free_xfer; | | 315 | goto free_xfer; |
313 | } | | 316 | } |
314 | return 0; | | 317 | return 0; |
315 | | | 318 | |
316 | free_xfer: | | 319 | free_xfer: |
317 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { | | 320 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { |
318 | if (sc->sc_rxdx) | | 321 | if (sc->sc_rxdx) |
319 | pxa2x0_dmac_free_xfer(sc->sc_rxdx); | | 322 | pxa2x0_dmac_free_xfer(sc->sc_rxdx); |
320 | if (sc->sc_txdx) | | 323 | if (sc->sc_txdx) |
| @@ -602,55 +605,60 @@ pxamci_exec_command(sdmmc_chipset_handle | | | @@ -602,55 +605,60 @@ pxamci_exec_command(sdmmc_chipset_handle |
602 | if (numblk > NOB_MASK) { | | 605 | if (numblk > NOB_MASK) { |
603 | aprint_error_dev(sc->sc_dev, "too much data\n"); | | 606 | aprint_error_dev(sc->sc_dev, "too much data\n"); |
604 | cmd->c_error = EINVAL; | | 607 | cmd->c_error = EINVAL; |
605 | goto out; | | 608 | goto out; |
606 | } | | 609 | } |
607 | | | 610 | |
608 | CSR_WRITE_4(sc, MMC_BLKLEN, blklen); | | 611 | CSR_WRITE_4(sc, MMC_BLKLEN, blklen); |
609 | CSR_WRITE_4(sc, MMC_NOB, numblk); | | 612 | CSR_WRITE_4(sc, MMC_NOB, numblk); |
610 | CSR_WRITE_4(sc, MMC_RDTO, RDTO_MASK); | | 613 | CSR_WRITE_4(sc, MMC_RDTO, RDTO_MASK); |
611 | | | 614 | |
612 | cmdat |= CMDAT_DATA_EN; | | 615 | cmdat |= CMDAT_DATA_EN; |
613 | | | 616 | |
614 | /* setting DMA */ | | 617 | /* setting DMA */ |
615 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { | | 618 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) |
| | | 619 | && DMA_ALIGNED(cmd->c_data)) { |
616 | struct dmac_xfer_desc *dx_desc; | | 620 | struct dmac_xfer_desc *dx_desc; |
617 | | | 621 | |
| | | 622 | DPRINTF(1,("%s: using DMA\n",device_xname(sc->sc_dev))); |
| | | 623 | |
618 | cmdat |= CMDAT_MMC_DMA_EN; | | 624 | cmdat |= CMDAT_MMC_DMA_EN; |
619 | | | 625 | |
620 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) { | | 626 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) { |
621 | dx_desc = &sc->sc_rxdx->dx_desc[DMAC_DESC_DST]; | | 627 | dx_desc = &sc->sc_rxdx->dx_desc[DMAC_DESC_DST]; |
622 | dx_desc->xd_nsegs = cmd->c_dmamap->dm_nsegs; | | 628 | dx_desc->xd_nsegs = cmd->c_dmamap->dm_nsegs; |
623 | dx_desc->xd_dma_segs = cmd->c_dmamap->dm_segs; | | 629 | dx_desc->xd_dma_segs = cmd->c_dmamap->dm_segs; |
624 | error = pxa2x0_dmac_start_xfer(sc->sc_rxdx); | | 630 | error = pxa2x0_dmac_start_xfer(sc->sc_rxdx); |
625 | } else { | | 631 | } else { |
626 | dx_desc = &sc->sc_txdx->dx_desc[DMAC_DESC_SRC]; | | 632 | dx_desc = &sc->sc_txdx->dx_desc[DMAC_DESC_SRC]; |
627 | dx_desc->xd_nsegs = cmd->c_dmamap->dm_nsegs; | | 633 | dx_desc->xd_nsegs = cmd->c_dmamap->dm_nsegs; |
628 | dx_desc->xd_dma_segs = cmd->c_dmamap->dm_segs; | | 634 | dx_desc->xd_dma_segs = cmd->c_dmamap->dm_segs; |
629 | /* workaround for erratum #91 */ | | 635 | /* workaround for erratum #91 */ |
630 | error = 0; | | 636 | error = 0; |
631 | if (!CPU_IS_PXA270) { | | 637 | if (!CPU_IS_PXA270) { |
632 | error = | | 638 | error = |
633 | pxa2x0_dmac_start_xfer(sc->sc_txdx); | | 639 | pxa2x0_dmac_start_xfer(sc->sc_txdx); |
634 | } | | 640 | } |
635 | } | | 641 | } |
636 | if (error) { | | 642 | if (error) { |
637 | aprint_error_dev(sc->sc_dev, | | 643 | aprint_error_dev(sc->sc_dev, |
638 | "couldn't start dma xfer. (error=%d)\n", | | 644 | "couldn't start dma xfer. (error=%d)\n", |
639 | error); | | 645 | error); |
640 | cmd->c_error = EIO; | | 646 | cmd->c_error = EIO; |
641 | goto err; | | 647 | goto err; |
642 | } | | 648 | } |
643 | } else { | | 649 | } else { |
| | | 650 | DPRINTF(1,("%s: using PIO\n",device_xname(sc->sc_dev))); |
| | | 651 | |
644 | cmd->c_resid = cmd->c_datalen; | | 652 | cmd->c_resid = cmd->c_datalen; |
645 | cmd->c_buf = cmd->c_data; | | 653 | cmd->c_buf = cmd->c_data; |
646 | | | 654 | |
647 | pxamci_enable_intr(sc, MMC_I_RXFIFO_RD_REQ | | 655 | pxamci_enable_intr(sc, MMC_I_RXFIFO_RD_REQ |
648 | | MMC_I_TXFIFO_WR_REQ | | 656 | | MMC_I_TXFIFO_WR_REQ |
649 | | MMC_I_DAT_ERR); | | 657 | | MMC_I_DAT_ERR); |
650 | } | | 658 | } |
651 | } | | 659 | } |
652 | | | 660 | |
653 | sc->sc_cmd = cmd; | | 661 | sc->sc_cmd = cmd; |
654 | | | 662 | |
655 | /* | | 663 | /* |
656 | * "After reset, the MMC card must be initialized by sending | | 664 | * "After reset, the MMC card must be initialized by sending |
| @@ -729,50 +737,51 @@ pxamci_stop_clock(struct pxamci_softc *s | | | @@ -729,50 +737,51 @@ pxamci_stop_clock(struct pxamci_softc *s |
729 | * SD/MMC controller interrput handler | | 737 | * SD/MMC controller interrput handler |
730 | */ | | 738 | */ |
731 | static int | | 739 | static int |
732 | pxamci_intr(void *arg) | | 740 | pxamci_intr(void *arg) |
733 | { | | 741 | { |
734 | struct pxamci_softc *sc = arg; | | 742 | struct pxamci_softc *sc = arg; |
735 | int status; | | 743 | int status; |
736 | #ifdef PXAMCI_DEBUG | | 744 | #ifdef PXAMCI_DEBUG |
737 | int ostatus; | | 745 | int ostatus; |
738 | | | 746 | |
739 | ostatus = | | 747 | ostatus = |
740 | #endif | | 748 | #endif |
741 | status = CSR_READ_4(sc, MMC_I_REG) & ~CSR_READ_4(sc, MMC_I_MASK); | | 749 | status = CSR_READ_4(sc, MMC_I_REG) & ~CSR_READ_4(sc, MMC_I_MASK); |
742 | DPRINTF(9,("%s: intr status = %08x\n", device_xname(sc->sc_dev), | | 750 | DPRINTF(10,("%s: intr status = %08x\n", device_xname(sc->sc_dev), |
743 | status)); | | 751 | status)); |
744 | | | 752 | |
745 | /* | | 753 | /* |
746 | * Notify the process waiting in pxamci_clock_stop() when | | 754 | * Notify the process waiting in pxamci_clock_stop() when |
747 | * the clock has really stopped. | | 755 | * the clock has really stopped. |
748 | */ | | 756 | */ |
749 | if (ISSET(status, MMC_I_CLK_IS_OFF)) { | | 757 | if (ISSET(status, MMC_I_CLK_IS_OFF)) { |
750 | DPRINTF(2,("%s: clock is now off\n", device_xname(sc->sc_dev))); | | 758 | DPRINTF(2,("%s: clock is now off\n", device_xname(sc->sc_dev))); |
751 | wakeup(sc); | | 759 | wakeup(sc); |
752 | pxamci_disable_intr(sc, MMC_I_CLK_IS_OFF); | | 760 | pxamci_disable_intr(sc, MMC_I_CLK_IS_OFF); |
753 | CLR(status, MMC_I_CLK_IS_OFF); | | 761 | CLR(status, MMC_I_CLK_IS_OFF); |
754 | } | | 762 | } |
755 | | | 763 | |
756 | if (sc->sc_cmd == NULL) | | 764 | if (sc->sc_cmd == NULL) |
757 | goto end; | | 765 | goto end; |
758 | | | 766 | |
759 | if (ISSET(status, MMC_I_RES_ERR)) { | | 767 | if (ISSET(status, MMC_I_RES_ERR)) { |
760 | DPRINTF(9, ("%s: handling MMC_I_RES_ERR\n", | | 768 | DPRINTF(9, ("%s: handling MMC_I_RES_ERR\n", |
761 | device_xname(sc->sc_dev))); | | 769 | device_xname(sc->sc_dev))); |
762 | pxamci_disable_intr(sc, MMC_I_RES_ERR); | | 770 | pxamci_disable_intr(sc, MMC_I_RES_ERR); |
763 | CLR(status, MMC_I_RES_ERR|MMC_I_END_CMD_RES); | | 771 | CLR(status, MMC_I_RES_ERR|MMC_I_END_CMD_RES); |
764 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) | | 772 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) |
765 | && (sc->sc_cmd->c_datalen > 0)) { | | 773 | && (sc->sc_cmd->c_datalen > 0) |
| | | 774 | && DMA_ALIGNED(sc->sc_cmd->c_data)) { |
766 | if (ISSET(sc->sc_cmd->c_flags, SCF_CMD_READ)) { | | 775 | if (ISSET(sc->sc_cmd->c_flags, SCF_CMD_READ)) { |
767 | pxa2x0_dmac_abort_xfer(sc->sc_rxdx); | | 776 | pxa2x0_dmac_abort_xfer(sc->sc_rxdx); |
768 | } else { | | 777 | } else { |
769 | pxa2x0_dmac_abort_xfer(sc->sc_txdx); | | 778 | pxa2x0_dmac_abort_xfer(sc->sc_txdx); |
770 | } | | 779 | } |
771 | } | | 780 | } |
772 | sc->sc_cmd->c_error = ENOEXEC; | | 781 | sc->sc_cmd->c_error = ENOEXEC; |
773 | pxamci_intr_done(sc); | | 782 | pxamci_intr_done(sc); |
774 | goto end; | | 783 | goto end; |
775 | } | | 784 | } |
776 | | | 785 | |
777 | if (ISSET(status, MMC_I_END_CMD_RES)) { | | 786 | if (ISSET(status, MMC_I_END_CMD_RES)) { |
778 | DPRINTF(9,("%s: handling MMC_I_END_CMD_RES\n", | | 787 | DPRINTF(9,("%s: handling MMC_I_END_CMD_RES\n", |
| @@ -786,51 +795,52 @@ pxamci_intr(void *arg) | | | @@ -786,51 +795,52 @@ pxamci_intr(void *arg) |
786 | CLR(status, MMC_I_PRG_DONE); | | 795 | CLR(status, MMC_I_PRG_DONE); |
787 | } | | 796 | } |
788 | if (sc->sc_cmd == NULL) | | 797 | if (sc->sc_cmd == NULL) |
789 | goto end; | | 798 | goto end; |
790 | } | | 799 | } |
791 | | | 800 | |
792 | if (ISSET(status, MMC_I_DAT_ERR)) { | | 801 | if (ISSET(status, MMC_I_DAT_ERR)) { |
793 | DPRINTF(9, ("%s: handling MMC_I_DAT_ERR\n", | | 802 | DPRINTF(9, ("%s: handling MMC_I_DAT_ERR\n", |
794 | device_xname(sc->sc_dev))); | | 803 | device_xname(sc->sc_dev))); |
795 | sc->sc_cmd->c_error = EIO; | | 804 | sc->sc_cmd->c_error = EIO; |
796 | pxamci_intr_done(sc); | | 805 | pxamci_intr_done(sc); |
797 | pxamci_disable_intr(sc, MMC_I_DAT_ERR); | | 806 | pxamci_disable_intr(sc, MMC_I_DAT_ERR); |
798 | CLR(status, MMC_I_DAT_ERR); | | 807 | CLR(status, MMC_I_DAT_ERR); |
799 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA)) { | | 808 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) |
| | | 809 | && DMA_ALIGNED(sc->sc_cmd->c_data)) { |
800 | if (ISSET(sc->sc_cmd->c_flags, SCF_CMD_READ)) { | | 810 | if (ISSET(sc->sc_cmd->c_flags, SCF_CMD_READ)) { |
801 | pxa2x0_dmac_abort_xfer(sc->sc_rxdx); | | 811 | pxa2x0_dmac_abort_xfer(sc->sc_rxdx); |
802 | } else { | | 812 | } else { |
803 | pxa2x0_dmac_abort_xfer(sc->sc_txdx); | | 813 | pxa2x0_dmac_abort_xfer(sc->sc_txdx); |
804 | } | | 814 | } |
805 | } | | 815 | } |
806 | /* ignore transmission done condition */ | | 816 | /* ignore transmission done condition */ |
807 | if (ISSET(status, MMC_I_DATA_TRAN_DONE)) { | | 817 | if (ISSET(status, MMC_I_DATA_TRAN_DONE)) { |
808 | pxamci_disable_intr(sc, MMC_I_DATA_TRAN_DONE); | | 818 | pxamci_disable_intr(sc, MMC_I_DATA_TRAN_DONE); |
809 | CLR(status, MMC_I_DATA_TRAN_DONE); | | 819 | CLR(status, MMC_I_DATA_TRAN_DONE); |
810 | } | | 820 | } |
811 | goto end; | | 821 | goto end; |
812 | } | | 822 | } |
813 | | | 823 | |
814 | if (ISSET(status, MMC_I_DATA_TRAN_DONE)) { | | 824 | if (ISSET(status, MMC_I_DATA_TRAN_DONE)) { |
815 | DPRINTF(9,("%s: handling MMC_I_DATA_TRAN_DONE\n", | | 825 | DPRINTF(9,("%s: handling MMC_I_DATA_TRAN_DONE\n", |
816 | device_xname(sc->sc_dev))); | | 826 | device_xname(sc->sc_dev))); |
817 | pxamci_intr_done(sc); | | 827 | pxamci_intr_done(sc); |
818 | pxamci_disable_intr(sc, MMC_I_DATA_TRAN_DONE); | | 828 | pxamci_disable_intr(sc, MMC_I_DATA_TRAN_DONE); |
819 | CLR(status, MMC_I_DATA_TRAN_DONE); | | 829 | CLR(status, MMC_I_DATA_TRAN_DONE); |
820 | } | | 830 | } |
821 | | | 831 | |
822 | if (ISSET(status, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ)) { | | 832 | if (ISSET(status, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ)) { |
823 | DPRINTF(9,("%s: handling MMC_I_xxFIFO_xx_REQ\n", | | 833 | DPRINTF(10,("%s: handling MMC_I_xxFIFO_xx_REQ\n", |
824 | device_xname(sc->sc_dev))); | | 834 | device_xname(sc->sc_dev))); |
825 | pxamci_intr_data(sc); | | 835 | pxamci_intr_data(sc); |
826 | CLR(status, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ); | | 836 | CLR(status, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ); |
827 | } | | 837 | } |
828 | | | 838 | |
829 | if (ISSET(status, STAT_SDIO_INT)) { | | 839 | if (ISSET(status, STAT_SDIO_INT)) { |
830 | DPRINTF(9,("%s: handling STAT_SDIO_INT\n", | | 840 | DPRINTF(9,("%s: handling STAT_SDIO_INT\n", |
831 | device_xname(sc->sc_dev))); | | 841 | device_xname(sc->sc_dev))); |
832 | sdmmc_card_intr(sc->sc_sdmmc); | | 842 | sdmmc_card_intr(sc->sc_sdmmc); |
833 | CLR(status, STAT_SDIO_INT); | | 843 | CLR(status, STAT_SDIO_INT); |
834 | } | | 844 | } |
835 | | | 845 | |
836 | end: | | 846 | end: |
| @@ -910,55 +920,57 @@ pxamci_intr_cmd(struct pxamci_softc *sc) | | | @@ -910,55 +920,57 @@ pxamci_intr_cmd(struct pxamci_softc *sc) |
910 | && ISSET(cmd->c_flags, SCF_RSP_CRC) | | 920 | && ISSET(cmd->c_flags, SCF_RSP_CRC) |
911 | && CPU_IS_PXA270) { | | 921 | && CPU_IS_PXA270) { |
912 | /* workaround for erratum #42 */ | | 922 | /* workaround for erratum #42 */ |
913 | if (ISSET(cmd->c_flags, SCF_RSP_136) | | 923 | if (ISSET(cmd->c_flags, SCF_RSP_136) |
914 | && (cmd->c_resp[0] & 0x80000000U)) { | | 924 | && (cmd->c_resp[0] & 0x80000000U)) { |
915 | DPRINTF(1,("%s: ignore CRC error\n", | | 925 | DPRINTF(1,("%s: ignore CRC error\n", |
916 | device_xname(sc->sc_dev))); | | 926 | device_xname(sc->sc_dev))); |
917 | } else | | 927 | } else |
918 | cmd->c_error = EIO; | | 928 | cmd->c_error = EIO; |
919 | } else if (ISSET(status, STAT_ERR)) | | 929 | } else if (ISSET(status, STAT_ERR)) |
920 | cmd->c_error = EIO; | | 930 | cmd->c_error = EIO; |
921 | | | 931 | |
922 | if (cmd->c_error == 0 && cmd->c_datalen > 0) { | | 932 | if (cmd->c_error == 0 && cmd->c_datalen > 0) { |
923 | /* workaround for erratum #91 */ | | | |
924 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) | | 933 | if (!ISSET(sc->sc_caps, PMC_CAPS_NO_DMA) |
925 | && CPU_IS_PXA270 | | 934 | && DMA_ALIGNED(cmd->c_data)) { |
926 | && !ISSET(cmd->c_flags, SCF_CMD_READ)) { | | 935 | /* workaround for erratum #91 */ |
927 | error = pxa2x0_dmac_start_xfer(sc->sc_txdx); | | 936 | if (CPU_IS_PXA270 |
928 | if (error) { | | 937 | && !ISSET(cmd->c_flags, SCF_CMD_READ)) { |
929 | aprint_error_dev(sc->sc_dev, | | 938 | error = pxa2x0_dmac_start_xfer(sc->sc_txdx); |
930 | "couldn't start dma xfer. (error=%d)\n", | | 939 | if (error) { |
931 | error); | | 940 | aprint_error_dev(sc->sc_dev, |
932 | cmd->c_error = EIO; | | 941 | "couldn't start dma xfer." |
933 | pxamci_intr_done(sc); | | 942 | " (error=%d)\n", error); |
934 | return; | | 943 | cmd->c_error = EIO; |
| | | 944 | pxamci_intr_done(sc); |
| | | 945 | return; |
| | | 946 | } |
935 | } | | 947 | } |
936 | pxamci_enable_intr(sc, | | 948 | pxamci_enable_intr(sc, |
937 | MMC_I_DATA_TRAN_DONE|MMC_I_DAT_ERR); | | 949 | MMC_I_DATA_TRAN_DONE|MMC_I_DAT_ERR); |
938 | } | | 950 | } |
939 | } else { | | 951 | } else { |
940 | pxamci_intr_done(sc); | | 952 | pxamci_intr_done(sc); |
941 | } | | 953 | } |
942 | } | | 954 | } |
943 | | | 955 | |
944 | static void | | 956 | static void |
945 | pxamci_intr_data(struct pxamci_softc *sc) | | 957 | pxamci_intr_data(struct pxamci_softc *sc) |
946 | { | | 958 | { |
947 | struct sdmmc_command *cmd = sc->sc_cmd; | | 959 | struct sdmmc_command *cmd = sc->sc_cmd; |
948 | int intr; | | 960 | int intr; |
949 | int n; | | 961 | int n; |
950 | | | 962 | |
951 | DPRINTF(1,("%s: pxamci_intr_data: cmd = %p, resid = %d\n", | | 963 | DPRINTF(10,("%s: pxamci_intr_data: cmd = %p, resid = %d\n", |
952 | device_xname(sc->sc_dev), cmd, cmd->c_resid)); | | 964 | device_xname(sc->sc_dev), cmd, cmd->c_resid)); |
953 | | | 965 | |
954 | n = MIN(32, cmd->c_resid); | | 966 | n = MIN(32, cmd->c_resid); |
955 | cmd->c_resid -= n; | | 967 | cmd->c_resid -= n; |
956 | | | 968 | |
957 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) { | | 969 | if (ISSET(cmd->c_flags, SCF_CMD_READ)) { |
958 | intr = MMC_I_RXFIFO_RD_REQ; | | 970 | intr = MMC_I_RXFIFO_RD_REQ; |
959 | while (n-- > 0) | | 971 | while (n-- > 0) |
960 | *cmd->c_buf++ = CSR_READ_1(sc, MMC_RXFIFO); | | 972 | *cmd->c_buf++ = CSR_READ_1(sc, MMC_RXFIFO); |
961 | } else { | | 973 | } else { |
962 | int short_xfer = n < 32; | | 974 | int short_xfer = n < 32; |
963 | | | 975 | |
964 | intr = MMC_I_TXFIFO_WR_REQ; | | 976 | intr = MMC_I_TXFIFO_WR_REQ; |
| @@ -988,29 +1000,39 @@ pxamci_intr_done(struct pxamci_softc *sc | | | @@ -988,29 +1000,39 @@ pxamci_intr_done(struct pxamci_softc *sc |
988 | | | 1000 | |
989 | pxamci_disable_intr(sc, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ| | | 1001 | pxamci_disable_intr(sc, MMC_I_TXFIFO_WR_REQ|MMC_I_RXFIFO_RD_REQ| |
990 | MMC_I_DATA_TRAN_DONE|MMC_I_END_CMD_RES|MMC_I_RES_ERR|MMC_I_DAT_ERR); | | 1002 | MMC_I_DATA_TRAN_DONE|MMC_I_END_CMD_RES|MMC_I_RES_ERR|MMC_I_DAT_ERR); |
991 | SET(sc->sc_cmd->c_flags, SCF_ITSDONE); | | 1003 | SET(sc->sc_cmd->c_flags, SCF_ITSDONE); |
992 | sc->sc_cmd = NULL; | | 1004 | sc->sc_cmd = NULL; |
993 | wakeup(sc); | | 1005 | wakeup(sc); |
994 | } | | 1006 | } |
995 | | | 1007 | |
996 | static void | | 1008 | static void |
997 | pxamci_dmac_iintr(struct dmac_xfer *dx, int status) | | 1009 | pxamci_dmac_iintr(struct dmac_xfer *dx, int status) |
998 | { | | 1010 | { |
999 | struct pxamci_softc *sc = dx->dx_cookie; | | 1011 | struct pxamci_softc *sc = dx->dx_cookie; |
1000 | | | 1012 | |
| | | 1013 | DPRINTF(1,("%s: pxamci_dmac_iintr: status = %#x\n", |
| | | 1014 | device_xname(sc->sc_dev), status)); |
| | | 1015 | |
1001 | if (status) { | | 1016 | if (status) { |
1002 | aprint_error_dev(sc->sc_dev, "pxamci_dmac_iintr: " | | 1017 | aprint_error_dev(sc->sc_dev, "pxamci_dmac_iintr: " |
1003 | "non-zero completion status %d\n", status); | | 1018 | "non-zero completion status %d\n", status); |
1004 | } | | 1019 | } |
1005 | } | | 1020 | } |
1006 | | | 1021 | |
1007 | static void | | 1022 | static void |
1008 | pxamci_dmac_ointr(struct dmac_xfer *dx, int status) | | 1023 | pxamci_dmac_ointr(struct dmac_xfer *dx, int status) |
1009 | { | | 1024 | { |
1010 | struct pxamci_softc *sc = dx->dx_cookie; | | 1025 | struct pxamci_softc *sc = dx->dx_cookie; |
1011 | | | 1026 | |
1012 | if (status) { | | 1027 | DPRINTF(1,("%s: pxamci_dmac_ointr: status = %#x\n", |
| | | 1028 | device_xname(sc->sc_dev), status)); |
| | | 1029 | |
| | | 1030 | if (status == 0) { |
| | | 1031 | if (sc->sc_cmd != NULL && (sc->sc_cmd->c_datalen & 31) != 0) { |
| | | 1032 | CSR_WRITE_4(sc, MMC_PRTBUF, 1); |
| | | 1033 | } |
| | | 1034 | } else { |
1013 | aprint_error_dev(sc->sc_dev, "pxamci_dmac_ointr: " | | 1035 | aprint_error_dev(sc->sc_dev, "pxamci_dmac_ointr: " |
1014 | "non-zero completion status %d\n", status); | | 1036 | "non-zero completion status %d\n", status); |
1015 | } | | 1037 | } |
1016 | } | | 1038 | } |