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