[U-Boot] [PATCH v2 16/18] mmc: mtk-sd: add SD/MMC host controller driver for MT7623 SoC
Simon Glass
sjg at chromium.org
Thu Oct 25 03:30:16 UTC 2018
Hi Ryder.
On 12 October 2018 at 01:01, Ryder Lee <ryder.lee at mediatek.com> wrote:
> From: Weijie Gao <weijie.gao at mediatek.com>
>
> This patch adds MT7623 host controller driver for accessing SD/MMC.
>
> Cc: Jaehoon Chung <jh80.chung at samsung.com>
> Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
> Signed-off-by: Ryder Lee <ryder.lee at mediatek.com>
> Tested-by: Matthias Brugger <matthias.bgg at gmail.com>
> ---
> drivers/mmc/Kconfig | 9 +
> drivers/mmc/Makefile | 1 +
> drivers/mmc/mtk-sd.c | 1331 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 1341 insertions(+)
> create mode 100644 drivers/mmc/mtk-sd.c
Reviewed-by: Simon Glass <sjg at chromium.org>
nits below
>
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
> index 0a0d4aa..ca13341 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -598,6 +598,15 @@ config FTSDC010_SDIO
> help
> This can enable ftsdc010 sdio function.
>
> +config MMC_MTK
> + bool "MediaTek SD/MMC Card Interface support"
> + default n
You should be able to omit this since it is the default.
> + help
> + This selects the MediaTek(R) Secure digital and Multimedia card Interface.
> + If you have a machine with a integrated SD/MMC card reader, say Y or M here.
> + This is needed if support for any SD/SDIO/MMC devices is required.
> + If unsure, say N.
> +
> endif
>
> config TEGRA124_MMC_DISABLE_EXT_LOOPBACK
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 23c5b0d..801a26d 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -65,3 +65,4 @@ obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o
> obj-$(CONFIG_MMC_UNIPHIER) += tmio-common.o uniphier-sd.o
> obj-$(CONFIG_RENESAS_SDHI) += tmio-common.o renesas-sdhi.o
> obj-$(CONFIG_MMC_BCM2835) += bcm2835_sdhost.o
> +obj-$(CONFIG_MMC_MTK) += mtk-sd.o
> diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
> new file mode 100644
> index 0000000..5027764
> --- /dev/null
> +++ b/drivers/mmc/mtk-sd.c
> @@ -0,0 +1,1331 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * MediaTek SD/MMC Card Interface driver
> + *
> + * Copyright (C) 2018 MediaTek Inc.
> + * Author: Weijie Gao <weijie.gao at mediatek.com>
> + */
> +
> +#include <clk.h>
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/pinctrl.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <malloc.h>
> +#include <mmc.h>
> +#include <asm/gpio.h>
> +#include <linux/bitops.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
Please check include-file order on all these patches.
> +
> +#define MSDC_CFG 0x0
> +#define MSDC_CFG_HS400_CK_MODE_EXT BIT(22)
> +#define MSDC_CFG_CKMOD_EXT_M 0x03
> +#define MSDC_CFG_CKMOD_EXT_S 20
> +#define MSDC_CFG_CKDIV_EXT_M 0xfff
> +#define MSDC_CFG_CKDIV_EXT_S 8
> +#define MSDC_CFG_HS400_CK_MODE BIT(18)
> +#define MSDC_CFG_CKMOD_M 0x03
> +#define MSDC_CFG_CKMOD_S 16
> +#define MSDC_CFG_CKDIV_M 0xff
> +#define MSDC_CFG_CKDIV_S 8
We mostly use shifted masks in U-Boot since they are easier to use:
+#define MSDC_CFG_CKDIV_S 8
+#define MSDC_CFG_CKDIV_M (0xff << MSDC_CFG_CKDIV_S)
> +#define MSDC_CFG_CKSTB BIT(7)
> +#define MSDC_CFG_PIO BIT(3)
> +#define MSDC_CFG_RST BIT(2)
> +#define MSDC_CFG_CKPDN BIT(1)
> +#define MSDC_CFG_MODE BIT(0)
> +
> +#define MSDC_IOCON 0x04
> +#define MSDC_IOCON_W_DSPL BIT(8)
> +#define MSDC_IOCON_DSPL BIT(2)
> +#define MSDC_IOCON_RSPL BIT(1)
> +
> +#define MSDC_PS 0x08
> +#define MSDC_PS_DAT0 BIT(16)
> +#define MSDC_PS_CDEN BIT(0)
> +
> +#define MSDC_INT 0x0c
> +#define MSDC_INTEN 0x10
> +#define MSDC_INT_ACMDRDY BIT(3)
> +#define MSDC_INT_ACMDTMO BIT(4)
> +#define MSDC_INT_ACMDCRCERR BIT(5)
> +#define MSDC_INT_CMDRDY BIT(8)
> +#define MSDC_INT_CMDTMO BIT(9)
> +#define MSDC_INT_RSPCRCERR BIT(10)
> +#define MSDC_INT_XFER_COMPL BIT(12)
> +#define MSDC_INT_DATTMO BIT(14)
> +#define MSDC_INT_DATCRCERR BIT(15)
> +
> +#define MSDC_FIFOCS 0x14
> +#define MSDC_FIFOCS_CLR BIT(31)
> +#define MSDC_FIFOCS_TXCNT_M 0xff
> +#define MSDC_FIFOCS_TXCNT_S 16
> +#define MSDC_FIFOCS_RXCNT_M 0xff
> +#define MSDC_FIFOCS_RXCNT_S 0
> +
> +#define MSDC_TXDATA 0x18
> +#define MSDC_RXDATA 0x1c
> +
> +#define SDC_CFG 0x30
> +#define SDC_CFG_DTOC_M 0xff
> +#define SDC_CFG_DTOC_S 24
> +#define SDC_CFG_SDIOIDE BIT(20)
> +#define SDC_CFG_SDIO BIT(19)
> +#define SDC_CFG_BUSWIDTH_M 0x03
> +#define SDC_CFG_BUSWIDTH_S 16
> +
> +#define SDC_CMD 0x34
> +#define SDC_CMD_BLK_LEN_M 0xfff
> +#define SDC_CMD_BLK_LEN_S 16
> +#define SDC_CMD_STOP BIT(14)
> +#define SDC_CMD_WR BIT(13)
> +#define SDC_CMD_DTYPE_M 0x03
> +#define SDC_CMD_DTYPE_S 11
> +#define SDC_CMD_RSPTYP_M 0x07
> +#define SDC_CMD_RSPTYP_S 7
> +#define SDC_CMD_CMD_M 0x3f
> +#define SDC_CMD_CMD_S 0
> +
> +#define SDC_ARG 0x38
> +
> +#define SDC_STS 0x3c
> +#define SDC_STS_CMDBUSY BIT(1)
> +#define SDC_STS_SDCBUSY BIT(0)
> +
> +#define SDC_RESP0 0x40
> +#define SDC_RESP1 0x44
> +#define SDC_RESP2 0x48
> +#define SDC_RESP3 0x4c
> +
> +#define SDC_BLK_NUM 0x50
> +
> +#define SDC_ADV_CFG0 0x64
> +#define SDC_RX_ENHANCE_EN BIT(20)
> +
> +#define MSDC_PATCH_BIT 0xb0
> +#define MSDC_INT_DAT_LATCH_CK_SEL_M 0x07
> +#define MSDC_INT_DAT_LATCH_CK_SEL_S 7
> +
> +#define MSDC_PATCH_BIT1 0xb4
> +#define MSDC_PB1_STOP_DLY_M 0x0f
> +#define MSDC_PB1_STOP_DLY_S 8
> +
> +#define MSDC_PATCH_BIT2 0xb8
> +#define MSDC_PB2_CRCSTSENSEL_M 0x07
> +#define MSDC_PB2_CRCSTSENSEL_S 29
> +#define MSDC_PB2_CFGCRCSTS BIT(28)
> +#define MSDC_PB2_RESPSTSENSEL_M 0x07
> +#define MSDC_PB2_RESPSTSENSEL_S 16
> +#define MSDC_PB2_CFGRESP BIT(15)
> +#define MSDC_PB2_RESPWAIT_M 0x03
> +#define MSDC_PB2_RESPWAIT_S 2
> +
> +#define MSDC_PAD_TUNE 0xec
> +#define MSDC_PAD_TUNE_CMDRRDLY_M 0x1f
> +#define MSDC_PAD_TUNE_CMDRRDLY_S 22
> +#define MSDC_PAD_TUNE_CMD_SEL BIT(21)
> +#define MSDC_PAD_TUNE_CMDRDLY_M 0x1f
> +#define MSDC_PAD_TUNE_CMDRDLY_S 16
> +#define MSDC_PAD_TUNE_RXDLYSEL BIT(15)
> +#define MSDC_PAD_TUNE_RD_SEL BIT(13)
> +#define MSDC_PAD_TUNE_DATRRDLY_M 0x1f
> +#define MSDC_PAD_TUNE_DATRRDLY_S 8
> +#define MSDC_PAD_TUNE_DATWRDLY_M 0x1f
> +#define MSDC_PAD_TUNE_DATWRDLY_S 0
> +
> +#define MSDC_PAD_TUNE0 0xf0
> +
> +#define PAD_DS_TUNE 0x188
> +
> +#define EMMC50_CFG0 0x208
> +#define EMMC50_CFG_CFCSTS_SEL BIT(4)
> +
> +#define SDC_FIFO_CFG 0x228
> +#define SDC_FIFO_CFG_WRVALIDSEL BIT(24)
> +#define SDC_FIFO_CFG_RDVALIDSEL BIT(25)
> +
> +/* SDC_CFG_BUSWIDTH */
> +#define MSDC_BUS_1BITS 0x0
> +#define MSDC_BUS_4BITS 0x1
> +#define MSDC_BUS_8BITS 0x2
> +
> +#define MSDC_FIFO_SIZE 128
> +
> +#define PAD_DELAY_MAX 32
> +
> +#define CMD_INTS_MASK \
> + (MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO)
> +
> +#define DATA_INTS_MASK \
> + (MSDC_INT_XFER_COMPL | MSDC_INT_DATTMO | MSDC_INT_DATCRCERR)
> +
> +struct msdc_compatible {
> + u8 clk_div_bits;
> + bool pad_tune0;
> + bool async_fifo;
> + bool data_tune;
> + bool busy_check;
> + bool stop_clk_fix;
> + bool enhance_rx;
> +};
> +
> +struct msdc_delay_phase {
> + u8 maxlen;
> + u8 start;
> + u8 final_phase;
> +};
> +
> +struct msdc_plat {
> + struct mmc_config cfg;
> + struct mmc mmc;
> +};
> +
> +struct msdc_tune_para {
> + u32 iocon;
> + u32 pad_tune;
> +};
> +
> +struct msdc_host {
> + void __iomem *base;
> + struct mmc *mmc;
> +
> + struct msdc_compatible *dev_comp;
> +
> + struct clk src_clk;
> + struct clk h_clk;
> +
> + u32 mclk;
> + u32 src_clk_freq;
> + u32 sclk;
> +
> + u32 timeout_ns;
> + u32 timeout_clks;
> +
> + u32 hs400_ds_delay;
> + u32 hs200_cmd_int_delay;
> + u32 hs200_write_int_delay;
> + u32 latch_ck;
> + u32 r_smpl;
> + bool hs400_mode;
> +
> + struct gpio_desc gpio_wp;
> + struct gpio_desc gpio_cd;
> +
> + uint last_resp_type;
> + uint last_data_write;
> +
> + enum bus_mode timing;
> +
> + struct msdc_tune_para def_tune_para;
> + struct msdc_tune_para saved_tune_para;
This struct needs comments.
> +};
> +
> +static void msdc_reset_hw(struct msdc_host *host)
> +{
> + u32 reg;
> +
> + setbits_le32(host->base + MSDC_CFG, MSDC_CFG_RST);
> +
> + readl_poll_timeout(host->base + MSDC_CFG, reg,
> + !(reg & MSDC_CFG_RST), 1000000);
> +}
> +
> +static void msdc_fifo_clr(struct msdc_host *host)
> +{
> + u32 reg;
> +
> + setbits_le32(host->base + MSDC_FIFOCS, MSDC_FIFOCS_CLR);
> +
> + readl_poll_timeout(host->base + MSDC_FIFOCS, reg,
> + !(reg & MSDC_FIFOCS_CLR), 1000000);
> +}
> +
> +static u32 msdc_fifo_rx_bytes(struct msdc_host *host)
> +{
> + return (readl(host->base + MSDC_FIFOCS) >> MSDC_FIFOCS_RXCNT_S) &
> + MSDC_FIFOCS_RXCNT_M;
> +}
> +
> +static u32 msdc_fifo_tx_bytes(struct msdc_host *host)
> +{
> + return (readl(host->base + MSDC_FIFOCS) >> MSDC_FIFOCS_TXCNT_S) &
> + MSDC_FIFOCS_TXCNT_M;
> +}
> +
> +static u32 msdc_cmd_find_resp(struct msdc_host *host, struct mmc_cmd *cmd)
> +{
> + u32 resp;
> +
> + switch (cmd->resp_type) {
> + /* Actually, R1, R5, R6, R7 are the same */
> + case MMC_RSP_R1:
> + resp = 0x1;
> + break;
> + case MMC_RSP_R1b:
> + resp = 0x7;
> + break;
> + case MMC_RSP_R2:
> + resp = 0x2;
> + break;
> + case MMC_RSP_R3:
> + resp = 0x3;
> + break;
> + case MMC_RSP_NONE:
> + default:
> + resp = 0x0;
> + break;
> + }
> +
> + return resp;
> +}
> +
> +static u32 msdc_cmd_prepare_raw_cmd(struct msdc_host *host,
> + struct mmc_cmd *cmd,
> + struct mmc_data *data)
> +{
> + u32 opcode = cmd->cmdidx;
> + u32 resp_type = msdc_cmd_find_resp(host, cmd);
> + uint blocksize = 0;
> + u32 dtype = 0;
> + u32 rawcmd = 0;
> +
> + switch (opcode) {
> + case MMC_CMD_WRITE_MULTIPLE_BLOCK:
> + case MMC_CMD_READ_MULTIPLE_BLOCK:
> + dtype = 2;
> + break;
> + case MMC_CMD_WRITE_SINGLE_BLOCK:
> + case MMC_CMD_READ_SINGLE_BLOCK:
> + case SD_CMD_APP_SEND_SCR:
> + dtype = 1;
> + break;
> + case SD_CMD_SWITCH_FUNC: /* same as MMC_CMD_SWITCH */
> + case SD_CMD_SEND_IF_COND: /* same as MMC_CMD_SEND_EXT_CSD */
> + case SD_CMD_APP_SD_STATUS: /* same as MMC_CMD_SEND_STATUS */
> + if (data)
> + dtype = 1;
> + }
> +
> + if (data) {
> + if (data->flags == MMC_DATA_WRITE)
> + rawcmd |= SDC_CMD_WR;
> +
> + if (data->blocks > 1)
> + dtype = 2;
> +
> + blocksize = data->blocksize;
> + }
> +
> + rawcmd |= ((opcode & SDC_CMD_CMD_M) << SDC_CMD_CMD_S) |
> + ((resp_type & SDC_CMD_RSPTYP_M) << SDC_CMD_RSPTYP_S) |
> + ((blocksize & SDC_CMD_BLK_LEN_M) << SDC_CMD_BLK_LEN_S) |
> + ((dtype & SDC_CMD_DTYPE_M) << SDC_CMD_DTYPE_S);
> +
> + if (opcode == MMC_CMD_STOP_TRANSMISSION)
> + rawcmd |= SDC_CMD_STOP;
> +
> + return rawcmd;
> +}
> +
> +static int msdc_cmd_done(struct msdc_host *host, int events,
> + struct mmc_cmd *cmd)
> +{
> + u32 *rsp = cmd->response;
> + int ret = 0;
> +
> + if (cmd->resp_type & MMC_RSP_PRESENT) {
> + if (cmd->resp_type & MMC_RSP_136) {
> + rsp[0] = readl(host->base + SDC_RESP3);
> + rsp[1] = readl(host->base + SDC_RESP2);
> + rsp[2] = readl(host->base + SDC_RESP1);
> + rsp[3] = readl(host->base + SDC_RESP0);
> + } else {
> + rsp[0] = readl(host->base + SDC_RESP0);
Use a C struct instead of all this base +_ xxx stuff?
[..]
> +static int msdc_drv_probe(struct udevice *dev)
> +{
> + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> + struct msdc_plat *plat = dev_get_platdata(dev);
> + struct msdc_host *host = dev_get_priv(dev);
> + struct mmc_config *cfg = &plat->cfg;
> + int ret;
> +
> + cfg->name = dev->name;
> +
> + host->base = (void *)dev_read_addr(dev);
> + if (!host->base)
> + return -EINVAL;
> +
> + ret = mmc_of_parse(dev, cfg);
> + if (ret)
> + return ret;
Normally we read the DT in the ofdata_to_platdata() method.
[..]
Regards,
Simon
More information about the U-Boot
mailing list