162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) STMicroelectronics 2018 - All Rights Reserved 462306a36Sopenharmony_ci * Author: Ludovic.barre@st.com for STMicroelectronics. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 962306a36Sopenharmony_ci#include <linux/iopoll.h> 1062306a36Sopenharmony_ci#include <linux/mmc/host.h> 1162306a36Sopenharmony_ci#include <linux/mmc/card.h> 1262306a36Sopenharmony_ci#include <linux/of_address.h> 1362306a36Sopenharmony_ci#include <linux/reset.h> 1462306a36Sopenharmony_ci#include <linux/scatterlist.h> 1562306a36Sopenharmony_ci#include "mmci.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define SDMMC_LLI_BUF_LEN PAGE_SIZE 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define DLYB_CR 0x0 2062306a36Sopenharmony_ci#define DLYB_CR_DEN BIT(0) 2162306a36Sopenharmony_ci#define DLYB_CR_SEN BIT(1) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define DLYB_CFGR 0x4 2462306a36Sopenharmony_ci#define DLYB_CFGR_SEL_MASK GENMASK(3, 0) 2562306a36Sopenharmony_ci#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8) 2662306a36Sopenharmony_ci#define DLYB_CFGR_LNG_MASK GENMASK(27, 16) 2762306a36Sopenharmony_ci#define DLYB_CFGR_LNGF BIT(31) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DLYB_NB_DELAY 11 3062306a36Sopenharmony_ci#define DLYB_CFGR_SEL_MAX (DLYB_NB_DELAY + 1) 3162306a36Sopenharmony_ci#define DLYB_CFGR_UNIT_MAX 127 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define DLYB_LNG_TIMEOUT_US 1000 3462306a36Sopenharmony_ci#define SDMMC_VSWEND_TIMEOUT_US 10000 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define SYSCFG_DLYBSD_CR 0x0 3762306a36Sopenharmony_ci#define DLYBSD_CR_EN BIT(0) 3862306a36Sopenharmony_ci#define DLYBSD_CR_RXTAPSEL_MASK GENMASK(6, 1) 3962306a36Sopenharmony_ci#define DLYBSD_TAPSEL_NB 32 4062306a36Sopenharmony_ci#define DLYBSD_BYP_EN BIT(16) 4162306a36Sopenharmony_ci#define DLYBSD_BYP_CMD GENMASK(21, 17) 4262306a36Sopenharmony_ci#define DLYBSD_ANTIGLITCH_EN BIT(22) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SYSCFG_DLYBSD_SR 0x4 4562306a36Sopenharmony_ci#define DLYBSD_SR_LOCK BIT(0) 4662306a36Sopenharmony_ci#define DLYBSD_SR_RXTAPSEL_ACK BIT(1) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define DLYBSD_TIMEOUT_1S_IN_US 1000000 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct sdmmc_lli_desc { 5162306a36Sopenharmony_ci u32 idmalar; 5262306a36Sopenharmony_ci u32 idmabase; 5362306a36Sopenharmony_ci u32 idmasize; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct sdmmc_idma { 5762306a36Sopenharmony_ci dma_addr_t sg_dma; 5862306a36Sopenharmony_ci void *sg_cpu; 5962306a36Sopenharmony_ci dma_addr_t bounce_dma_addr; 6062306a36Sopenharmony_ci void *bounce_buf; 6162306a36Sopenharmony_ci bool use_bounce_buffer; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct sdmmc_dlyb; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct sdmmc_tuning_ops { 6762306a36Sopenharmony_ci int (*dlyb_enable)(struct sdmmc_dlyb *dlyb); 6862306a36Sopenharmony_ci void (*set_input_ck)(struct sdmmc_dlyb *dlyb); 6962306a36Sopenharmony_ci int (*tuning_prepare)(struct mmci_host *host); 7062306a36Sopenharmony_ci int (*set_cfg)(struct sdmmc_dlyb *dlyb, int unit __maybe_unused, 7162306a36Sopenharmony_ci int phase, bool sampler __maybe_unused); 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistruct sdmmc_dlyb { 7562306a36Sopenharmony_ci void __iomem *base; 7662306a36Sopenharmony_ci u32 unit; 7762306a36Sopenharmony_ci u32 max; 7862306a36Sopenharmony_ci struct sdmmc_tuning_ops *ops; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int sdmmc_idma_validate_data(struct mmci_host *host, 8262306a36Sopenharmony_ci struct mmc_data *data) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct sdmmc_idma *idma = host->dma_priv; 8562306a36Sopenharmony_ci struct device *dev = mmc_dev(host->mmc); 8662306a36Sopenharmony_ci struct scatterlist *sg; 8762306a36Sopenharmony_ci int i; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * idma has constraints on idmabase & idmasize for each element 9162306a36Sopenharmony_ci * excepted the last element which has no constraint on idmasize 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci idma->use_bounce_buffer = false; 9462306a36Sopenharmony_ci for_each_sg(data->sg, sg, data->sg_len - 1, i) { 9562306a36Sopenharmony_ci if (!IS_ALIGNED(sg->offset, sizeof(u32)) || 9662306a36Sopenharmony_ci !IS_ALIGNED(sg->length, 9762306a36Sopenharmony_ci host->variant->stm32_idmabsize_align)) { 9862306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 9962306a36Sopenharmony_ci "unaligned scatterlist: ofst:%x length:%d\n", 10062306a36Sopenharmony_ci data->sg->offset, data->sg->length); 10162306a36Sopenharmony_ci goto use_bounce_buffer; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (!IS_ALIGNED(sg->offset, sizeof(u32))) { 10662306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 10762306a36Sopenharmony_ci "unaligned last scatterlist: ofst:%x length:%d\n", 10862306a36Sopenharmony_ci data->sg->offset, data->sg->length); 10962306a36Sopenharmony_ci goto use_bounce_buffer; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciuse_bounce_buffer: 11562306a36Sopenharmony_ci if (!idma->bounce_buf) { 11662306a36Sopenharmony_ci idma->bounce_buf = dmam_alloc_coherent(dev, 11762306a36Sopenharmony_ci host->mmc->max_req_size, 11862306a36Sopenharmony_ci &idma->bounce_dma_addr, 11962306a36Sopenharmony_ci GFP_KERNEL); 12062306a36Sopenharmony_ci if (!idma->bounce_buf) { 12162306a36Sopenharmony_ci dev_err(dev, "Unable to map allocate DMA bounce buffer.\n"); 12262306a36Sopenharmony_ci return -ENOMEM; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci idma->use_bounce_buffer = true; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int _sdmmc_idma_prep_data(struct mmci_host *host, 13262306a36Sopenharmony_ci struct mmc_data *data) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct sdmmc_idma *idma = host->dma_priv; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (idma->use_bounce_buffer) { 13762306a36Sopenharmony_ci if (data->flags & MMC_DATA_WRITE) { 13862306a36Sopenharmony_ci unsigned int xfer_bytes = data->blksz * data->blocks; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci sg_copy_to_buffer(data->sg, data->sg_len, 14162306a36Sopenharmony_ci idma->bounce_buf, xfer_bytes); 14262306a36Sopenharmony_ci dma_wmb(); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } else { 14562306a36Sopenharmony_ci int n_elem; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci n_elem = dma_map_sg(mmc_dev(host->mmc), 14862306a36Sopenharmony_ci data->sg, 14962306a36Sopenharmony_ci data->sg_len, 15062306a36Sopenharmony_ci mmc_get_dma_dir(data)); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (!n_elem) { 15362306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); 15462306a36Sopenharmony_ci return -EINVAL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int sdmmc_idma_prep_data(struct mmci_host *host, 16162306a36Sopenharmony_ci struct mmc_data *data, bool next) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci /* Check if job is already prepared. */ 16462306a36Sopenharmony_ci if (!next && data->host_cookie == host->next_cookie) 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return _sdmmc_idma_prep_data(host, data); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void sdmmc_idma_unprep_data(struct mmci_host *host, 17162306a36Sopenharmony_ci struct mmc_data *data, int err) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct sdmmc_idma *idma = host->dma_priv; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (idma->use_bounce_buffer) { 17662306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 17762306a36Sopenharmony_ci unsigned int xfer_bytes = data->blksz * data->blocks; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci sg_copy_from_buffer(data->sg, data->sg_len, 18062306a36Sopenharmony_ci idma->bounce_buf, xfer_bytes); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci } else { 18362306a36Sopenharmony_ci dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 18462306a36Sopenharmony_ci mmc_get_dma_dir(data)); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int sdmmc_idma_setup(struct mmci_host *host) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct sdmmc_idma *idma; 19162306a36Sopenharmony_ci struct device *dev = mmc_dev(host->mmc); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci idma = devm_kzalloc(dev, sizeof(*idma), GFP_KERNEL); 19462306a36Sopenharmony_ci if (!idma) 19562306a36Sopenharmony_ci return -ENOMEM; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci host->dma_priv = idma; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (host->variant->dma_lli) { 20062306a36Sopenharmony_ci idma->sg_cpu = dmam_alloc_coherent(dev, SDMMC_LLI_BUF_LEN, 20162306a36Sopenharmony_ci &idma->sg_dma, GFP_KERNEL); 20262306a36Sopenharmony_ci if (!idma->sg_cpu) { 20362306a36Sopenharmony_ci dev_err(dev, "Failed to alloc IDMA descriptor\n"); 20462306a36Sopenharmony_ci return -ENOMEM; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci host->mmc->max_segs = SDMMC_LLI_BUF_LEN / 20762306a36Sopenharmony_ci sizeof(struct sdmmc_lli_desc); 20862306a36Sopenharmony_ci host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci host->mmc->max_req_size = SZ_1M; 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci host->mmc->max_segs = 1; 21362306a36Sopenharmony_ci host->mmc->max_seg_size = host->mmc->max_req_size; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return dma_set_max_seg_size(dev, host->mmc->max_seg_size); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct sdmmc_idma *idma = host->dma_priv; 22362306a36Sopenharmony_ci struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; 22462306a36Sopenharmony_ci struct mmc_data *data = host->data; 22562306a36Sopenharmony_ci struct scatterlist *sg; 22662306a36Sopenharmony_ci int i; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci host->dma_in_progress = true; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (!host->variant->dma_lli || data->sg_len == 1 || 23162306a36Sopenharmony_ci idma->use_bounce_buffer) { 23262306a36Sopenharmony_ci u32 dma_addr; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (idma->use_bounce_buffer) 23562306a36Sopenharmony_ci dma_addr = idma->bounce_dma_addr; 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci dma_addr = sg_dma_address(data->sg); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci writel_relaxed(dma_addr, 24062306a36Sopenharmony_ci host->base + MMCI_STM32_IDMABASE0R); 24162306a36Sopenharmony_ci writel_relaxed(MMCI_STM32_IDMAEN, 24262306a36Sopenharmony_ci host->base + MMCI_STM32_IDMACTRLR); 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci for_each_sg(data->sg, sg, data->sg_len, i) { 24762306a36Sopenharmony_ci desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc); 24862306a36Sopenharmony_ci desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS 24962306a36Sopenharmony_ci | MMCI_STM32_ABR; 25062306a36Sopenharmony_ci desc[i].idmabase = sg_dma_address(sg); 25162306a36Sopenharmony_ci desc[i].idmasize = sg_dma_len(sg); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* notice the end of link list */ 25562306a36Sopenharmony_ci desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dma_wmb(); 25862306a36Sopenharmony_ci writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR); 25962306a36Sopenharmony_ci writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR); 26062306a36Sopenharmony_ci writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R); 26162306a36Sopenharmony_ci writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER); 26262306a36Sopenharmony_ci writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN, 26362306a36Sopenharmony_ci host->base + MMCI_STM32_IDMACTRLR); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic void sdmmc_idma_error(struct mmci_host *host) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct mmc_data *data = host->data; 27162306a36Sopenharmony_ci struct sdmmc_idma *idma = host->dma_priv; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!dma_inprogress(host)) 27462306a36Sopenharmony_ci return; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); 27762306a36Sopenharmony_ci host->dma_in_progress = false; 27862306a36Sopenharmony_ci data->host_cookie = 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (!idma->use_bounce_buffer) 28162306a36Sopenharmony_ci dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 28262306a36Sopenharmony_ci mmc_get_dma_dir(data)); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci if (!dma_inprogress(host)) 28862306a36Sopenharmony_ci return; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); 29162306a36Sopenharmony_ci host->dma_in_progress = false; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!data->host_cookie) 29462306a36Sopenharmony_ci sdmmc_idma_unprep_data(host, data, 0); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci unsigned int clk = 0, ddr = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 || 30262306a36Sopenharmony_ci host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) 30362306a36Sopenharmony_ci ddr = MCI_STM32_CLK_DDR; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci * cclk = mclk / (2 * clkdiv) 30762306a36Sopenharmony_ci * clkdiv 0 => bypass 30862306a36Sopenharmony_ci * in ddr mode bypass is not possible 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci if (desired) { 31162306a36Sopenharmony_ci if (desired >= host->mclk && !ddr) { 31262306a36Sopenharmony_ci host->cclk = host->mclk; 31362306a36Sopenharmony_ci } else { 31462306a36Sopenharmony_ci clk = DIV_ROUND_UP(host->mclk, 2 * desired); 31562306a36Sopenharmony_ci if (clk > MCI_STM32_CLK_CLKDIV_MSK) 31662306a36Sopenharmony_ci clk = MCI_STM32_CLK_CLKDIV_MSK; 31762306a36Sopenharmony_ci host->cclk = host->mclk / (2 * clk); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * while power-on phase the clock can't be define to 0, 32262306a36Sopenharmony_ci * Only power-off and power-cyc deactivate the clock. 32362306a36Sopenharmony_ci * if desired clock is 0, set max divider 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci clk = MCI_STM32_CLK_CLKDIV_MSK; 32662306a36Sopenharmony_ci host->cclk = host->mclk / (2 * clk); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* Set actual clock for debug */ 33062306a36Sopenharmony_ci if (host->mmc->ios.power_mode == MMC_POWER_ON) 33162306a36Sopenharmony_ci host->mmc->actual_clock = host->cclk; 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci host->mmc->actual_clock = 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) 33662306a36Sopenharmony_ci clk |= MCI_STM32_CLK_WIDEBUS_4; 33762306a36Sopenharmony_ci if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) 33862306a36Sopenharmony_ci clk |= MCI_STM32_CLK_WIDEBUS_8; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci clk |= MCI_STM32_CLK_HWFCEN; 34162306a36Sopenharmony_ci clk |= host->clk_reg_add; 34262306a36Sopenharmony_ci clk |= ddr; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) 34562306a36Sopenharmony_ci clk |= MCI_STM32_CLK_BUSSPEED; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci mmci_write_clkreg(host, clk); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic void sdmmc_dlyb_mp15_input_ck(struct sdmmc_dlyb *dlyb) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci if (!dlyb || !dlyb->base) 35362306a36Sopenharmony_ci return; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Output clock = Input clock */ 35662306a36Sopenharmony_ci writel_relaxed(0, dlyb->base + DLYB_CR); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct mmc_ios ios = host->mmc->ios; 36262306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb = host->variant_priv; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* adds OF options */ 36562306a36Sopenharmony_ci pwr = host->pwr_reg_add; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (dlyb && dlyb->ops->set_input_ck) 36862306a36Sopenharmony_ci dlyb->ops->set_input_ck(dlyb); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (ios.power_mode == MMC_POWER_OFF) { 37162306a36Sopenharmony_ci /* Only a reset could power-off sdmmc */ 37262306a36Sopenharmony_ci reset_control_assert(host->rst); 37362306a36Sopenharmony_ci udelay(2); 37462306a36Sopenharmony_ci reset_control_deassert(host->rst); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * Set the SDMMC in Power-cycle state. 37862306a36Sopenharmony_ci * This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK 37962306a36Sopenharmony_ci * are driven low, to prevent the Card from being supplied 38062306a36Sopenharmony_ci * through the signal lines. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr); 38362306a36Sopenharmony_ci } else if (ios.power_mode == MMC_POWER_ON) { 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * After power-off (reset): the irq mask defined in probe 38662306a36Sopenharmony_ci * functionis lost 38762306a36Sopenharmony_ci * ault irq mask (probe) must be activated 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci writel(MCI_IRQENABLE | host->variant->start_err, 39062306a36Sopenharmony_ci host->base + MMCIMASK0); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* preserves voltage switch bits */ 39362306a36Sopenharmony_ci pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN | 39462306a36Sopenharmony_ci MCI_STM32_VSWITCH); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * After a power-cycle state, we must set the SDMMC in 39862306a36Sopenharmony_ci * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are 39962306a36Sopenharmony_ci * driven high. Then we can set the SDMMC to Power-on state 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci mmci_write_pwrreg(host, MCI_PWR_OFF | pwr); 40262306a36Sopenharmony_ci mdelay(1); 40362306a36Sopenharmony_ci mmci_write_pwrreg(host, MCI_PWR_ON | pwr); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci u32 datactrl; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci datactrl = mmci_dctrl_blksz(host); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (host->hw_revision >= 3) { 41462306a36Sopenharmony_ci u32 thr = 0; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 || 41762306a36Sopenharmony_ci host->mmc->ios.timing == MMC_TIMING_MMC_HS200) { 41862306a36Sopenharmony_ci thr = ffs(min_t(unsigned int, host->data->blksz, 41962306a36Sopenharmony_ci host->variant->fifosize)); 42062306a36Sopenharmony_ci thr = min_t(u32, thr, MMCI_STM32_THR_MASK); 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci writel_relaxed(thr, host->base + MMCI_STM32_FIFOTHRR); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (host->mmc->card && mmc_card_sdio(host->mmc->card) && 42762306a36Sopenharmony_ci host->data->blocks == 1) 42862306a36Sopenharmony_ci datactrl |= MCI_DPSM_STM32_MODE_SDIO; 42962306a36Sopenharmony_ci else if (host->data->stop && !host->mrq->sbc) 43062306a36Sopenharmony_ci datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP; 43162306a36Sopenharmony_ci else 43262306a36Sopenharmony_ci datactrl |= MCI_DPSM_STM32_MODE_BLOCK; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return datactrl; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic bool sdmmc_busy_complete(struct mmci_host *host, struct mmc_command *cmd, 43862306a36Sopenharmony_ci u32 status, u32 err_msk) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci void __iomem *base = host->base; 44162306a36Sopenharmony_ci u32 busy_d0, busy_d0end, mask, sdmmc_status; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci mask = readl_relaxed(base + MMCIMASK0); 44462306a36Sopenharmony_ci sdmmc_status = readl_relaxed(base + MMCISTATUS); 44562306a36Sopenharmony_ci busy_d0end = sdmmc_status & MCI_STM32_BUSYD0END; 44662306a36Sopenharmony_ci busy_d0 = sdmmc_status & MCI_STM32_BUSYD0; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* complete if there is an error or busy_d0end */ 44962306a36Sopenharmony_ci if ((status & err_msk) || busy_d0end) 45062306a36Sopenharmony_ci goto complete; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * On response the busy signaling is reflected in the BUSYD0 flag. 45462306a36Sopenharmony_ci * if busy_d0 is in-progress we must activate busyd0end interrupt 45562306a36Sopenharmony_ci * to wait this completion. Else this request has no busy step. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci if (busy_d0) { 45862306a36Sopenharmony_ci if (!host->busy_status) { 45962306a36Sopenharmony_ci writel_relaxed(mask | host->variant->busy_detect_mask, 46062306a36Sopenharmony_ci base + MMCIMASK0); 46162306a36Sopenharmony_ci host->busy_status = status & 46262306a36Sopenharmony_ci (MCI_CMDSENT | MCI_CMDRESPEND); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci return false; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cicomplete: 46862306a36Sopenharmony_ci if (host->busy_status) { 46962306a36Sopenharmony_ci writel_relaxed(mask & ~host->variant->busy_detect_mask, 47062306a36Sopenharmony_ci base + MMCIMASK0); 47162306a36Sopenharmony_ci host->busy_status = 0; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci writel_relaxed(host->variant->busy_detect_mask, base + MMCICLEAR); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return true; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int sdmmc_dlyb_mp15_enable(struct sdmmc_dlyb *dlyb) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int sdmmc_dlyb_mp15_set_cfg(struct sdmmc_dlyb *dlyb, 48762306a36Sopenharmony_ci int unit, int phase, bool sampler) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci u32 cfgr; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci writel_relaxed(DLYB_CR_SEN | DLYB_CR_DEN, dlyb->base + DLYB_CR); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) | 49462306a36Sopenharmony_ci FIELD_PREP(DLYB_CFGR_SEL_MASK, phase); 49562306a36Sopenharmony_ci writel_relaxed(cfgr, dlyb->base + DLYB_CFGR); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (!sampler) 49862306a36Sopenharmony_ci writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int sdmmc_dlyb_mp15_prepare(struct mmci_host *host) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb = host->variant_priv; 50662306a36Sopenharmony_ci u32 cfgr; 50762306a36Sopenharmony_ci int i, lng, ret; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { 51062306a36Sopenharmony_ci dlyb->ops->set_cfg(dlyb, i, DLYB_CFGR_SEL_MAX, true); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, 51362306a36Sopenharmony_ci (cfgr & DLYB_CFGR_LNGF), 51462306a36Sopenharmony_ci 1, DLYB_LNG_TIMEOUT_US); 51562306a36Sopenharmony_ci if (ret) { 51662306a36Sopenharmony_ci dev_warn(mmc_dev(host->mmc), 51762306a36Sopenharmony_ci "delay line cfg timeout unit:%d cfgr:%d\n", 51862306a36Sopenharmony_ci i, cfgr); 51962306a36Sopenharmony_ci continue; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr); 52362306a36Sopenharmony_ci if (lng < BIT(DLYB_NB_DELAY) && lng > 0) 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (i > DLYB_CFGR_UNIT_MAX) 52862306a36Sopenharmony_ci return -EINVAL; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci dlyb->unit = i; 53162306a36Sopenharmony_ci dlyb->max = __fls(lng); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int sdmmc_dlyb_mp25_enable(struct sdmmc_dlyb *dlyb) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci u32 cr, sr; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci cr = readl_relaxed(dlyb->base + SYSCFG_DLYBSD_CR); 54162306a36Sopenharmony_ci cr |= DLYBSD_CR_EN; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci writel_relaxed(cr, dlyb->base + SYSCFG_DLYBSD_CR); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return readl_relaxed_poll_timeout(dlyb->base + SYSCFG_DLYBSD_SR, 54662306a36Sopenharmony_ci sr, sr & DLYBSD_SR_LOCK, 1, 54762306a36Sopenharmony_ci DLYBSD_TIMEOUT_1S_IN_US); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic int sdmmc_dlyb_mp25_set_cfg(struct sdmmc_dlyb *dlyb, 55162306a36Sopenharmony_ci int unit __maybe_unused, int phase, 55262306a36Sopenharmony_ci bool sampler __maybe_unused) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci u32 cr, sr; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci cr = readl_relaxed(dlyb->base + SYSCFG_DLYBSD_CR); 55762306a36Sopenharmony_ci cr &= ~DLYBSD_CR_RXTAPSEL_MASK; 55862306a36Sopenharmony_ci cr |= FIELD_PREP(DLYBSD_CR_RXTAPSEL_MASK, phase); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci writel_relaxed(cr, dlyb->base + SYSCFG_DLYBSD_CR); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return readl_relaxed_poll_timeout(dlyb->base + SYSCFG_DLYBSD_SR, 56362306a36Sopenharmony_ci sr, sr & DLYBSD_SR_RXTAPSEL_ACK, 1, 56462306a36Sopenharmony_ci DLYBSD_TIMEOUT_1S_IN_US); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic int sdmmc_dlyb_mp25_prepare(struct mmci_host *host) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb = host->variant_priv; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci dlyb->max = DLYBSD_TAPSEL_NB; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return 0; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb = host->variant_priv; 57962306a36Sopenharmony_ci int cur_len = 0, max_len = 0, end_of_len = 0; 58062306a36Sopenharmony_ci int phase, ret; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci for (phase = 0; phase <= dlyb->max; phase++) { 58362306a36Sopenharmony_ci ret = dlyb->ops->set_cfg(dlyb, dlyb->unit, phase, false); 58462306a36Sopenharmony_ci if (ret) { 58562306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "tuning config failed\n"); 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (mmc_send_tuning(host->mmc, opcode, NULL)) { 59062306a36Sopenharmony_ci cur_len = 0; 59162306a36Sopenharmony_ci } else { 59262306a36Sopenharmony_ci cur_len++; 59362306a36Sopenharmony_ci if (cur_len > max_len) { 59462306a36Sopenharmony_ci max_len = cur_len; 59562306a36Sopenharmony_ci end_of_len = phase; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (!max_len) { 60162306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "no tuning point found\n"); 60262306a36Sopenharmony_ci return -EINVAL; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (dlyb->ops->set_input_ck) 60662306a36Sopenharmony_ci dlyb->ops->set_input_ck(dlyb); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci phase = end_of_len - max_len / 2; 60962306a36Sopenharmony_ci ret = dlyb->ops->set_cfg(dlyb, dlyb->unit, phase, false); 61062306a36Sopenharmony_ci if (ret) { 61162306a36Sopenharmony_ci dev_err(mmc_dev(host->mmc), "tuning reconfig failed\n"); 61262306a36Sopenharmony_ci return ret; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", 61662306a36Sopenharmony_ci dlyb->unit, dlyb->max, phase); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct mmci_host *host = mmc_priv(mmc); 62462306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb = host->variant_priv; 62562306a36Sopenharmony_ci u32 clk; 62662306a36Sopenharmony_ci int ret; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if ((host->mmc->ios.timing != MMC_TIMING_UHS_SDR104 && 62962306a36Sopenharmony_ci host->mmc->ios.timing != MMC_TIMING_MMC_HS200) || 63062306a36Sopenharmony_ci host->mmc->actual_clock <= 50000000) 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (!dlyb || !dlyb->base) 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = dlyb->ops->dlyb_enable(dlyb); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * SDMMC_FBCK is selected when an external Delay Block is needed 64262306a36Sopenharmony_ci * with SDR104 or HS200. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci clk = host->clk_reg; 64562306a36Sopenharmony_ci clk &= ~MCI_STM32_CLK_SEL_MSK; 64662306a36Sopenharmony_ci clk |= MCI_STM32_CLK_SELFBCK; 64762306a36Sopenharmony_ci mmci_write_clkreg(host, clk); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci ret = dlyb->ops->tuning_prepare(host); 65062306a36Sopenharmony_ci if (ret) 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return sdmmc_dlyb_phase_tuning(host, opcode); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic void sdmmc_pre_sig_volt_vswitch(struct mmci_host *host) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci /* clear the voltage switch completion flag */ 65962306a36Sopenharmony_ci writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR); 66062306a36Sopenharmony_ci /* enable Voltage switch procedure */ 66162306a36Sopenharmony_ci mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic int sdmmc_post_sig_volt_switch(struct mmci_host *host, 66562306a36Sopenharmony_ci struct mmc_ios *ios) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci unsigned long flags; 66862306a36Sopenharmony_ci u32 status; 66962306a36Sopenharmony_ci int ret = 0; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 67262306a36Sopenharmony_ci if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180 && 67362306a36Sopenharmony_ci host->pwr_reg & MCI_STM32_VSWITCHEN) { 67462306a36Sopenharmony_ci mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); 67562306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* wait voltage switch completion while 10ms */ 67862306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS, 67962306a36Sopenharmony_ci status, 68062306a36Sopenharmony_ci (status & MCI_STM32_VSWEND), 68162306a36Sopenharmony_ci 10, SDMMC_VSWEND_TIMEOUT_US); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, 68462306a36Sopenharmony_ci host->base + MMCICLEAR); 68562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 68662306a36Sopenharmony_ci mmci_write_pwrreg(host, host->pwr_reg & 68762306a36Sopenharmony_ci ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return ret; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic struct mmci_host_ops sdmmc_variant_ops = { 69562306a36Sopenharmony_ci .validate_data = sdmmc_idma_validate_data, 69662306a36Sopenharmony_ci .prep_data = sdmmc_idma_prep_data, 69762306a36Sopenharmony_ci .unprep_data = sdmmc_idma_unprep_data, 69862306a36Sopenharmony_ci .get_datactrl_cfg = sdmmc_get_dctrl_cfg, 69962306a36Sopenharmony_ci .dma_setup = sdmmc_idma_setup, 70062306a36Sopenharmony_ci .dma_start = sdmmc_idma_start, 70162306a36Sopenharmony_ci .dma_finalize = sdmmc_idma_finalize, 70262306a36Sopenharmony_ci .dma_error = sdmmc_idma_error, 70362306a36Sopenharmony_ci .set_clkreg = mmci_sdmmc_set_clkreg, 70462306a36Sopenharmony_ci .set_pwrreg = mmci_sdmmc_set_pwrreg, 70562306a36Sopenharmony_ci .busy_complete = sdmmc_busy_complete, 70662306a36Sopenharmony_ci .pre_sig_volt_switch = sdmmc_pre_sig_volt_vswitch, 70762306a36Sopenharmony_ci .post_sig_volt_switch = sdmmc_post_sig_volt_switch, 70862306a36Sopenharmony_ci}; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic struct sdmmc_tuning_ops dlyb_tuning_mp15_ops = { 71162306a36Sopenharmony_ci .dlyb_enable = sdmmc_dlyb_mp15_enable, 71262306a36Sopenharmony_ci .set_input_ck = sdmmc_dlyb_mp15_input_ck, 71362306a36Sopenharmony_ci .tuning_prepare = sdmmc_dlyb_mp15_prepare, 71462306a36Sopenharmony_ci .set_cfg = sdmmc_dlyb_mp15_set_cfg, 71562306a36Sopenharmony_ci}; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic struct sdmmc_tuning_ops dlyb_tuning_mp25_ops = { 71862306a36Sopenharmony_ci .dlyb_enable = sdmmc_dlyb_mp25_enable, 71962306a36Sopenharmony_ci .tuning_prepare = sdmmc_dlyb_mp25_prepare, 72062306a36Sopenharmony_ci .set_cfg = sdmmc_dlyb_mp25_set_cfg, 72162306a36Sopenharmony_ci}; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_civoid sdmmc_variant_init(struct mmci_host *host) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct device_node *np = host->mmc->parent->of_node; 72662306a36Sopenharmony_ci void __iomem *base_dlyb; 72762306a36Sopenharmony_ci struct sdmmc_dlyb *dlyb; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci host->ops = &sdmmc_variant_ops; 73062306a36Sopenharmony_ci host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); 73362306a36Sopenharmony_ci if (IS_ERR(base_dlyb)) 73462306a36Sopenharmony_ci return; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL); 73762306a36Sopenharmony_ci if (!dlyb) 73862306a36Sopenharmony_ci return; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci dlyb->base = base_dlyb; 74162306a36Sopenharmony_ci if (of_device_is_compatible(np, "st,stm32mp25-sdmmc2")) 74262306a36Sopenharmony_ci dlyb->ops = &dlyb_tuning_mp25_ops; 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci dlyb->ops = &dlyb_tuning_mp15_ops; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci host->variant_priv = dlyb; 74762306a36Sopenharmony_ci host->mmc_ops->execute_tuning = sdmmc_execute_tuning; 74862306a36Sopenharmony_ci} 749