imx23_mmc.c revision 1.1
11.1Syurix/* $Id: imx23_mmc.c,v 1.1 2026/02/01 11:31:28 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 return; 2521.1Syurix} 2531.1Syurix 2541.1Syurix/* 2551.1Syurix * sdmmc chip functions. 2561.1Syurix */ 2571.1Syurixstatic int 2581.1Syuriximx23_mmc_host_reset(sdmmc_chipset_handle_t sch) 2591.1Syurix{ 2601.1Syurix struct imx23_mmc_softc *sc = sch; 2611.1Syurix imx23_mmc_reset(sc); 2621.1Syurix return 0; 2631.1Syurix} 2641.1Syurix 2651.1Syurixstatic uint32_t 2661.1Syuriximx23_mmc_host_ocr(sdmmc_chipset_handle_t sch) 2671.1Syurix{ 2681.1Syurix /* SSP supports at least 3.2 - 3.3v */ 2691.1Syurix return MMC_OCR_3_2V_3_3V; 2701.1Syurix} 2711.1Syurix 2721.1Syurixstatic int 2731.1Syuriximx23_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) 2741.1Syurix{ 2751.1Syurix return 512; 2761.1Syurix} 2771.1Syurix 2781.1Syurix/* 2791.1Syurix * Called at the beginning of sdmmc_task_thread to detect the presence 2801.1Syurix * of the SD card. 2811.1Syurix */ 2821.1Syurixstatic int 2831.1Syuriximx23_mmc_card_detect(sdmmc_chipset_handle_t sch) 2841.1Syurix{ 2851.1Syurix return 1; /* the olinuxino has no card detection */ 2861.1Syurix} 2871.1Syurix 2881.1Syurixstatic int 2891.1Syuriximx23_mmc_write_protect(sdmmc_chipset_handle_t sch) 2901.1Syurix{ 2911.1Syurix /* The device is not write protected. */ 2921.1Syurix return 0; 2931.1Syurix} 2941.1Syurix 2951.1Syurixstatic int 2961.1Syuriximx23_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 2971.1Syurix{ 2981.1Syurix /* i.MX23 SSP does not support setting bus power. */ 2991.1Syurix return 0; 3001.1Syurix} 3011.1Syurix 3021.1Syurixstatic int 3031.1Syuriximx23_mmc_bus_clock(sdmmc_chipset_handle_t sch, int clock) 3041.1Syurix{ 3051.1Syurix struct imx23_mmc_softc *sc = sch; 3061.1Syurix uint32_t sck; 3071.1Syurix 3081.1Syurix if (clock < SSP_CLK_MIN) 3091.1Syurix sck = imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000); 3101.1Syurix else 3111.1Syurix sck = imx23_mmc_set_sck(sc, clock * 1000); 3121.1Syurix 3131.1Syurix /* Notify user if we didn't get the exact clock rate from SSP that was 3141.1Syurix * requested from the SDMMC subsystem. */ 3151.1Syurix if (sck != clock * 1000) { 3161.1Syurix sck = sck / 1000; 3171.1Syurix if (((sck) / 1000) != 0) 3181.1Syurix aprint_normal_dev(sc->sc_dev, "bus clock @ %u.%03u " 3191.1Syurix "MHz\n", sck / 1000, sck % 1000); 3201.1Syurix else 3211.1Syurix aprint_normal_dev(sc->sc_dev, "bus clock @ %u KHz\n", 3221.1Syurix sck % 1000); 3231.1Syurix } 3241.1Syurix 3251.1Syurix return 0; 3261.1Syurix} 3271.1Syurix 3281.1Syurixstatic int 3291.1Syuriximx23_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) 3301.1Syurix{ 3311.1Syurix struct imx23_mmc_softc *sc = sch; 3321.1Syurix 3331.1Syurix switch(width) { 3341.1Syurix case(1): 3351.1Syurix sc->sc_bus_width = BUS_WIDTH_1_BIT; 3361.1Syurix break; 3371.1Syurix case(4): 3381.1Syurix sc->sc_bus_width = BUS_WIDTH_4_BIT; 3391.1Syurix break; 3401.1Syurix case(8): 3411.1Syurix sc->sc_bus_width = BUS_WIDTH_8_BIT; 3421.1Syurix break; 3431.1Syurix default: 3441.1Syurix return 1; 3451.1Syurix } 3461.1Syurix 3471.1Syurix return 0; 3481.1Syurix} 3491.1Syurix 3501.1Syurixstatic int 3511.1Syuriximx23_mmc_bus_rod(sdmmc_chipset_handle_t sch, int rod) 3521.1Syurix{ 3531.1Syurix /* Go to data transfer mode. */ 3541.1Syurix return 0; 3551.1Syurix} 3561.1Syurix 3571.1Syurixstatic void 3581.1Syuriximx23_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 3591.1Syurix{ 3601.1Syurix struct imx23_mmc_softc *sc = sch; 3611.1Syurix struct fdtbus_dma_req req; 3621.1Syurix 3631.1Syurix /* SSP does not support over 64k transfer size. */ 3641.1Syurix if (cmd->c_data != NULL && cmd->c_datalen > MAX_TRANSFER_SIZE) { 3651.1Syurix aprint_error_dev(sc->sc_dev, "transfer size over %d: %d\n", 3661.1Syurix MAX_TRANSFER_SIZE, cmd->c_datalen); 3671.1Syurix cmd->c_error = ENODEV; 3681.1Syurix return; 3691.1Syurix } 3701.1Syurix 3711.1Syurix mutex_enter(&sc->sc_lock); 3721.1Syurix 3731.1Syurix /* Setup DMA command chain.*/ 3741.1Syurix if (cmd->c_data != NULL && cmd->c_datalen) { 3751.1Syurix /* command with data */ 3761.1Syurix imx23_mmc_prepare_data_command(sc, &req, cmd); 3771.1Syurix } else { 3781.1Syurix /* Only command, no data. */ 3791.1Syurix imx23_mmc_prepare_command(sc, &req, cmd); 3801.1Syurix } 3811.1Syurix 3821.1Syurix 3831.1Syurix sc->sc_state = SSP_STATE_DMA; 3841.1Syurix sc->sc_irq_error = 0; 3851.1Syurix cmd->c_error = 0; 3861.1Syurix 3871.1Syurix /* Run DMA */ 3881.1Syurix if(fdtbus_dma_transfer(sc->dma_channel, &req)) { 3891.1Syurix aprint_error_dev(sc->sc_dev, "dma transfer error\n"); 3901.1Syurix goto out; 3911.1Syurix } 3921.1Syurix 3931.1Syurix /* Wait DMA to complete. */ 3941.1Syurix while (sc->sc_state == SSP_STATE_DMA) 3951.1Syurix cv_wait(&sc->sc_intr_cv, &sc->sc_lock); 3961.1Syurix 3971.1Syurix if (sc->sc_irq_error) { 3981.1Syurix /* Do not log RESP_TIMEOUT_IRQ error if bus width is 0 as it is 3991.1Syurix * expected during SD card initialization phase. */ 4001.1Syurix if (sc->sc_bus_width) { 4011.1Syurix aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n", 4021.1Syurix sc->sc_irq_error); 4031.1Syurix } 4041.1Syurix else if(!(sc->sc_irq_error & HW_SSP_CTRL1_RESP_TIMEOUT_IRQ)) { 4051.1Syurix aprint_error_dev(sc->sc_dev, "SSP_ERROR_IRQ: %d\n", 4061.1Syurix sc->sc_irq_error); 4071.1Syurix } 4081.1Syurix 4091.1Syurix /* Shift unsigned error code so it fits nicely to signed int. */ 4101.1Syurix cmd->c_error = sc->sc_irq_error >> 8; 4111.1Syurix } 4121.1Syurix 4131.1Syurix /* Check response from the card if such was requested. */ 4141.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 4151.1Syurix cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0); 4161.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 4171.1Syurix cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1); 4181.1Syurix cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2); 4191.1Syurix cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3); 4201.1Syurix /* 4211.1Syurix * Remove CRC7 + LSB by rotating all bits right by 8 to 4221.1Syurix * make sdmmc __bitfield() happy. 4231.1Syurix */ 4241.1Syurix cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */ 4251.1Syurix cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24; 4261.1Syurix cmd->c_resp[1] >>= 8; 4271.1Syurix cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24; 4281.1Syurix cmd->c_resp[2] >>= 8; 4291.1Syurix cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24; 4301.1Syurix cmd->c_resp[3] >>= 8; 4311.1Syurix } 4321.1Syurix } 4331.1Syurix 4341.1Syurixout: 4351.1Syurix mutex_exit(&sc->sc_lock); 4361.1Syurix 4371.1Syurix return; 4381.1Syurix} 4391.1Syurix 4401.1Syurixstatic void 4411.1Syuriximx23_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int irq) 4421.1Syurix{ 4431.1Syurix struct imx23_mmc_softc *sc = sch; 4441.1Syurix aprint_error_dev(sc->sc_dev, "issp_card_enable_intr not implemented\n"); 4451.1Syurix return; 4461.1Syurix} 4471.1Syurix 4481.1Syurixstatic void 4491.1Syuriximx23_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) 4501.1Syurix{ 4511.1Syurix struct imx23_mmc_softc *sc = sch; 4521.1Syurix aprint_error_dev(sc->sc_dev, "issp_card_intr_ack not implemented\n"); 4531.1Syurix return; 4541.1Syurix} 4551.1Syurix 4561.1Syurix/* 4571.1Syurix * Reset the SSP block. 4581.1Syurix * 4591.1Syurix * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block" 4601.1Syurix */ 4611.1Syurixstatic void 4621.1Syuriximx23_mmc_reset(struct imx23_mmc_softc *sc) 4631.1Syurix{ 4641.1Syurix unsigned int loop; 4651.1Syurix 4661.1Syurix /* Prepare for soft-reset by making sure that SFTRST is not currently 4671.1Syurix * asserted. Also clear CLKGATE so we can wait for its assertion below. 4681.1Syurix */ 4691.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST); 4701.1Syurix 4711.1Syurix /* Wait at least a microsecond for SFTRST to deassert. */ 4721.1Syurix loop = 0; 4731.1Syurix while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) || 4741.1Syurix (loop < SSP_SOFT_RST_LOOP)) 4751.1Syurix loop++; 4761.1Syurix 4771.1Syurix /* Clear CLKGATE so we can wait for its assertion below. */ 4781.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE); 4791.1Syurix 4801.1Syurix /* Soft-reset the block. */ 4811.1Syurix SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST); 4821.1Syurix 4831.1Syurix /* Wait until clock is in the gated state. */ 4841.1Syurix while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE)); 4851.1Syurix 4861.1Syurix /* Bring block out of reset. */ 4871.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST); 4881.1Syurix 4891.1Syurix loop = 0; 4901.1Syurix while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) || 4911.1Syurix (loop < SSP_SOFT_RST_LOOP)) 4921.1Syurix loop++; 4931.1Syurix 4941.1Syurix SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE); 4951.1Syurix 4961.1Syurix /* Wait until clock is in the NON-gated state. */ 4971.1Syurix while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE); 4981.1Syurix 4991.1Syurix return; 5001.1Syurix} 5011.1Syurix 5021.1Syurix/* 5031.1Syurix * Initialize SSP controller to SD/MMC mode. 5041.1Syurix */ 5051.1Syurixstatic void 5061.1Syuriximx23_mmc_init(struct imx23_mmc_softc *sc) 5071.1Syurix{ 5081.1Syurix uint32_t reg; 5091.1Syurix 5101.1Syurix reg = SSP_RD(sc, HW_SSP_CTRL0); 5111.1Syurix reg |= HW_SSP_CTRL0_ENABLE; 5121.1Syurix 5131.1Syurix /* Initial data bus width is 1-bit. */ 5141.1Syurix reg &= ~(HW_SSP_CTRL0_BUS_WIDTH); 5151.1Syurix reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) | 5161.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE; 5171.1Syurix SSP_WR(sc, HW_SSP_CTRL0, reg); 5181.1Syurix sc->sc_bus_width = BUS_WIDTH_1_BIT; 5191.1Syurix 5201.1Syurix /* Set data timeout. */ 5211.1Syurix reg = SSP_RD(sc, HW_SSP_TIMING); 5221.1Syurix reg &= ~(HW_SSP_TIMING_TIMEOUT); 5231.1Syurix reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT); 5241.1Syurix SSP_WR(sc, HW_SSP_TIMING, reg); 5251.1Syurix 5261.1Syurix /* Set initial clock rate to minimum. */ 5271.1Syurix imx23_mmc_set_sck(sc, SSP_CLK_MIN * 1000); 5281.1Syurix 5291.1Syurix reg = SSP_RD(sc, HW_SSP_CTRL1); 5301.1Syurix /* Enable all but SDIO IRQ's. */ 5311.1Syurix reg |= HW_SSP_CTRL1_RESP_ERR_IRQ_EN | 5321.1Syurix HW_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | 5331.1Syurix HW_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | 5341.1Syurix HW_SSP_CTRL1_DATA_CRC_IRQ_EN | 5351.1Syurix HW_SSP_CTRL1_FIFO_UNDERRUN_EN | 5361.1Syurix HW_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | 5371.1Syurix HW_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN; 5381.1Syurix reg |= HW_SSP_CTRL1_DMA_ENABLE; 5391.1Syurix reg |= HW_SSP_CTRL1_POLARITY; 5401.1Syurix /* Set SD/MMC mode and use use 8-bits per word. */ 5411.1Syurix reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE); 5421.1Syurix reg |= __SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) | 5431.1Syurix __SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE); 5441.1Syurix SSP_WR(sc, HW_SSP_CTRL1, reg); 5451.1Syurix 5461.1Syurix return; 5471.1Syurix} 5481.1Syurix 5491.1Syurix/* 5501.1Syurix * Set SSP_SCK clock rate to the value specified in target. 5511.1Syurix * 5521.1Syurix * SSP_SCK is calculated as: SSP_CLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)) 5531.1Syurix * 5541.1Syurix * imx23_mmc_set_sck finds the most suitable CLOCK_DIVIDE and CLOCK_RATE 5551.1Syurix * register values for the target clock rate by iterating through all possible 5561.1Syurix * register values. 5571.1Syurix */ 5581.1Syurixstatic uint32_t 5591.1Syuriximx23_mmc_set_sck(struct imx23_mmc_softc *sc, uint32_t target) 5601.1Syurix{ 5611.1Syurix uint32_t newclk, found, reg; 5621.1Syurix uint8_t div, rate, d, r; 5631.1Syurix 5641.1Syurix found = div = rate = 0; 5651.1Syurix 5661.1Syurix for (d = 2; d < 254; d++) { 5671.1Syurix for (r = 0; r < 255; r++) { 5681.1Syurix newclk = SSP_CLK / (d * (1 + r)); 5691.1Syurix if (newclk == target) { 5701.1Syurix found = newclk; 5711.1Syurix div = d; 5721.1Syurix rate = r; 5731.1Syurix goto out; 5741.1Syurix } 5751.1Syurix if (newclk < target && newclk > found) { 5761.1Syurix found = newclk; 5771.1Syurix div = d; 5781.1Syurix rate = r; 5791.1Syurix } 5801.1Syurix } 5811.1Syurix } 5821.1Syurixout: 5831.1Syurix reg = SSP_RD(sc, HW_SSP_TIMING); 5841.1Syurix reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE); 5851.1Syurix reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) | 5861.1Syurix __SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE); 5871.1Syurix SSP_WR(sc, HW_SSP_TIMING, reg); 5881.1Syurix 5891.1Syurix return SSP_CLK / (div * (1 + rate)); 5901.1Syurix} 5911.1Syurix 5921.1Syurix/* 5931.1Syurix * IRQ from DMA. 5941.1Syurix */ 5951.1Syurixstatic void 5961.1Syuriximx23_mmc_dma_intr(void *arg) 5971.1Syurix{ 5981.1Syurix struct imx23_mmc_softc *sc = arg; 5991.1Syurix 6001.1Syurix mutex_enter(&sc->sc_lock); 6011.1Syurix 6021.1Syurix sc->sc_state = SSP_STATE_IDLE; 6031.1Syurix 6041.1Syurix /* Signal thread that interrupt was handled. */ 6051.1Syurix cv_signal(&sc->sc_intr_cv); 6061.1Syurix 6071.1Syurix mutex_exit(&sc->sc_lock); 6081.1Syurix} 6091.1Syurix 6101.1Syurix/* 6111.1Syurix * IRQ from SSP block. 6121.1Syurix * 6131.1Syurix * When SSP receives IRQ it terminates ongoing DMA transfer by issuing DMATERM 6141.1Syurix * signal to DMA block. 6151.1Syurix */ 6161.1Syurixstatic int 6171.1Syuriximx23_mmc_error_intr(void *arg) 6181.1Syurix{ 6191.1Syurix struct imx23_mmc_softc *sc = arg; 6201.1Syurix 6211.1Syurix mutex_enter(&sc->sc_lock); 6221.1Syurix 6231.1Syurix sc->sc_irq_error = 6241.1Syurix SSP_RD(sc, HW_SSP_CTRL1) & HW_SSP_CTRL1_IRQ_MASK; 6251.1Syurix 6261.1Syurix /* Acknowledge all IRQ's. */ 6271.1Syurix SSP_WR(sc, HW_SSP_CTRL1_CLR, HW_SSP_CTRL1_IRQ_MASK); 6281.1Syurix 6291.1Syurix mutex_exit(&sc->sc_lock); 6301.1Syurix 6311.1Syurix /* Return 1 to acknowledge IRQ. */ 6321.1Syurix return 1; 6331.1Syurix} 6341.1Syurix 6351.1Syurix/* 6361.1Syurix * Set up a dma transfer for a block with data. 6371.1Syurix */ 6381.1Syurixstatic void 6391.1Syuriximx23_mmc_prepare_data_command(struct imx23_mmc_softc *sc, 6401.1Syurix struct fdtbus_dma_req *req, struct sdmmc_command *cmd) 6411.1Syurix{ 6421.1Syurix int block_count = cmd->c_datalen / cmd->c_blklen; 6431.1Syurix 6441.1Syurix /* prepare DMA request */ 6451.1Syurix req->dreq_segs = cmd->c_dmamap->dm_segs; 6461.1Syurix req->dreq_nsegs = cmd->c_dmamap->dm_nsegs; 6471.1Syurix req->dreq_block_irq = 1; 6481.1Syurix req->dreq_block_multi = 0; 6491.1Syurix req->dreq_datalen = 3; 6501.1Syurix req->dreq_data = sc->pio_words; 6511.1Syurix 6521.1Syurix /* prepare CTRL0 register*/ 6531.1Syurix sc->pio_words[PIO_WORD_CTRL0] = 6541.1Syurix HW_SSP_CTRL0_DATA_XFER | 6551.1Syurix __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) | 6561.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | 6571.1Syurix __SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT) | 6581.1Syurix HW_SSP_CTRL0_ENABLE; 6591.1Syurix if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 6601.1Syurix req->dreq_dir = FDT_DMA_READ; 6611.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_READ; 6621.1Syurix } else { 6631.1Syurix req->dreq_dir = FDT_DMA_WRITE; 6641.1Syurix } 6651.1Syurix if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) { 6661.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC; 6671.1Syurix } 6681.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 6691.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP; 6701.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 6711.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP; 6721.1Syurix } 6731.1Syurix } 6741.1Syurix 6751.1Syurix /* prepare CMD0 register */ 6761.1Syurix sc->pio_words[PIO_WORD_CMD0] = 6771.1Syurix HW_SSP_CMD0_APPEND_8CYC | 6781.1Syurix __SHIFTIN(ffs(cmd->c_blklen) - 1, HW_SSP_CMD0_BLOCK_SIZE) | 6791.1Syurix __SHIFTIN(block_count - 1, HW_SSP_CMD0_BLOCK_COUNT) | 6801.1Syurix __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD); 6811.1Syurix 6821.1Syurix /* prepare CMD1 register */ 6831.1Syurix sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg; 6841.1Syurix} 6851.1Syurix 6861.1Syurix/* 6871.1Syurix * Setup a dma transfer for a command without data (PIO only) 6881.1Syurix */ 6891.1Syurixstatic void 6901.1Syuriximx23_mmc_prepare_command(struct imx23_mmc_softc *sc, 6911.1Syurix struct fdtbus_dma_req *req, struct sdmmc_command *cmd) 6921.1Syurix{ 6931.1Syurix /* prepare DMA */ 6941.1Syurix req->dreq_nsegs = 0; 6951.1Syurix req->dreq_block_irq = 1; 6961.1Syurix req->dreq_block_multi = 0; 6971.1Syurix req->dreq_dir = FDT_DMA_NO_XFER; 6981.1Syurix req->dreq_datalen = 3; 6991.1Syurix req->dreq_data = sc->pio_words; 7001.1Syurix 7011.1Syurix /* prepare CTRL0 register*/ 7021.1Syurix sc->pio_words[PIO_WORD_CTRL0] = 7031.1Syurix __SHIFTIN(sc->sc_bus_width, HW_SSP_CTRL0_BUS_WIDTH) | 7041.1Syurix HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE; 7051.1Syurix if (!ISSET(cmd->c_flags, SCF_RSP_CRC)) { 7061.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_IGNORE_CRC; 7071.1Syurix } 7081.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { 7091.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_GET_RESP; 7101.1Syurix if (ISSET(cmd->c_flags, SCF_RSP_136)) { 7111.1Syurix sc->pio_words[PIO_WORD_CTRL0] |= HW_SSP_CTRL0_LONG_RESP; 7121.1Syurix } 7131.1Syurix } 7141.1Syurix 7151.1Syurix /* prepare CMD0 register */ 7161.1Syurix sc->pio_words[PIO_WORD_CMD0] = 7171.1Syurix __SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD); 7181.1Syurix 7191.1Syurix /* prepare CMD1 register */ 7201.1Syurix sc->pio_words[PIO_WORD_CMD1] = cmd->c_arg; 7211.1Syurix} 722