linux/drivers/mmc/host/mtk-sd.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2014-2015, 2022 MediaTek Inc.
 * Author: Chaotian.Jing <[email protected]>
 */

#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pm_wakeirq.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/reset.h>

#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>

#include "cqhci.h"

#define MAX_BD_NUM
#define MSDC_NR_CLOCKS

/*--------------------------------------------------------------------------*/
/* Common Definition                                                        */
/*--------------------------------------------------------------------------*/
#define MSDC_BUS_1BITS
#define MSDC_BUS_4BITS
#define MSDC_BUS_8BITS

#define MSDC_BURST_64B

/*--------------------------------------------------------------------------*/
/* Register Offset                                                          */
/*--------------------------------------------------------------------------*/
#define MSDC_CFG
#define MSDC_IOCON
#define MSDC_PS
#define MSDC_INT
#define MSDC_INTEN
#define MSDC_FIFOCS
#define SDC_CFG
#define SDC_CMD
#define SDC_ARG
#define SDC_STS
#define SDC_RESP0
#define SDC_RESP1
#define SDC_RESP2
#define SDC_RESP3
#define SDC_BLK_NUM
#define SDC_ADV_CFG0
#define EMMC_IOCON
#define SDC_ACMD_RESP
#define DMA_SA_H4BIT
#define MSDC_DMA_SA
#define MSDC_DMA_CTRL
#define MSDC_DMA_CFG
#define MSDC_PATCH_BIT
#define MSDC_PATCH_BIT1
#define MSDC_PATCH_BIT2
#define MSDC_PAD_TUNE
#define MSDC_PAD_TUNE0
#define PAD_DS_TUNE
#define PAD_CMD_TUNE
#define EMMC51_CFG0
#define EMMC50_CFG0
#define EMMC50_CFG1
#define EMMC50_CFG3
#define SDC_FIFO_CFG
#define CQHCI_SETTING

/*--------------------------------------------------------------------------*/
/* Top Pad Register Offset                                                  */
/*--------------------------------------------------------------------------*/
#define EMMC_TOP_CONTROL
#define EMMC_TOP_CMD
#define EMMC50_PAD_DS_TUNE

/*--------------------------------------------------------------------------*/
/* Register Mask                                                            */
/*--------------------------------------------------------------------------*/

/* MSDC_CFG mask */
#define MSDC_CFG_MODE
#define MSDC_CFG_CKPDN
#define MSDC_CFG_RST
#define MSDC_CFG_PIO
#define MSDC_CFG_CKDRVEN
#define MSDC_CFG_BV18SDT
#define MSDC_CFG_BV18PSS
#define MSDC_CFG_CKSTB
#define MSDC_CFG_CKDIV
#define MSDC_CFG_CKMOD
#define MSDC_CFG_HS400_CK_MODE
#define MSDC_CFG_HS400_CK_MODE_EXTRA
#define MSDC_CFG_CKDIV_EXTRA
#define MSDC_CFG_CKMOD_EXTRA

/* MSDC_IOCON mask */
#define MSDC_IOCON_SDR104CKS
#define MSDC_IOCON_RSPL
#define MSDC_IOCON_DSPL
#define MSDC_IOCON_DDLSEL
#define MSDC_IOCON_DDR50CKD
#define MSDC_IOCON_DSPLSEL
#define MSDC_IOCON_W_DSPL
#define MSDC_IOCON_D0SPL
#define MSDC_IOCON_D1SPL
#define MSDC_IOCON_D2SPL
#define MSDC_IOCON_D3SPL
#define MSDC_IOCON_D4SPL
#define MSDC_IOCON_D5SPL
#define MSDC_IOCON_D6SPL
#define MSDC_IOCON_D7SPL
#define MSDC_IOCON_RISCSZ

/* MSDC_PS mask */
#define MSDC_PS_CDEN
#define MSDC_PS_CDSTS
#define MSDC_PS_CDDEBOUNCE
#define MSDC_PS_DAT
#define MSDC_PS_DATA1
#define MSDC_PS_CMD
#define MSDC_PS_WP

/* MSDC_INT mask */
#define MSDC_INT_MMCIRQ
#define MSDC_INT_CDSC
#define MSDC_INT_ACMDRDY
#define MSDC_INT_ACMDTMO
#define MSDC_INT_ACMDCRCERR
#define MSDC_INT_DMAQ_EMPTY
#define MSDC_INT_SDIOIRQ
#define MSDC_INT_CMDRDY
#define MSDC_INT_CMDTMO
#define MSDC_INT_RSPCRCERR
#define MSDC_INT_CSTA
#define MSDC_INT_XFER_COMPL
#define MSDC_INT_DXFER_DONE
#define MSDC_INT_DATTMO
#define MSDC_INT_DATCRCERR
#define MSDC_INT_ACMD19_DONE
#define MSDC_INT_DMA_BDCSERR
#define MSDC_INT_DMA_GPDCSERR
#define MSDC_INT_DMA_PROTECT
#define MSDC_INT_CMDQ

