drivers/mmc/host/mmci_stm32_sdmmc.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/mmci_stm32_sdmmc.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/mmci_stm32_sdmmc.c
Extension
.c
Size
19168 bytes
Lines
750
Domain
Driver Families
Bucket
drivers/mmc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct sdmmc_lli_desc {
	u32 idmalar;
	u32 idmabase;
	u32 idmasize;
};

struct sdmmc_idma {
	dma_addr_t sg_dma;
	void *sg_cpu;
	dma_addr_t bounce_dma_addr;
	void *bounce_buf;
	bool use_bounce_buffer;
};

struct sdmmc_dlyb;

struct sdmmc_tuning_ops {
	int (*dlyb_enable)(struct sdmmc_dlyb *dlyb);
	void (*set_input_ck)(struct sdmmc_dlyb *dlyb);
	int (*tuning_prepare)(struct mmci_host *host);
	int (*set_cfg)(struct sdmmc_dlyb *dlyb, int unit __maybe_unused,
		       int phase, bool sampler __maybe_unused);
};

struct sdmmc_dlyb {
	void __iomem *base;
	u32 unit;
	u32 max;
	struct sdmmc_tuning_ops *ops;
};

static int sdmmc_idma_validate_data(struct mmci_host *host,
				    struct mmc_data *data)
{
	struct sdmmc_idma *idma = host->dma_priv;
	struct device *dev = mmc_dev(host->mmc);
	struct scatterlist *sg;
	int i;

	/*
	 * idma has constraints on idmabase & idmasize for each element
	 * excepted the last element which has no constraint on idmasize
	 */
	idma->use_bounce_buffer = false;
	for_each_sg(data->sg, sg, data->sg_len - 1, i) {
		if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
		    !IS_ALIGNED(sg->length,
				host->variant->stm32_idmabsize_align)) {
			dev_dbg(mmc_dev(host->mmc),
				"unaligned scatterlist: ofst:%x length:%d\n",
				data->sg->offset, data->sg->length);
			goto use_bounce_buffer;
		}
	}

	if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
		dev_dbg(mmc_dev(host->mmc),
			"unaligned last scatterlist: ofst:%x length:%d\n",
			data->sg->offset, data->sg->length);
		goto use_bounce_buffer;
	}

	return 0;

use_bounce_buffer:
	if (!idma->bounce_buf) {
		idma->bounce_buf = dmam_alloc_coherent(dev,
						       host->mmc->max_req_size,
						       &idma->bounce_dma_addr,
						       GFP_KERNEL);
		if (!idma->bounce_buf) {
			dev_err(dev, "Unable to map allocate DMA bounce buffer.\n");
			return -ENOMEM;
		}
	}

	idma->use_bounce_buffer = true;

	return 0;
}

static int _sdmmc_idma_prep_data(struct mmci_host *host,
				 struct mmc_data *data)
{
	struct sdmmc_idma *idma = host->dma_priv;

	if (idma->use_bounce_buffer) {
		if (data->flags & MMC_DATA_WRITE) {
			unsigned int xfer_bytes = data->blksz * data->blocks;

Annotation

Implementation Notes