Hi Ryder. On 12 October 2018 at 01:01, Ryder Lee <ryder....@mediatek.com> wrote: > From: Weijie Gao <weijie....@mediatek.com> > > This patch adds MT7623 host controller driver for accessing SD/MMC. > > Cc: Jaehoon Chung <jh80.ch...@samsung.com> > Signed-off-by: Weijie Gao <weijie....@mediatek.com> > Signed-off-by: Ryder Lee <ryder....@mediatek.com> > Tested-by: Matthias Brugger <matthias....@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 <s...@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....@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot