linux/drivers/mmc/host/sdhci-esdhc-imx.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Freescale eSDHC i.MX controller driver for the platform bus.
 *
 * derived from the OF-version.
 *
 * Copyright (c) 2010 Pengutronix e.K.
 *   Author: Wolfram Sang <[email protected]>
 */

#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pm_qos.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include "sdhci-cqhci.h"
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
#include "cqhci.h"

#define ESDHC_SYS_CTRL_DTOCV_MASK
#define ESDHC_CTRL_D3CD
#define ESDHC_BURST_LEN_EN_INCR
/* VENDOR SPEC register */
#define ESDHC_VENDOR_SPEC
#define ESDHC_VENDOR_SPEC_SDIO_QUIRK
#define ESDHC_VENDOR_SPEC_VSELECT
#define ESDHC_VENDOR_SPEC_FRC_SDCLK_ON
#define ESDHC_DEBUG_SEL_AND_STATUS_REG
#define ESDHC_DEBUG_SEL_REG
#define ESDHC_DEBUG_SEL_MASK
#define ESDHC_DEBUG_SEL_CMD_STATE
#define ESDHC_DEBUG_SEL_DATA_STATE
#define ESDHC_DEBUG_SEL_TRANS_STATE
#define ESDHC_DEBUG_SEL_DMA_STATE
#define ESDHC_DEBUG_SEL_ADMA_STATE
#define ESDHC_DEBUG_SEL_FIFO_STATE
#define ESDHC_DEBUG_SEL_ASYNC_FIFO_STATE
#define ESDHC_WTMK_LVL
#define ESDHC_WTMK_DEFAULT_VAL
#define ESDHC_WTMK_LVL_RD_WML_MASK
#define ESDHC_WTMK_LVL_RD_WML_SHIFT
#define ESDHC_WTMK_LVL_WR_WML_MASK
#define ESDHC_WTMK_LVL_WR_WML_SHIFT
#define ESDHC_WTMK_LVL_WML_VAL_DEF
#define ESDHC_WTMK_LVL_WML_VAL_MAX
#define ESDHC_MIX_CTRL
#define ESDHC_MIX_CTRL_DDREN
#define ESDHC_MIX_CTRL_AC23EN
#define ESDHC_MIX_CTRL_EXE_TUNE
#define ESDHC_MIX_CTRL_SMPCLK_SEL
#define ESDHC_MIX_CTRL_AUTO_TUNE_EN
#define ESDHC_MIX_CTRL_FBCLK_SEL
#define ESDHC_MIX_CTRL_HS400_EN
#define ESDHC_MIX_CTRL_HS400_ES_EN
/* Bits 3 and 6 are not SDHCI standard definitions */
#define ESDHC_MIX_CTRL_SDHCI_MASK
/* Tuning bits */
#define ESDHC_MIX_CTRL_TUNING_MASK

/* dll control register */
#define ESDHC_DLL_CTRL
#define ESDHC_DLL_OVERRIDE_VAL_SHIFT
#define ESDHC_DLL_OVERRIDE_EN_SHIFT

/* tune control register */
#define ESDHC_TUNE_CTRL_STATUS
#define ESDHC_TUNE_CTRL_STEP
#define ESDHC_TUNE_CTRL_MIN
#define ESDHC_TUNE_CTRL_MAX

/* strobe dll register */
#define ESDHC_STROBE_DLL_CTRL
#define ESDHC_STROBE_DLL_CTRL_ENABLE
#define ESDHC_STROBE_DLL_CTRL_RESET
#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT
#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT
#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT

#define ESDHC_STROBE_DLL_STATUS
#define ESDHC_STROBE_DLL_STS_REF_LOCK
#define ESDHC_STROBE_DLL_STS_SLV_LOCK

#define ESDHC_VEND_SPEC2
#define ESDHC_VEND_SPEC2_EN_BUSY_IRQ
#define ESDHC_VEND_SPEC2_AUTO_TUNE_8BIT_EN
#define ESDHC_VEND_SPEC2_AUTO_TUNE_4BIT_EN
#define ESDHC_VEND_SPEC2_AUTO_TUNE_1BIT_EN
#define ESDHC_VEND_SPEC2_AUTO_TUNE_CMD_EN
#define ESDHC_VEND_SPEC2_AUTO_TUNE_MODE_MASK

