imx23_mmc.c revision 1.5
11.5Syurix/* $NetBSD: imx23_mmc.c,v 1.5 2026/02/02 09:51:40 yurix Exp $ */ 21.1Syurix 31.1Syurix/* 41.1Syurix * Copyright (c) 2012 The NetBSD Foundation, Inc. 51.1Syurix * All rights reserved. 61.1Syurix * 71.1Syurix * This code is derived from software contributed to The NetBSD Foundation 81.1Syurix * by Petri Laakso. 91.1Syurix * 101.1Syurix * Redistribution and use in source and binary forms, with or without 111.1Syurix * modification, are permitted provided that the following conditions 121.1Syurix * are met: 131.1Syurix * 1. Redistributions of source code must retain the above copyright 141.1Syurix * notice, this list of conditions and the following disclaimer. 151.1Syurix * 2. Redistributions in binary form must reproduce the above copyright 161.1Syurix * notice, this list of conditions and the following disclaimer in the 171.1Syurix * documentation and/or other materials provided with the distribution. 181.1Syurix * 191.1Syurix * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 201.1Syurix * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 211.1Syurix * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 221.1Syurix * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 231.1Syurix * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 241.1Syurix * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 251.1Syurix * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 261.1Syurix * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 271.1Syurix * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 281.1Syurix * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 291.1Syurix * POSSIBILITY OF SUCH DAMAGE. 301.1Syurix */ 311.1Syurix 321.1Syurix#include <sys/param.h> 331.1Syurix#include <sys/types.h> 341.1Syurix#include <sys/bus.h> 351.1Syurix#include <sys/cdefs.h> 361.1Syurix#include <sys/condvar.h> 371.1Syurix#include <sys/device.h> 381.1Syurix#include <sys/errno.h> 391.1Syurix#include <sys/mutex.h> 401.1Syurix#include <sys/systm.h> 411.1Syurix 421.1Syurix#include <dev/fdt/fdtvar.h> 431.1Syurix#include <dev/sdmmc/sdmmcchip.h> 441.1Syurix#include <dev/sdmmc/sdmmcreg.h> 451.1Syurix#include <dev/sdmmc/sdmmcvar.h> 461.1Syurix 471.1Syurix#include <arm/imx/imx23_icollreg.h> 481.1Syurix#include <arm/imx/imx23_mmcreg.h> 491.1Syurix#include <arm/imx/imx23var.h> 501.1Syurix#include <arm/pic/picvar.h> 511.1Syurix 521.1Syurix/* 531.1Syurix * SD/MMC host controller driver for i.MX23. 541.1Syurix * 551.1Syurix * TODO: 561.1Syurix * 571.1Syurix * - Add support for SMC_CAPS_AUTO_STOP. 581.1Syurix * - Uset GPIO for SD card detection. 591.1Syurix */ 601.1Syurix 611.1Syurixstruct imx23_mmc_softc { 621.1Syurix device_t sc_dev; 631.1Syurix struct fdtbus_dma *dma_channel; 641.1Syurix bus_space_handle_t sc_hdl; 651.1Syurix bus_space_tag_t sc_iot; 661.1Syurix device_t sc_sdmmc; 671.1Syurix kmutex_t sc_lock; 681.1Syurix struct kcondvar sc_intr_cv; 691.1Syurix uint32_t sc_irq_error; 701.1Syurix uint8_t sc_state; 711.1Syurix uint8_t sc_bus_width; 721.1Syurix uint32_t pio_words[3]; 731.1Syurix}; 741.1Syurix 751.1Syurix 761.1Syurixstatic int imx23_mmc_match(device_t, cfdata_t, void *); 771.1Syurixstatic void imx23_mmc_attach(device_t, device_t, void *); 781.1Syurix 791.1Syurixstatic void imx23_mmc_reset(struct imx23_mmc_softc *); 801.1Syurixstatic void imx23_mmc_init(struct imx23_mmc_softc *); 811.1Syurixstatic uint32_t imx23_mmc_set_sck(struct imx23_mmc_softc *, uint32_t); 821.1Syurixstatic void imx23_mmc_dma_intr(void *); 831.1Syurixstatic int imx23_mmc_error_intr(void *); 841.1Syurixstatic void imx23_mmc_prepare_data_command(struct imx23_mmc_softc *, 851.1Syurix struct fdtbus_dma_req *, struct sdmmc_command *); 861.1Syurixstatic void imx23_mmc_prepare_command(struct imx23_mmc_softc *, 871.1Syurix struct fdtbus_dma_req *, struct sdmmc_command *); 881.1Syurix 891.1Syurix/* sdmmc(4) driver chip function prototypes. */ 901.1Syurixstatic int imx23_mmc_host_reset(sdmmc_chipset_handle_t); 911.1Syurixstatic uint32_t imx23_mmc_host_ocr(sdmmc_chipset_handle_t); 921.1Syurixstatic int imx23_mmc_host_maxblklen(sdmmc_chipset_handle_t); 931.1Syurixstatic int imx23_mmc_card_detect(sdmmc_chipset_handle_t); 941.1Syurixstatic int imx23_mmc_write_protect(sdmmc_chipset_handle_t); 951.1Syurixstatic int imx23_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 961.1Syurixstatic int imx23_mmc_bus_clock(sdmmc_chipset_handle_t, int); 971.1Syurixstatic int imx23_mmc_bus_width(sdmmc_chipset_handle_t, int); 981.1Syurixstatic int imx23_mmc_bus_rod(sdmmc_chipset_handle_t, int); 991.1Syurixstatic void imx23_mmc_exec_command(sdmmc_chipset_handle_t, 1001.1Syurix struct sdmmc_command *); 1011.1Syurixstatic void imx23_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); 1021.1Syurixstatic void imx23_mmc_card_intr_ack(sdmmc_chipset_handle_t); 1031.1Syurix 1041.1Syurixstatic struct sdmmc_chip_functions imx23_mmc_functions = { 1051.1Syurix .host_reset = imx23_mmc_host_reset, 1061.1Syurix .host_ocr = imx23_mmc_host_ocr, 1071.1Syurix .host_maxblklen = imx23_mmc_host_maxblklen, 1081.1Syurix .card_detect = imx23_mmc_card_detect, 1091.1Syurix .write_protect = imx23_mmc_write_protect, 1101.1Syurix .bus_power = imx23_mmc_bus_power, 1111.1Syurix .bus_clock = imx23_mmc_bus_clock, 1121.1Syurix .bus_width = imx23_mmc_bus_width, 1131.1Syurix .bus_rod = imx23_mmc_bus_rod, 1141.1Syurix .exec_command = imx23_mmc_exec_command, 1151.1Syurix .card_enable_intr = imx23_mmc_card_enable_intr, 1161.1Syurix .card_intr_ack = imx23_mmc_card_intr_ack 1171.1Syurix}; 1181.1Syurix 1191.1SyurixCFATTACH_DECL_NEW(imx23mmc, sizeof(struct imx23_mmc_softc), imx23_mmc_match, 1201.1Syurix imx23_mmc_attach, NULL, NULL); 1211.1Syurix 1221.1Syurix#define SSP_SOFT_RST_LOOP 455 /* At least 1 us ... */ 1231.1Syurix 1241.1Syurix#define SSP_RD(sc, reg) \ 1251.1Syurix bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg)) 1261.1Syurix#define SSP_WR(sc, reg, val) \ 1271.1Syurix bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val)) 1281.1Syurix 1291.1Syurix#define SSP_CLK 160000000 /* CLK_SSP from PLL in Hz */ 1301.1Syurix#define SSP_CLK_MIN 400 /* 400 kHz */ 1311.1Syurix#define SSP_CLK_MAX 48000 /* 48 MHz */ 1321.1Syurix 1331.1Syurix/* DATA_TIMEOUT is calculated as: * (1 / SSP_CLK) * (DATA_TIMEOUT * 4096) */ 1341.1Syurix#define DATA_TIMEOUT 0x4240 1351.1Syurix 1361.1Syurix#define BUS_WIDTH_1_BIT 0x0 1371.1Syurix#define BUS_WIDTH_4_BIT 0x1 1381.1Syurix#define BUS_WIDTH_8_BIT 0x2 1391.1Syurix 1401.1Syurix/* Flags for sc_state. */ 1411.1Syurix#define SSP_STATE_IDLE 0 1421.1Syurix#define SSP_STATE_DMA 1 1431.1Syurix 1441.1Syurix#define HW_SSP_CTRL1_IRQ_MASK ( \ 1451.1Syurix HW_SSP_CTRL1_SDIO_IRQ | \ 1461.1Syurix HW_SSP_CTRL1_RESP_ERR_IRQ | \ 1471.1Syurix HW_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ 1481.1Syurix HW_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ 1491.1Syurix HW_SSP_CTRL1_DATA_CRC_IRQ | \ 1501.1Syurix HW_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ 1511.1Syurix HW_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ 1521.1Syurix HW_SSP_CTRL1_FIFO_OVERRUN_IRQ) 1531.1Syurix 1541.1Syurix/* SSP does not support over 64k transfer size. */ 1551.1Syurix#define MAX_TRANSFER_SIZE 65536 1561.1Syurix 1571.1Syurix/* Offsets of pio words in pio array */ 1581.1Syurix#define PIO_WORD_CTRL0 0 1591.1Syurix#define PIO_WORD_CMD0 1 1601.1Syurix#define PIO_WORD_CMD1 2 1611.1Syurix 1621.1Syurixstatic const struct device_compatible_entry compat_data[] = { 1631.1Syurix { .compat = "fsl,imx23-mmc" }, 1641.1Syurix DEVICE_COMPAT_EOL 1651.1Syurix}; 1661.1Syurix 1671.1Syurixstatic int 1681.1Syuriximx23_mmc_match(device_t parent, cfdata_t match, void *aux) 1691.1Syurix{ 1701.1Syurix struct fdt_attach_args *const faa = aux; 1711.1Syurix 1721.1Syurix return of_compatible_match(faa->faa_phandle, compat_data); 1731.1Syurix} 1741.1Syurix 1751.1Syurixstatic void 1761.1Syuriximx23_mmc_attach(device_t parent, device_t self, void *aux) 1771.1Syurix{ 1781.1Syurix struct imx23_mmc_softc *const sc = device_private(self); 1791.1Syurix struct fdt_attach_args *const faa = aux; 1801.1Syurix const int phandle = faa->faa_phandle; 1811.1Syurix struct sdmmcbus_attach_args saa; 1821.1Syurix char intrstr[128]; 1831.1Syurix 1841.1Syurix sc->sc_dev = self; 1851.1Syurix sc->sc_iot = faa->faa_bst; 1861.1Syurix 1871.1Syurix /* map ssp control registers */ 1881.1Syurix bus_addr_t addr; 1891.1Syurix bus_size_t size; 1901.1Syurix if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 1911.1Syurix aprint_error(": couldn't get register address\n"); 1921.1Syurix return; 1931.1Syurix } 1941.1Syurix if (bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_hdl)) { 1951.1Syurix aprint_error(": couldn't map registers\n"); 1961.1Syurix return; 1971.1Syurix } 1981.1Syurix 1991.1Syurix /* Initialize lock. */ 2001.1Syurix mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED); 2011.1Syurix 2021.1Syurix /* Condvar to wait interrupt complete. */ 2031.1Syurix cv_init(&sc->sc_intr_cv, "ssp_intr"); 2041.1Syurix 2051.1Syurix /* acquire DMA channel */ 2061.1Syurix sc->dma_channel = fdtbus_dma_get(phandle,"rx-tx", imx23_mmc_dma_intr, 2071.1Syurix sc); 2081.1Syurix if(sc->dma_channel == NULL) { 2091.1Syurix aprint_error(": couldn't map registers\n"); 2101.1Syurix return; 2111.1Syurix } 2121.1Syurix 2131.1Syurix /* establish error interrupt */ 2141.1Syurix if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 2151.1Syurix aprint_error(": failed to decode interrupt\n"); 2161.1Syurix return; 2171.1Syurix } 2181.1Syurix void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_SDMMC, IST_LEVEL, 2191.1Syurix imx23_mmc_error_intr, sc, 2201.1Syurix device_xname(self)); 2211.1Syurix if (ih == NULL) { 2221.1Syurix aprint_error_dev(self, "couldn't establish error interrupt\n"); 2231.1Syurix return; 2241.1Syurix } 2251.1Syurix 2261.1Syurix imx23_mmc_reset(sc); 2271.1Syurix imx23_mmc_init(sc); 2281.1Syurix 2291.1Syurix uint32_t imx23_mmc_vers = SSP_RD(sc, HW_SSP_VERSION); 2301.1Syurix aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n", 2311.1Syurix __SHIFTOUT(imx23_mmc_vers, HW_SSP_VERSION_MAJOR), 2321.1Syurix __SHIFTOUT(imx23_mmc_vers, HW_SSP_VERSION_MINOR)); 2331.1Syurix 2341.1Syurix /* Attach sdmmc to ssp bus. */ 2351.1Syurix memset(&saa, 0, sizeof(saa)); 2361.1Syurix saa.saa_busname = "sdmmc"; 2371.1Syurix saa.saa_sct = &imx23_mmc_functions; 2381.1Syurix saa.saa_spi_sct = NULL; 2391.1Syurix saa.saa_sch = sc; 2401.1Syurix saa.saa_dmat = faa->faa_dmat; 2411.1Syurix saa.saa_clkmin = SSP_CLK_MIN; 2421.1Syurix saa.saa_clkmax = SSP_CLK_MAX; 2431.1Syurix saa.saa_caps = SMC_CAPS_DMA | SMC_CAPS_4BIT_MODE; 2441.1Syurix 2451.1Syurix sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE); 2461.1Syurix if (sc->sc_sdmmc == NULL) { 2471.1Syurix aprint_error_dev(sc->sc_dev, "unable to attach sdmmc\n"); 2481.1Syurix return; 2491.1Syurix } 2501.1Syurix} 2511.1Syurix 2521.1Syurix/* 2531.1Syurix * sdmmc chip functions. 2541.1Syurix */ 2551.1Syurixstatic int 2561.1Syuriximx23_mmc_host_reset(sdmmc_chipset_handle_t sch) 2571.1Syurix{ 2581.1Syurix struct imx23_mmc_softc *sc = sch; 2591.1Syurix imx23_mmc_reset(sc); 2601.1Syurix return 0; 2611.1Syurix} 2621.1Syurix 2631.1Syurixstatic uint32_t 2641.1Syuriximx23_mmc_host_ocr(sdmmc_chipset_handle_t sch) 2651.1Syurix{ 2661.1Syurix /* SSP supports at least 3.2 - 3.3v */ 2671.1Syurix return MMC_OCR_3_2V_3_3V; 2681.1Syurix} 2691.1Syurix 2701.1Syurixstatic int 2711.1Syuriximx23_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) 2721.1Syurix{ 2731.1Syurix return 512; 2741.1Syurix} 2751.1Syurix 2761.1Syurix/* 2771.1Syurix * Called at the beginning of sdmmc_task_thread to detect the presence 2781.1Syurix * of the SD card. 2791.1Syurix */ 2801.1Syurixstatic int 2811.1Syuriximx23_mmc_card_detect(sdmmc_chipset_handle_t sch) 2821.1Syurix{ 2831.1Syurix return 1; /* the olinuxino has no card detection */ 2841.1Syurix} 2851.1Syurix 2861.1Syurixstatic int 2871.1Syuriximx23_mmc_write_protect(sdmmc_chipset_handle_t sch) 2881.1Syurix{ 2891.1Syurix /* The device is not write protected. */ 2901.1Syurix return 0; 2911.1Syurix} 2921.1Syurix 2931.1Syurixstatic int 2941.1Syuriximx23_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 2951.1Syurix{ 2961.1Syurix /* i.MX23 SSP does not support setting bus power. */ 2971.1Syurix return 0; 2981.1Syurix} 2991.1Syurix 3001.1Syurixstatic int 3011.1Syuriximx23_mmc_bus_clock(sdmmc_chipset_handle_t sch, int clock) 3021.1Syurix{ 3031.1Syurix struct imx23_mmc_softc *sc = sch; 3041.1Syurix uint32_t sck; 3051.1Syurix 3061.1Syurix if (clock < SSP_CLK_MIN) 3071.1Syurix sck = imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000); 3081.1Syurix else 3091.1Syurix sck = imx23_mmc_set_sck(sc, clock * 1000); 3101.1Syurix 3111.1Syurix /* Notify user if we didn't get the exact clock rate from SSP that was 3121.1Syurix * requested from the SDMMC subsystem. */ 3131.1Syurix if (sck != clock * 1000) { 3141.1Syurix sck = sck / 1000; 3151.1Syurix if (((sck) / 1000) != 0) 3161.1Syurix aprint_normal_dev(sc->sc_dev, "bus clock @ %u.%03u " 3171.1Syurix "MHz\n", sck / 1000, sck % 1000); 3181.1Syurix else 3191.1Syurix aprint_normal_dev(sc->sc_dev, "bus clock @ %u KHz\n", 3201.1Syurix sck % 1000); 3211.1Syurix } 3221.1Syurix 3231.1Syurix return 0; 3241.1Syurix} 3251.1Syurix 3261.1Syurixstatic int 3271.1Syuriximx23_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) 3281.1Syurix{ 3291.1Syurix struct imx23_mmc_softc *sc = sch; 3301.1Syurix 3311.1Syurix switch(width) { 3321.1Syurix case(1): 3331.1Syurix sc->sc_bus_width = BUS_WIDTH_1_BIT; 3341.1Syurix break; 3351.1Syurix case(4): 3361.1Syurix sc->sc_bus_width = BUS_WIDTH_4_BIT; 3371.1Syurix break; 3381.1Syurix case(8): 3391.1Syurix sc->sc_bus_width = BUS_WIDTH_8_BIT; 3401.1Syurix break; 3411.1Syurix default: 3421.1Syurix return 1; 3431.1Syurix } 3441.1Syurix 3451.1Syurix return 0; 3461.1Syurix} 3471.1Syurix 3481.1Syurixstatic int 3491.1Syuriximx23_mmc_bus_rod(sdmmc_chipset_handle_t sch, int rod) 3501.1Syurix{ 3511.1Syurix /* Go to data transfer mode. */ 3521.1Syurix return 0; 3531.1Syurix} 3541.1Syurix 3551.1Syurixstatic void 3561.1Syuriximx23_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 3571.1Syurix{ 3581.1Syurix struct imx23_mmc_softc *sc = sch; 3591.1Syurix struct fdtbus_dma_req req; 3601.1Syurix 3611.1Syurix /* SSP does not support over 64k transfer size. */ 3621.1Syurix if (cmd->c_data != NULL && cmd->c_datalen > MAX_TRANSFER_SIZE) { 3631.1Syurix aprint_error_dev(sc->sc_dev, "transfer size over %d: %d\n", 3641.1Syurix MAX_TRANSFER_SIZE, cmd->c_datalen); 3651.1Syurix cmd->c_error = ENODEV; 3661.1Syurix return; 3671.1Syurix } 3681.1Syurix 3691.1Syurix mutex_enter(&sc->sc_lock); 3701.1Syurix 3711.1Syurix /* Setup DMA command chain.*/ 3721.1Syurix if (cmd->c_data != NULL && cmd->c_datalen) { 3731.1Syurix /* command with data */ 3741.1Syurix imx23_mmc_prepare_data_command(sc, &req, cmd); 3751.1Syurix } else { 3761.1Syurix /* Only command, no data. */ 3771.1Syurix imx23_mmc_prepare_command(sc, &req, cmd); 3781.1Syurix } 3791.1Syurix 3801.1Syurix 3811.1Syurix sc->sc_state = SSP_STATE_DMA; 3821.1Syurix sc->sc_irq_error = 0; 3831.1Syurix cmd->c_error = 0; 3841.1Syurix 3851.1Syurix /* Run DMA */ 3861.1Syurix if(fdtbus_dma_transfer(sc->dma_channel, &req)) { 3871.1Syurix aprint_error_dev(sc->sc_dev, "dma transfer error\n"); 3881.1Syurix goto out; 3891.1Syurix } 3901.1Syurix 3911.1Syurix /* Wait DMA to complete. */ 3921.1Syurix while (sc->sc_state == SSP_STATE_DMA) 3931.1Syurix cv_wait(&sc->sc_intr_cv, &sc->sc_lock); 3941.1Syurix 3951.1Syurix if (sc->sc_irq_error) { 3961.1Syurix /* Do not log RESP_TIMEOUT_IRQ error if bus width is 0 as it is 3971.1Syurix * expected during SD card initialization phase. */ 3981.1Syurix if (sc->sc_bus_width) { 3991.1Syurix aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n", 4001.1Syurix sc->sc_irq_error); 4011.1Syurix } 4021.1Syurix else if(!(sc->sc_irq_error & HW_SSP_CTRL1_RESP_TIMEOUT_IRQ)) { 4031.1Syurix aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n", 4041.1Syurix sc->sc_irq_error); 4051.1Syurix } 4061.1Syurix 4071.1Syurix /* Shift unsigned error code so it fits nicely to signed int. */ 4081.1Syurix cmd->c_error = sc->sc_irq_error >> 8; 4091.1Syurix } 4101.1Syurix 4111.1Syurix /* Check response from the card if such was requested. */ 4121.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 4131.1Syurix cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0); 4141.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 4151.1Syurix cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1); 4161.1Syurix cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2); 4171.1Syurix cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3); 4181.1Syurix /* 4191.1Syurix * Remove CRC7 + LSB by rotating all bits right by 8 to 4201.1Syurix * make sdmmc __bitfield() happy. 4211.1Syurix */ 4221.1Syurix cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */ 4231.1Syurix cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24; 4241.1Syurix cmd->c_resp[1] >>= 8; 4251.1Syurix cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24; 4261.1Syurix cmd->c_resp[2] >>= 8; 4271.1Syurix cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24; 4281.1Syurix cmd->c_resp[3] >>= 8; 4291.1Syurix } 4301.1Syurix } 4311.1Syurix 4321.1Syurixout: 4331.1Syurix mutex_exit(&sc->sc_lock); 4341.1Syurix} 4351.1Syurix 4361.1Syurixstatic void 4371.1Syuriximx23_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int irq) 4381.1Syurix{ 4391.1Syurix struct imx23_mmc_softc *sc = sch; 4401.1Syurix aprint_error_dev(sc->sc_dev, "issp_card_enable_intr not implemented\n"); 4411.1Syurix} 4421.1Syurix 4431.1Syurixstatic void 4441.1Syuriximx23_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) 4451.1Syurix{ 4461.1Syurix struct imx23_mmc_softc *sc = sch; 4471.1Syurix aprint_error_dev(sc->sc_dev, "issp_card_intr_ack not implemented\n"); 4481.1Syurix} 4491.1Syurix 4501.1Syurix/* 4511.1Syurix * Reset the SSP block. 4521.1Syurix * 4531.1Syurix * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block" 4541.1Syurix */ 4551.1Syurixstatic void 4561.1Syuriximx23_mmc_reset(struct imx23_mmc_softc *sc) 4571.1Syurix{ 4581.1Syurix unsigned int loop; 4591.1Syurix 4601.1Syurix /* Prepare for soft-reset by making sure that SFTRST is not currently 4611.1Syurix * asserted. Also clear CLKGATE so we can wait for its assertion below. 4621.1Syurix */ 4631.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST); 4641.1Syurix 4651.1Syurix /* Wait at least a microsecond for SFTRST to deassert. */ 4661.1Syurix loop = 0; 4671.1Syurix while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) || 4681.1Syurix (loop < SSP_SOFT_RST_LOOP)) 4691.1Syurix loop++; 4701.1Syurix 4711.1Syurix /* Clear CLKGATE so we can wait for its assertion below. */ 4721.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE); 4731.1Syurix 4741.1Syurix /* Soft-reset the block. */ 4751.1Syurix SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST); 4761.1Syurix 4771.1Syurix /* Wait until clock is in the gated state. */ 4781.5Syurix while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE)) 4791.5Syurix continue; 4801.1Syurix 4811.1Syurix /* Bring block out of reset. */ 4821.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST); 4831.1Syurix 4841.1Syurix loop = 0; 4851.1Syurix while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) || 4861.1Syurix (loop < SSP_SOFT_RST_LOOP)) 4871.1Syurix loop++; 4881.1Syurix 4891.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE); 4901.1Syurix 4911.1Syurix /* Wait until clock is in the NON-gated state. */ 4921.5Syurix while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE) 4931.5Syurix continue; 4941.1Syurix} 4951.1Syurix 4961.1Syurix/* 4971.1Syurix * Initialize SSP controller to SD/MMC mode. 4981.1Syurix */ 4991.1Syurixstatic void 5001.1Syuriximx23_mmc_init(struct imx23_mmc_softc *sc) 5011.1Syurix{ 5021.1Syurix uint32_t reg; 5031.1Syurix 5041.1Syurix reg = SSP_RD(sc, HW_SSP_CTRL0); 5051.1Syurix reg |= HW_SSP_CTRL0_ENABLE; 5061.1Syurix 5071.1Syurix /* Initial data bus width is 1-bit. */ 5081.1Syurix reg &= ~(HW_SSP_CTRL0_BUS_WIDTH); 5091.1Syurix reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) | 5101.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE; 5111.1Syurix SSP_WR(sc, HW_SSP_CTRL0, reg); 5121.1Syurix sc->sc_bus_width = BUS_WIDTH_1_BIT; 5131.1Syurix 5141.1Syurix /* Set data timeout. */ 5151.1Syurix reg = SSP_RD(sc, HW_SSP_TIMING); 5161.1Syurix reg &= ~(HW_SSP_TIMING_TIMEOUT); 5171.1Syurix reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT); 5181.1Syurix SSP_WR(sc, HW_SSP_TIMING, reg); 5191.1Syurix 5201.1Syurix /* Set initial clock rate to minimum. */ 5211.1Syurix imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000); 5221.1Syurix 5231.1Syurix reg = SSP_RD(sc, HW_SSP_CTRL1); 5241.1Syurix /* Enable all but SDIO IRQ's. */ 5251.1Syurix reg |= HW_SSP_CTRL1_RESP_ERR_IRQ_EN | 5261.1Syurix HW_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | 5271.1Syurix HW_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | 5281.1Syurix HW_SSP_CTRL1_DATA_CRC_IRQ_EN | 5291.1Syurix HW_SSP_CTRL1_FIFO_UNDERRUN_EN | 5301.1Syurix HW_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | 5311.1Syurix HW_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN; 5321.1Syurix reg |= HW_SSP_CTRL1_DMA_ENABLE; 5331.1Syurix reg |= HW_SSP_CTRL1_POLARITY; 5341.1Syurix /* Set SD/MMC mode and use use 8-bits per word. */ 5351.1Syurix reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE); 5361.1Syurix reg |= __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) | 5371.1Syurix __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE); 5381.1Syurix SSP_WR(sc, HW_SSP_CTRL1, reg); 5391.1Syurix} 5401.1Syurix 5411.1Syurix/* 5421.1Syurix * Set SSP_SCK clock rate to the value specified in target. 5431.1Syurix * 5441.1Syurix * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)) 5451.1Syurix * 5461.1Syurix * imx23_mmc_set_sck finds the most suitable CLOCK_DIVIDE and CLOCK_RATE 5471.1Syurix * register values for the target clock rate by iterating through all possible 5481.1Syurix * register values. 5491.1Syurix */ 5501.1Syurixstatic uint32_t 5511.1Syuriximx23_mmc_set_sck(struct imx23_mmc_softc *sc, uint32_t target) 5521.1Syurix{ 5531.1Syurix uint32_t newclk, found, reg; 5541.1Syurix uint8_t div, rate, d, r; 5551.1Syurix 5561.1Syurix found = div = rate = 0; 5571.1Syurix 5581.1Syurix for (d = 2; d < 254; d++) { 5591.1Syurix for (r = 0; r < 255; r++) { 5601.1Syurix newclk = SSP_CLK / (d * (1 + r)); 5611.1Syurix if (newclk == target) { 5621.1Syurix found = newclk; 5631.1Syurix div = d; 5641.1Syurix rate = r; 5651.1Syurix goto out; 5661.1Syurix } 5671.1Syurix if (newclk < target && newclk > found) { 5681.1Syurix found = newclk; 5691.1Syurix div = d; 5701.1Syurix rate = r; 5711.1Syurix } 5721.1Syurix } 5731.1Syurix } 5741.1Syurixout: 5751.1Syurix reg = SSP_RD(sc, HW_SSP_TIMING); 5761.1Syurix reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE); 5771.1Syurix reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) | 5781.1Syurix __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE); 5791.1Syurix SSP_WR(sc, HW_SSP_TIMING, reg); 5801.1Syurix 5811.1Syurix return SSP_CLK / (div * (1 + rate)); 5821.1Syurix} 5831.1Syurix 5841.1Syurix/* 5851.1Syurix * IRQ from DMA. 5861.1Syurix */ 5871.1Syurixstatic void 5881.1Syuriximx23_mmc_dma_intr(void *arg) 5891.1Syurix{ 5901.1Syurix struct imx23_mmc_softc *sc = arg; 5911.1Syurix 5921.1Syurix mutex_enter(&sc->sc_lock); 5931.2Sskrll 5941.1Syurix sc->sc_state = SSP_STATE_IDLE; 5951.1Syurix 5961.1Syurix /* Signal thread that interrupt was handled. */ 5971.1Syurix cv_signal(&sc->sc_intr_cv); 5981.1Syurix 5991.1Syurix mutex_exit(&sc->sc_lock); 6001.1Syurix} 6011.1Syurix 6021.1Syurix/* 6031.1Syurix * IRQ from SSP block. 6041.1Syurix * 6051.1Syurix * When SSP receives IRQ it terminates ongoing DMA transfer by issuing DMATERM 6061.1Syurix * signal to DMA block. 6071.1Syurix */ 6081.1Syurixstatic int 6091.1Syuriximx23_mmc_error_intr(void *arg) 6101.1Syurix{ 6111.1Syurix struct imx23_mmc_softc *sc = arg; 6121.1Syurix 6131.1Syurix mutex_enter(&sc->sc_lock); 6141.1Syurix 6151.1Syurix sc->sc_irq_error = 6161.1Syurix SSP_RD(sc, HW_SSP_CTRL1) & HW_SSP_CTRL1_IRQ_MASK; 6171.1Syurix 6181.1Syurix /* Acknowledge all IRQ's. */ 6191.1Syurix SSP_WR(sc, HW_SSP_CTRL1_CLR, HW_SSP_CTRL1_IRQ_MASK); 6201.1Syurix 6211.1Syurix mutex_exit(&sc->sc_lock); 6221.1Syurix 6231.1Syurix /* Return 1 to acknowledge IRQ. */ 6241.1Syurix return 1; 6251.1Syurix} 6261.1Syurix 6271.1Syurix/* 6281.1Syurix * Set up a dma transfer for a block with data. 6291.1Syurix */ 6301.1Syurixstatic void 6311.1Syuriximx23_mmc_prepare_data_command(struct imx23_mmc_softc *sc, 6321.1Syurix struct fdtbus_dma_req *req, struct sdmmc_command *cmd) 6331.1Syurix{ 6341.1Syurix int block_count = cmd->c_datalen / cmd->c_blklen; 6351.1Syurix 6361.1Syurix /* prepare DMA request */ 6371.1Syurix req->dreq_segs = cmd->c_dmamap->dm_segs; 6381.1Syurix req->dreq_nsegs = cmd->c_dmamap->dm_nsegs; 6391.1Syurix req->dreq_block_irq = 1; 6401.1Syurix req->dreq_block_multi = 0; 6411.1Syurix req->dreq_datalen = 3; 6421.1Syurix req->dreq_data = sc->pio_words; 6431.1Syurix 6441.1Syurix /* prepare CTRL0 register*/ 6451.1Syurix sc->pio_words[PIO_WORD_CTRL0] = 6461.1Syurix HW_SSP_CTRL0_DATA_XFER | 6471.1Syurix __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) | 6481.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | 6491.1Syurix __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT) | 6501.1Syurix HW_SSP_CTRL0_ENABLE; 6511.1Syurix if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 6521.1Syurix req->dreq_dir = FDT_DMA_READ; 6531.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_READ; 6541.1Syurix } else { 6551.1Syurix req->dreq_dir = FDT_DMA_WRITE; 6561.1Syurix } 6571.1Syurix if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) { 6581.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC; 6591.1Syurix } 6601.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 6611.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP; 6621.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 6631.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP; 6641.1Syurix } 6651.1Syurix } 6661.1Syurix 6671.1Syurix /* prepare CMD0 register */ 6681.1Syurix sc->pio_words[PIO_WORD_CMD0] = 6691.1Syurix HW_SSP_CMD0_APPEND_8CYC | 6701.1Syurix __SHIFTIN(ffs(cmd->c_blklen) - 1, HW_SSP_CMD0_BLOCK_SIZE) | 6711.1Syurix __SHIFTIN(block_count - 1, HW_SSP_CMD0_BLOCK_COUNT) | 6721.1Syurix __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD); 6731.1Syurix 6741.1Syurix /* prepare CMD1 register */ 6751.1Syurix sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg; 6761.1Syurix} 6771.1Syurix 6781.1Syurix/* 6791.1Syurix * Setup a dma transfer for a command without data (PIO only) 6801.1Syurix */ 6811.1Syurixstatic void 6821.1Syuriximx23_mmc_prepare_command(struct imx23_mmc_softc *sc, 6831.1Syurix struct fdtbus_dma_req *req, struct sdmmc_command *cmd) 6841.1Syurix{ 6851.1Syurix /* prepare DMA */ 6861.1Syurix req->dreq_nsegs = 0; 6871.1Syurix req->dreq_block_irq = 1; 6881.1Syurix req->dreq_block_multi = 0; 6891.1Syurix req->dreq_dir = FDT_DMA_NO_XFER; 6901.1Syurix req->dreq_datalen = 3; 6911.1Syurix req->dreq_data = sc->pio_words; 6921.1Syurix 6931.1Syurix /* prepare CTRL0 register*/ 6941.1Syurix sc->pio_words[PIO_WORD_CTRL0] = 6951.1Syurix __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) | 6961.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE; 6971.1Syurix if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) { 6981.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC; 6991.1Syurix } 7001.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 7011.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP; 7021.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 7031.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP; 7041.1Syurix } 7051.1Syurix } 7061.1Syurix 7071.1Syurix /* prepare CMD0 register */ 7081.1Syurix sc->pio_words[PIO_WORD_CMD0] = 7091.1Syurix __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD); 7101.1Syurix 7111.1Syurix /* prepare CMD1 register */ 7121.1Syurix sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg; 7131.1Syurix} 714