/* MSDC_INTEN mask */
#define MSDC_INTEN_MMCIRQ
#define MSDC_INTEN_CDSC
#define MSDC_INTEN_ACMDRDY
#define MSDC_INTEN_ACMDTMO
#define MSDC_INTEN_ACMDCRCERR
#define MSDC_INTEN_DMAQ_EMPTY
#define MSDC_INTEN_SDIOIRQ
#define MSDC_INTEN_CMDRDY
#define MSDC_INTEN_CMDTMO
#define MSDC_INTEN_RSPCRCERR
#define MSDC_INTEN_CSTA
#define MSDC_INTEN_XFER_COMPL
#define MSDC_INTEN_DXFER_DONE
#define MSDC_INTEN_DATTMO
#define MSDC_INTEN_DATCRCERR
#define MSDC_INTEN_ACMD19_DONE
#define MSDC_INTEN_DMA_BDCSERR
#define MSDC_INTEN_DMA_GPDCSERR
#define MSDC_INTEN_DMA_PROTECT

/* MSDC_FIFOCS mask */
#define MSDC_FIFOCS_RXCNT
#define MSDC_FIFOCS_TXCNT
#define MSDC_FIFOCS_CLR

/* SDC_CFG mask */
#define SDC_CFG_SDIOINTWKUP
#define SDC_CFG_INSWKUP
#define SDC_CFG_WRDTOC
#define SDC_CFG_BUSWIDTH
#define SDC_CFG_SDIO
#define SDC_CFG_SDIOIDE
#define SDC_CFG_INTATGAP
#define SDC_CFG_DTOC

/* SDC_STS mask */
#define SDC_STS_SDCBUSY
#define SDC_STS_CMDBUSY
#define SDC_STS_SWR_COMPL

#define SDC_DAT1_IRQ_TRIGGER
/* SDC_ADV_CFG0 mask */
#define SDC_RX_ENHANCE_EN

/* DMA_SA_H4BIT mask */
#define DMA_ADDR_HIGH_4BIT

/* MSDC_DMA_CTRL mask */
#define MSDC_DMA_CTRL_START
#define MSDC_DMA_CTRL_STOP
#define MSDC_DMA_CTRL_RESUME
#define MSDC_DMA_CTRL_MODE
#define MSDC_DMA_CTRL_LASTBUF
#define MSDC_DMA_CTRL_BRUSTSZ

/* MSDC_DMA_CFG mask */
#define MSDC_DMA_CFG_STS
#define MSDC_DMA_CFG_DECSEN
#define MSDC_DMA_CFG_AHBHPROT2
#define MSDC_DMA_CFG_ACTIVEEN
#define MSDC_DMA_CFG_CS12B16B

/* MSDC_PATCH_BIT mask */
#define MSDC_PATCH_BIT_ODDSUPP
#define MSDC_INT_DAT_LATCH_CK_SEL
#define MSDC_CKGEN_MSDC_DLY_SEL
#define MSDC_PATCH_BIT_IODSSEL
#define MSDC_PATCH_BIT_IOINTSEL
#define MSDC_PATCH_BIT_BUSYDLY
#define MSDC_PATCH_BIT_WDOD
#define MSDC_PATCH_BIT_IDRTSEL
#define MSDC_PATCH_BIT_CMDFSEL
#define MSDC_PATCH_BIT_INTDLSEL
#define MSDC_PATCH_BIT_SPCPUSH
#define MSDC_PATCH_BIT_DECRCTMO

#define MSDC_PATCH_BIT1_CMDTA
#define MSDC_PB1_BUSY_CHECK_SEL
#define MSDC_PATCH_BIT1_STOP_DLY

#define MSDC_PATCH_BIT2_CFGRESP
#define MSDC_PATCH_BIT2_CFGCRCSTS
#define MSDC_PB2_SUPPORT_64G
#define MSDC_PB2_RESPWAIT
#define MSDC_PB2_RESPSTSENSEL
#define MSDC_PB2_CRCSTSENSEL

#define MSDC_PAD_TUNE_DATWRDLY
#define MSDC_PAD_TUNE_DATRRDLY
#define MSDC_PAD_TUNE_DATRRDLY2
#define MSDC_PAD_TUNE_CMDRDLY
#define MSDC_PAD_TUNE_CMDRDLY2
#define MSDC_PAD_TUNE_CMDRRDLY
#define MSDC_PAD_TUNE_CLKTDLY
#define MSDC_PAD_TUNE_RXDLYSEL
#define MSDC_PAD_TUNE_RD_SEL
#define MSDC_PAD_TUNE_CMD_SEL
#define MSDC_PAD_TUNE_RD2_SEL
#define MSDC_PAD_TUNE_CMD2_SEL

