[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