#define ESDHC_TUNING_CTRL
#define ESDHC_STD_TUNING_EN
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP_DEFAULT
#define ESDHC_TUNING_START_TAP_MASK
#define ESDHC_TUNING_CMD_CRC_CHECK_DISABLE
#define ESDHC_TUNING_STEP_DEFAULT
#define ESDHC_TUNING_STEP_MASK
#define ESDHC_TUNING_STEP_SHIFT

/* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ
#define ESDHC_PINCTRL_STATE_200MHZ

/*
 * Our interpretation of the SDHCI_HOST_CONTROL register
 */
#define ESDHC_CTRL_4BITBUS
#define ESDHC_CTRL_8BITBUS
#define ESDHC_CTRL_BUSWIDTH_MASK
#define USDHC_GET_BUSWIDTH(c)

/*
 * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC:
 * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
 * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
 * Define this macro DMA error INT for fsl eSDHC
 */
#define ESDHC_INT_VENDOR_SPEC_DMA_ERR

/* the address offset of CQHCI */
#define ESDHC_CQHCI_ADDR_OFFSET

/*
 * The CMDTYPE of the CMD register (offset 0xE) should be set to
 * "11" when the STOP CMD12 is issued on imx53 to abort one
 * open ended multi-blk IO. Otherwise the TC INT wouldn't
 * be generated.
 * In exact block transfer, the controller doesn't complete the
 * operations automatically as required at the end of the
 * transfer and remains on hold if the abort command is not sent.
 * As a result, the TC flag is not asserted and SW received timeout
 * exception. Bit1 of Vendor Spec register is used to fix it.
 */
#define ESDHC_FLAG_MULTIBLK_NO_INT
/*
 * The flag tells that the ESDHC controller is an USDHC block that is
 * integrated on the i.MX6 series.
 */
#define ESDHC_FLAG_USDHC
/* The IP supports manual tuning process */
#define ESDHC_FLAG_MAN_TUNING
/* The IP supports standard tuning process */
#define ESDHC_FLAG_STD_TUNING
/* The IP has SDHCI_CAPABILITIES_1 register */
#define ESDHC_FLAG_HAVE_CAP1
/*
 * The IP has erratum ERR004536
 * uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
 * when reading data from the card
 * This flag is also set for i.MX25 and i.MX35 in order to get
 * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits).
 */
#define ESDHC_FLAG_ERR004536
/* The IP supports HS200 mode */
#define ESDHC_FLAG_HS200
/* The IP supports HS400 mode */
#define ESDHC_FLAG_HS400
/*
 * The IP has errata ERR010450
 * uSDHC: At 1.8V due to the I/O timing limit, for SDR mode, SD card
 * clock can't exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
 */
#define ESDHC_FLAG_ERR010450
/* The IP supports HS400ES mode */
#define ESDHC_FLAG_HS400_ES
/* The IP has Host Controller Interface for Command Queuing */
#define ESDHC_FLAG_CQHCI
/* need request pmqos during low power */
#define ESDHC_FLAG_PMQOS
/* The IP state got lost in low power mode */
#define ESDHC_FLAG_STATE_LOST_IN_LPMODE
/* The IP lost clock rate in PM_RUNTIME */
#define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME
/*
 * The IP do not support the ACMD23 feature completely when use ADMA mode.
 * In ADMA mode, it only use the 16 bit block count of the register 0x4
 * (BLOCK_ATT) as the CMD23's argument for ACMD23 mode, which means it will
 * ignore the upper 16 bit of the CMD23's argument. This will block the reliable
 * write operation in RPMB, because RPMB reliable write need to set the bit31
 * of the CMD23's argument.
 * imx6qpdl/imx6sx/imx6sl/imx7d has this limitation only for ADMA mode, SDMA
 * do not has this limitation. so when these SoC use ADMA mode, it need to
 * disable the ACMD23 feature.
 */
#define ESDHC_FLAG_BROKEN_AUTO_CMD23

/* ERR004536 is not applicable for the IP  */
#define ESDHC_FLAG_SKIP_ERR004536

/* The IP does not have GPIO CD wake capabilities */
#define ESDHC_FLAG_SKIP_CD_WAKE

enum wp_types {};

enum cd_types {};

