[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