#define PAD_DS_TUNE_DLY_SEL
#define PAD_DS_TUNE_DLY1
#define PAD_DS_TUNE_DLY2
#define PAD_DS_TUNE_DLY3

#define PAD_CMD_TUNE_RX_DLY3

/* EMMC51_CFG0 mask */
#define CMDQ_RDAT_CNT

#define EMMC50_CFG_PADCMD_LATCHCK
#define EMMC50_CFG_CRCSTS_EDGE
#define EMMC50_CFG_CFCSTS_SEL
#define EMMC50_CFG_CMD_RESP_SEL

/* EMMC50_CFG1 mask */
#define EMMC50_CFG1_DS_CFG

#define EMMC50_CFG3_OUTS_WR

#define SDC_FIFO_CFG_WRVALIDSEL
#define SDC_FIFO_CFG_RDVALIDSEL

/* CQHCI_SETTING */
#define CQHCI_RD_CMD_WND_SEL
#define CQHCI_WR_CMD_WND_SEL

/* EMMC_TOP_CONTROL mask */
#define PAD_RXDLY_SEL
#define DELAY_EN
#define PAD_DAT_RD_RXDLY2
#define PAD_DAT_RD_RXDLY
#define PAD_DAT_RD_RXDLY2_SEL
#define PAD_DAT_RD_RXDLY_SEL
#define DATA_K_VALUE_SEL
#define SDC_RX_ENH_EN

/* EMMC_TOP_CMD mask */
#define PAD_CMD_RXDLY2
#define PAD_CMD_RXDLY
#define PAD_CMD_RD_RXDLY2_SEL
#define PAD_CMD_RD_RXDLY_SEL
#define PAD_CMD_TX_DLY

/* EMMC50_PAD_DS_TUNE mask */
#define PAD_DS_DLY_SEL
#define PAD_DS_DLY1
#define PAD_DS_DLY3

#define REQ_CMD_EIO
#define REQ_CMD_TMO
#define REQ_DAT_ERR
#define REQ_STOP_EIO
#define REQ_STOP_TMO
#define REQ_CMD_BUSY

#define MSDC_PREPARE_FLAG
#define MSDC_ASYNC_FLAG
#define MSDC_MMAP_FLAG

#define MTK_MMC_AUTOSUSPEND_DELAY
#define CMD_TIMEOUT
#define DAT_TIMEOUT

#define DEFAULT_DEBOUNCE

#define TUNING_REG2_FIXED_OFFEST
#define PAD_DELAY_HALF
#define PAD_DELAY_FULL
/*--------------------------------------------------------------------------*/
/* Descriptor Structure                                                     */
/*--------------------------------------------------------------------------*/
struct mt_gpdma_desc {};

struct mt_bdma_desc {};

struct msdc_dma {};

struct msdc_save_para {};

struct mtk_mmc_compatible {};

struct msdc_tune_para {};

struct msdc_delay_phase {};

struct msdc_host {};

static const struct mtk_mmc_compatible mt2701_compat =;

static const struct mtk_mmc_compatible mt2712_compat =;

static const struct mtk_mmc_compatible mt6779_compat =;

static const struct mtk_mmc_compatible mt6795_compat =;

static const struct mtk_mmc_compatible mt7620_compat =;

static const struct mtk_mmc_compatible mt7622_compat =;

static const struct mtk_mmc_compatible mt7986_compat =;

static const struct mtk_mmc_compatible mt8135_compat =;

static const struct mtk_mmc_compatible mt8173_compat =;

static const struct mtk_mmc_compatible mt8183_compat =;

static const struct mtk_mmc_compatible mt8516_compat =;

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

static void sdr_set_bits(void __iomem *reg, u32 bs)
{}

static void sdr_clr_bits(void __iomem *reg, u32 bs)
{}

static void sdr_set_field(void __iomem *reg, u32 field, u32 val)
{}

static void sdr_get_field(void __iomem *reg, u32 field, u32 *val)
{}

static void msdc_reset_hw(struct msdc_host *host)
{}

static void msdc_cmd_next(struct msdc_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd);
static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb);

static const u32 cmd_ints_mask =;
static const u32 data_ints_mask =;

static u8 msdc_dma_calcs(u8 *buf, u32 len)
{}

static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma,
		struct mmc_data *data)
{}

static void msdc_prepare_data(struct msdc_host *host, struct mmc_data *data)
{}