/*
 * struct esdhc_platform_data - platform data for esdhc on i.MX
 *
 * ESDHC_WP(CD)_CONTROLLER type is not available on i.MX25/35.
 *
 * @wp_type:	type of write_protect method (see wp_types enum above)
 * @cd_type:	type of card_detect method (see cd_types enum above)
 */

struct esdhc_platform_data {};

struct esdhc_soc_data {};

static const struct esdhc_soc_data esdhc_imx25_data =;

static const struct esdhc_soc_data esdhc_imx35_data =;

static const struct esdhc_soc_data esdhc_imx51_data =;

static const struct esdhc_soc_data esdhc_imx53_data =;

static const struct esdhc_soc_data usdhc_imx6q_data =;

static const struct esdhc_soc_data usdhc_imx6sl_data =;

static const struct esdhc_soc_data usdhc_imx6sll_data =;

static const struct esdhc_soc_data usdhc_imx6sx_data =;

static const struct esdhc_soc_data usdhc_imx6ull_data =;

static const struct esdhc_soc_data usdhc_imx7d_data =;

static struct esdhc_soc_data usdhc_s32g2_data =;

static struct esdhc_soc_data usdhc_imx7ulp_data =;
static struct esdhc_soc_data usdhc_imxrt1050_data =;

static struct esdhc_soc_data usdhc_imx8qxp_data =;

static struct esdhc_soc_data usdhc_imx8mm_data =;

struct pltfm_imx_data {};

static const struct of_device_id imx_esdhc_dt_ids[] =;
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);

static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
{}

static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
{}

static inline int esdhc_is_usdhc(struct pltfm_imx_data *data)
{}

static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
{}

#define DRIVER_NAME
#define ESDHC_IMX_DUMP(f, x...)
static void esdhc_dump_debug_regs(struct sdhci_host *host)
{}

static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
{}

/* Enable the auto tuning circuit to check the CMD line and BUS line */
static inline void usdhc_auto_tuning_mode_sel_and_en(struct sdhci_host *host)
{}

static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{}

static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
{}

static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{}

static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{}

static u8 esdhc_readb_le(struct sdhci_host *host, int reg)
{}

static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{}

static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
{}

static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
{}

static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
					 unsigned int clock)
{}

static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
{}

static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
{}

static void esdhc_reset_tuning(struct sdhci_host *host)
{}

static void usdhc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{}

static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{}

static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
{}

static void esdhc_post_tuning(struct sdhci_host *host)
{}

/*
 * find the largest pass window, and use the average delay of this
 * largest window to get the best timing.
 */
static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{}

static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios)
{}

static int esdhc_change_pinstate(struct sdhci_host *host,
						unsigned int uhs)
{}

/*
 * For HS400 eMMC, there is a data_strobe line. This signal is generated
 * by the device and used for data output and CRC status response output
 * in HS400 mode. The frequency of this signal follows the frequency of
 * CLK generated by host. The host receives the data which is aligned to the
 * edge of data_strobe line. Due to the time delay between CLK line and
 * data_strobe line, if the delay time is larger than one clock cycle,
 * then CLK and data_strobe line will be misaligned, read error shows up.
 */
static void esdhc_set_strobe_dll(struct sdhci_host *host)
{}

static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{}

static void esdhc_reset(struct sdhci_host *host, u8 mask)
{}

static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
{}

static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{}

static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
{}

static struct sdhci_ops sdhci_esdhc_ops =;

static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata =;

static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
{}

static void esdhc_cqe_enable(struct mmc_host *mmc)
{}

static void esdhc_sdhci_dumpregs(struct mmc_host *mmc)
{}

static const struct cqhci_host_ops esdhc_cqhci_ops =;

static int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
			 struct sdhci_host *host,
			 struct pltfm_imx_data *imx_data)
{}

static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
{}

static void sdhci_esdhc_imx_remove(struct platform_device *pdev)
{}

#ifdef CONFIG_PM_SLEEP
static int sdhci_esdhc_suspend(struct device *dev)
{}

static int sdhci_esdhc_resume(struct device *dev)
{}
#endif

#ifdef CONFIG_PM
static int sdhci_esdhc_runtime_suspend(struct device *dev)
{}

static int sdhci_esdhc_runtime_resume(struct device *dev)
{}
#endif

static const struct dev_pm_ops sdhci_esdhc_pmops =;

static struct platform_driver sdhci_esdhc_imx_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();