[PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
Jaehoon Chung
jh80.chung at samsung.com
Wed Oct 23 01:04:29 CEST 2024
> -----Original Message-----
> From: Vasileios Bimpikas via B4 Relay <devnull+vasileios.bimpikas.analog.com at kernel.org>
> Sent: Monday, October 21, 2024 10:55 PM
> To: Tom Rini <trini at konsulko.com>; Nathan Barrett-Morrison <nathan.morrison at timesys.com>; Greg Malysa
> <greg.malysa at timesys.com>; Ian Roberts <ian.roberts at timesys.com>; Vasileios Bimpikas
> <vasileios.bimpikas at analog.com>; Utsav Agarwal <utsav.agarwal at analog.com>; Arturs Artamonovs
> <arturs.artamonovs at analog.com>; Marek Vasut <marex at denx.de>; Heiko Schocher <hs at denx.de>; Joe
> Hershberger <joe.hershberger at ni.com>; Ramon Fried <rfried.dev at gmail.com>; Stefan Roese <sr at denx.de>;
> Jagan Teki <jagan at amarulasolutions.com>; Peng Fan <peng.fan at nxp.com>; Jaehoon Chung
> <jh80.chung at samsung.com>
> Cc: u-boot at lists.denx.de; adsp-linux at analog.com; Oliver Gaskell <Oliver.Gaskell at analog.com>
> Subject: [PATCH v2 11/11] mmc: Add support for ADI SC5XX-family processor SDHCI peripherals
>
> From: Oliver Gaskell <Oliver.Gaskell at analog.com>
>
> Co-developed-by: Greg Malysa <greg.malysa at timesys.com>
> Signed-off-by: Greg Malysa <greg.malysa at timesys.com>
> Co-developed-by: Ian Roberts <ian.roberts at timesys.com>
> Signed-off-by: Ian Roberts <ian.roberts at timesys.com>
> Signed-off-by: Vasileios Bimpikas <vasileios.bimpikas at analog.com>
> Signed-off-by: Utsav Agarwal <utsav.agarwal at analog.com>
> Signed-off-by: Arturs Artamonovs <arturs.artamonovs at analog.com>
> Signed-off-by: Nathan Barrett-Morrison <nathan.morrison at timesys.com>
> Signed-off-by: Oliver Gaskell <Oliver.Gaskell at analog.com>
> ---
> MAINTAINERS | 1 +
> drivers/mmc/Kconfig | 9 +++
> drivers/mmc/Makefile | 1 +
> drivers/mmc/adi_sdhci.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 165 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a553584fb7390adff2af78fe5d9461e99d0084e7..c59e061671e1bca03236211515bc4016306fdf68 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -616,6 +616,7 @@ F: drivers/dma/adi_dma.c
> F: drivers/gpio/adp5588_gpio.c
> F: drivers/gpio/gpio-adi-adsp.c
> F: drivers/i2c/adi_i2c.c
> +F: drivers/mmc/adi_sdhci.c
> F: drivers/net/dwc_eth_qos_adi.c
> F: drivers/pinctrl/pinctrl-adi-adsp.c
> F: drivers/remoteproc/adi_sc5xx_rproc.c
> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
> index 38817622fca1784703024c357b5d5ca11703afd6..b922765799bdbda991abb306e61969b4d9646e05 100644
> --- a/drivers/mmc/Kconfig
> +++ b/drivers/mmc/Kconfig
> @@ -293,6 +293,15 @@ config MMC_DW_ROCKCHIP
> SD 3.0, SDIO 3.0 and MMC 4.5 and supports common eMMC chips as well
> as removeable SD and micro-SD cards.
>
> +config MMC_SDHCI_ADI
> + bool "ADI SD/MMC controller support"
> + depends on ARCH_SC5XX
> + depends on DM_MMC && OF_CONTROL
> + depends on MMC_SDHCI && MMC_SDHCI_ADMA
> + help
> + This enables support for the SD/MMC controller included in some Analog
> + Devices SC5XX Socs.
> +
> config MMC_DW_SOCFPGA
> bool "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
> depends on ARCH_SOCFPGA
> diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
> index 868f3090ff24cc50cf9d71ac8f1f779efeb1471f..d4b747784b061996e218a2df6906d8c731732b9f 100644
> --- a/drivers/mmc/Makefile
> +++ b/drivers/mmc/Makefile
> @@ -70,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_NPCM) += npcm_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o
> +obj-$(CONFIG_MMC_SDHCI_ADI) += adi_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_STI) += sti_sdhci.o
> obj-$(CONFIG_MMC_SDHCI_TANGIER) += tangier_sdhci.o
> diff --git a/drivers/mmc/adi_sdhci.c b/drivers/mmc/adi_sdhci.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..311089a5f5230d827bbf8b5439064c94ada2b209
> --- /dev/null
> +++ b/drivers/mmc/adi_sdhci.c
> @@ -0,0 +1,154 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * (C) Copyright 2022 - Analog Devices, Inc.
> + *
> + * Written and/or maintained by Timesys Corporation
> + *
> + * Contact: Nathan Barrett-Morrison <nathan.morrison at timesys.com>
> + * Contact: Greg Malysa <greg.malysa at timesys.com>
> + *
> + * Based on Rockchip's sdhci.c file
> + */
> +
> +#include <clk.h>
> +#include <dm.h>
> +#include <malloc.h>
> +#include <sdhci.h>
> +#include <asm/cache.h>
> +
> +/* 400KHz is max freq for card ID etc. Use that as min */
> +#define EMMC_MIN_FREQ 400000
> +
> +/* Check if an operation crossed a boundary of size ADMA_BOUNDARY_ALIGN */
> +#define ADMA_BOUNDARY_ALGN SZ_128M
> +#define BOUNDARY_OK(addr, len) \
> + (((addr) | (ADMA_BOUNDARY_ALGN - 1)) == (((addr) + (len) - 1) | \
> + (ADMA_BOUNDARY_ALGN - 1)))
> +
> +/* We split a descriptor for every crossing of the ADMA alignment boundary,
> + * so we need an additional descriptor for every expected crossing.
> + * As I understand it, the max expected transaction size is:
> + * CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN
> + *
> + * With the way the SDHCI-ADMA driver is implemented, if ADMA_MAX_LEN was a
> + * clean power of two, we'd only ever need +1 descriptor as the first
> + * descriptor that got split would then bring the remaining DMA
> + * destination addresses into alignment. Unfortunately, it's currently
> + * hardcoded to a non-power-of-two value.
> + *
> + * If that ever becomes parameterized, ADMA max length can be set to
> + * 0x10000, and set this to 1.
> + */
> +#define ADMA_POTENTIAL_CROSSINGS \
> + DIV_ROUND_UP((CONFIG_SYS_MMC_MAX_BLK_COUNT * MMC_MAX_BLOCK_LEN), \
> + ADMA_BOUNDARY_ALGN)
> +/* +1 descriptor for each crossing.
> + */
Could you change the above comment? I can't know where is relevant to this comment.
> +#define ADMA_TABLE_EXTRA_SZ (ADMA_POTENTIAL_CROSSINGS * ADMA_DESC_LEN)
> +
> +struct adi_sdhc_plat {
> + struct mmc_config cfg;
> + struct mmc mmc;
> +};
> +
> +struct adi_sdhc {
> + struct sdhci_host host;
> + void *base;
> +};
> +
> +void adi_dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
> + dma_addr_t addr, int len, bool end)
Can it be static?
> +{
> + int tmplen, offset;
> +
> + if (likely(!len || BOUNDARY_OK(addr, len))) {
> + sdhci_adma_write_desc(host, desc, addr, len, end);
> + return;
> + }
> +
> + offset = addr & (ADMA_BOUNDARY_ALGN - 1);
> + tmplen = ADMA_BOUNDARY_ALGN - offset;
> + sdhci_adma_write_desc(host, desc, addr, tmplen, false);
> +
> + addr += tmplen;
> + len -= tmplen;
> + sdhci_adma_write_desc(host, desc, addr, len, end);
> +}
> +
> +struct sdhci_ops adi_dwcmshc_sdhci_ops = {
> + .adma_write_desc = adi_dwcmshc_adma_write_desc,
> +};
> +
> +static int adi_dwcmshc_sdhci_probe(struct udevice *dev)
> +{
> + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
> + struct adi_sdhc_plat *plat = dev_get_plat(dev);
> + struct adi_sdhc *prv = dev_get_priv(dev);
> + struct sdhci_host *host = &prv->host;
> + int max_frequency, ret;
> + struct clk clk;
> +
> + max_frequency = dev_read_u32_default(dev, "max-frequency", 0);
> + ret = clk_get_by_index(dev, 0, &clk);
> +
> + host->quirks = 0;
> + host->max_clk = max_frequency;
> + /*
> + * The sdhci-driver only supports 4bit and 8bit, as sdhci_setup_cfg
> + * doesn't allow us to clear MMC_MODE_4BIT. Consequently, we don't
> + * check for other bus-width values.
> + */
> + if (host->bus_width == 8)
> + host->host_caps |= MMC_MODE_8BIT;
> +
> + host->mmc = &plat->mmc;
> + host->mmc->priv = &prv->host;
> + host->mmc->dev = dev;
> + upriv->mmc = host->mmc;
> +
> + host->ops = &adi_dwcmshc_sdhci_ops;
> + host->adma_desc_table = memalign(ARCH_DMA_MINALIGN,
> + ADMA_TABLE_SZ + ADMA_TABLE_EXTRA_SZ);
> + host->adma_addr = virt_to_phys(host->adma_desc_table);
> +
> + ret = sdhci_setup_cfg(&plat->cfg, host, 0, EMMC_MIN_FREQ);
> + if (ret)
> + return ret;
> +
> + return sdhci_probe(dev);
> +}
> +
> +static int adi_dwcmshc_sdhci_of_to_plat(struct udevice *dev)
> +{
> + struct sdhci_host *host = dev_get_priv(dev);
> +
> + host->name = dev->name;
> + host->ioaddr = dev_read_addr_ptr(dev);
> + host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
> +
> + return 0;
> +}
> +
> +static int adi_sdhci_bind(struct udevice *dev)
> +{
> + struct adi_sdhc_plat *plat = dev_get_plat(dev);
> +
> + return sdhci_bind(dev, &plat->mmc, &plat->cfg);
> +}
> +
> +static const struct udevice_id adi_dwcmshc_sdhci_ids[] = {
> + { .compatible = "adi,dwc-sdhci" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(adi_dwcmshc_sdhci_drv) = {
> + .name = "adi_sdhci",
> + .id = UCLASS_MMC,
> + .of_match = adi_dwcmshc_sdhci_ids,
> + .of_to_plat = adi_dwcmshc_sdhci_of_to_plat,
> + .ops = &sdhci_ops,
> + .bind = adi_sdhci_bind,
> + .probe = adi_dwcmshc_sdhci_probe,
> + .priv_auto = sizeof(struct adi_sdhc),
> + .plat_auto = sizeof(struct adi_sdhc_plat),
> +};
>
> --
> 2.34.1
>
More information about the U-Boot
mailing list