static void msdc_unprepare_data(struct msdc_host *host, struct mmc_data *data)
{}

static u64 msdc_timeout_cal(struct msdc_host *host, u64 ns, u64 clks)
{}

/* clock control primitives */
static void msdc_set_timeout(struct msdc_host *host, u64 ns, u64 clks)
{}

static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
{}

static void msdc_gate_clock(struct msdc_host *host)
{}

static int msdc_ungate_clock(struct msdc_host *host)
{}

static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{}

static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
		struct mmc_command *cmd)
{}

static inline u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd)
{}

static void msdc_start_data(struct msdc_host *host, struct mmc_command *cmd,
		struct mmc_data *data)
{}

static int msdc_auto_cmd_done(struct msdc_host *host, int events,
		struct mmc_command *cmd)
{}

/*
 * msdc_recheck_sdio_irq - recheck whether the SDIO irq is lost
 *
 * Host controller may lost interrupt in some special case.
 * Add SDIO irq recheck mechanism to make sure all interrupts
 * can be processed immediately
 */
static void msdc_recheck_sdio_irq(struct msdc_host *host)
{}

static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd)
{}

static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
{}

/* returns true if command is fully handled; returns false otherwise */
static bool msdc_cmd_done(struct msdc_host *host, int events,
			  struct mmc_request *mrq, struct mmc_command *cmd)
{}

/* It is the core layer's responsibility to ensure card status
 * is correct before issue a request. but host design do below
 * checks recommended.
 */
static inline bool msdc_cmd_is_ready(struct msdc_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd)
{}

static void msdc_start_command(struct msdc_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd)
{}

static void msdc_cmd_next(struct msdc_host *host,
		struct mmc_request *mrq, struct mmc_command *cmd)
{}

static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
{}

static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{}

static void msdc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
		int err)
{}

static void msdc_data_xfer_next(struct msdc_host *host, struct mmc_request *mrq)
{}

static void msdc_data_xfer_done(struct msdc_host *host, u32 events,
				struct mmc_request *mrq, struct mmc_data *data)
{}

static void msdc_set_buswidth(struct msdc_host *host, u32 width)
{}

static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios)
{}

static int msdc_card_busy(struct mmc_host *mmc)
{}

static void msdc_request_timeout(struct work_struct *work)
{}

static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb)
{}

static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{}

static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
{}

static irqreturn_t msdc_irq(int irq, void *dev_id)
{}

static void msdc_init_hw(struct msdc_host *host)
{}

static void msdc_deinit_hw(struct msdc_host *host)
{}

/* init gpd and bd list in msdc_drv_probe */
static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
{}

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

static u64 test_delay_bit(u64 delay, u32 bit)
{}

static int get_delay_len(u64 delay, u32 start_bit)
{}

static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u64 delay)
{}

static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value)
{}

static inline void msdc_set_data_delay(struct msdc_host *host, u32 value)
{}

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

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

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

/*
 * MSDC IP which supports data tune + async fifo can do CMD/DAT tune
 * together, which can save the tuning time.
 */
static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
{}

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

static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
{}

static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card)
{}

static void msdc_hw_reset(struct mmc_host *mmc)
{}

static void msdc_ack_sdio_irq(struct mmc_host *mmc)
{}

static int msdc_get_cd(struct mmc_host *mmc)
{}

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

static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
{}

static void msdc_cqe_enable(struct mmc_host *mmc)
{}

static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
{}

static void msdc_cqe_pre_enable(struct mmc_host *mmc)
{}

static void msdc_cqe_post_disable(struct mmc_host *mmc)
{}

static const struct mmc_host_ops mt_msdc_ops =;

static const struct cqhci_host_ops msdc_cmdq_ops =;

static void msdc_of_property_parse(struct platform_device *pdev,
				   struct msdc_host *host)
{}

static int msdc_of_clock_parse(struct platform_device *pdev,
			       struct msdc_host *host)
{}

static int msdc_drv_probe(struct platform_device *pdev)
{}

static void msdc_drv_remove(struct platform_device *pdev)
{}

static void msdc_save_reg(struct msdc_host *host)
{}

static void msdc_restore_reg(struct msdc_host *host)
{}

static int __maybe_unused msdc_runtime_suspend(struct device *dev)
{}

static int __maybe_unused msdc_runtime_resume(struct device *dev)
{}

static int __maybe_unused msdc_suspend(struct device *dev)
{}

static int __maybe_unused msdc_resume(struct device *dev)
{}

static const struct dev_pm_ops msdc_dev_pm_ops =;

static struct platform_driver mt_msdc_driver =;

module_platform_driver();
MODULE_LICENSE();
MODULE_DESCRIPTION();