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