drivers/mmc/host/sdhci-of-sparx5.c

Source file repositories/reference/linux-study-clean/drivers/mmc/host/sdhci-of-sparx5.c

File Facts

System
Linux kernel
Corpus path
drivers/mmc/host/sdhci-of-sparx5.c
Extension
.c
Size
7386 bytes
Lines
258
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 sdhci_sparx5_data {
	struct sdhci_host *host;
	struct regmap *cpu_ctrl;
	int delay_clock;
};

#define BOUNDARY_OK(addr, len) \
	((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))

/*
 * If DMA addr spans 128MB boundary, we split the DMA transfer into two
 * so that each DMA transfer doesn't exceed the boundary.
 */
static void sdhci_sparx5_adma_write_desc(struct sdhci_host *host, void **desc,
					  dma_addr_t addr, int len,
					  unsigned int cmd)
{
	int tmplen, offset;

	if (likely(!len || BOUNDARY_OK(addr, len))) {
		sdhci_adma_write_desc(host, desc, addr, len, cmd);
		return;
	}

	pr_debug("%s: write_desc: splitting dma len %d, offset %pad\n",
		 mmc_hostname(host->mmc), len, &addr);

	offset = addr & (SZ_128M - 1);
	tmplen = SZ_128M - offset;
	sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);

	addr += tmplen;
	len -= tmplen;
	sdhci_adma_write_desc(host, desc, addr, len, cmd);
}

static void sparx5_set_cacheable(struct sdhci_host *host, u32 value)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);

	pr_debug("%s: Set Cacheable = 0x%x\n", mmc_hostname(host->mmc), value);

	/* Update ACP caching attributes in HW */
	regmap_update_bits(sdhci_sparx5->cpu_ctrl,
			   CPU_REGS_PROC_CTRL, ACP_CACHE_MASK, value);
}

static void sparx5_set_delay(struct sdhci_host *host, u8 value)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_sparx5_data *sdhci_sparx5 = sdhci_pltfm_priv(pltfm_host);

	pr_debug("%s: Set DLY_CC = %u\n", mmc_hostname(host->mmc), value);

	/* Update DLY_CC in HW */
	regmap_update_bits(sdhci_sparx5->cpu_ctrl,
			   CPU_REGS_GENERAL_CTRL,
			   MSHC_DLY_CC_MASK,
			   (value << MSHC_DLY_CC_SHIFT));
}

static void sdhci_sparx5_set_emmc(struct sdhci_host *host)
{
	if (!mmc_card_is_removable(host->mmc)) {
		u8 value;

		value = sdhci_readb(host, MSHC2_EMMC_CTRL);
		if (!(value & MSHC2_EMMC_CTRL_IS_EMMC)) {
			value |= MSHC2_EMMC_CTRL_IS_EMMC;
			pr_debug("%s: Set EMMC_CTRL: 0x%08x\n",
				 mmc_hostname(host->mmc), value);
			sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
		}
	}
}

static void sdhci_sparx5_reset_emmc(struct sdhci_host *host)
{
	u8 value;

	pr_debug("%s: Toggle EMMC_CTRL.EMMC_RST_N\n", mmc_hostname(host->mmc));
	value = sdhci_readb(host, MSHC2_EMMC_CTRL) &
		~MSHC2_EMMC_CTRL_EMMC_RST_N;
	sdhci_writeb(host, value, MSHC2_EMMC_CTRL);
	/* For eMMC, minimum is 1us but give it 10us for good measure */
	usleep_range(10, 20);
	sdhci_writeb(host, value | MSHC2_EMMC_CTRL_EMMC_RST_N,
		     MSHC2_EMMC_CTRL);
	/* For eMMC, minimum is 200us but give it 300us for good measure */

Annotation

Implementation Notes