146b723ddSLudovic Barre // SPDX-License-Identifier: GPL-2.0 246b723ddSLudovic Barre /* 346b723ddSLudovic Barre * Copyright (C) STMicroelectronics 2018 - All Rights Reserved 446b723ddSLudovic Barre * Author: Ludovic.barre@st.com for STMicroelectronics. 546b723ddSLudovic Barre */ 646b723ddSLudovic Barre #include <linux/delay.h> 746b723ddSLudovic Barre #include <linux/dma-mapping.h> 846b723ddSLudovic Barre #include <linux/mmc/host.h> 946b723ddSLudovic Barre #include <linux/mmc/card.h> 1046b723ddSLudovic Barre #include <linux/reset.h> 1146b723ddSLudovic Barre #include <linux/scatterlist.h> 1246b723ddSLudovic Barre #include "mmci.h" 1346b723ddSLudovic Barre 1446b723ddSLudovic Barre #define SDMMC_LLI_BUF_LEN PAGE_SIZE 1546b723ddSLudovic Barre #define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) 1646b723ddSLudovic Barre 1746b723ddSLudovic Barre struct sdmmc_lli_desc { 1846b723ddSLudovic Barre u32 idmalar; 1946b723ddSLudovic Barre u32 idmabase; 2046b723ddSLudovic Barre u32 idmasize; 2146b723ddSLudovic Barre }; 2246b723ddSLudovic Barre 2346b723ddSLudovic Barre struct sdmmc_priv { 2446b723ddSLudovic Barre dma_addr_t sg_dma; 2546b723ddSLudovic Barre void *sg_cpu; 2646b723ddSLudovic Barre }; 2746b723ddSLudovic Barre 2846b723ddSLudovic Barre int sdmmc_idma_validate_data(struct mmci_host *host, 2946b723ddSLudovic Barre struct mmc_data *data) 3046b723ddSLudovic Barre { 3146b723ddSLudovic Barre struct scatterlist *sg; 3246b723ddSLudovic Barre int i; 3346b723ddSLudovic Barre 3446b723ddSLudovic Barre /* 3546b723ddSLudovic Barre * idma has constraints on idmabase & idmasize for each element 3646b723ddSLudovic Barre * excepted the last element which has no constraint on idmasize 3746b723ddSLudovic Barre */ 3846b723ddSLudovic Barre for_each_sg(data->sg, sg, data->sg_len - 1, i) { 3946b723ddSLudovic Barre if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) || 4046b723ddSLudovic Barre !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) { 4146b723ddSLudovic Barre dev_err(mmc_dev(host->mmc), 4246b723ddSLudovic Barre "unaligned scatterlist: ofst:%x length:%d\n", 4346b723ddSLudovic Barre data->sg->offset, data->sg->length); 4446b723ddSLudovic Barre return -EINVAL; 4546b723ddSLudovic Barre } 4646b723ddSLudovic Barre } 4746b723ddSLudovic Barre 4846b723ddSLudovic Barre if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) { 4946b723ddSLudovic Barre dev_err(mmc_dev(host->mmc), 5046b723ddSLudovic Barre "unaligned last scatterlist: ofst:%x length:%d\n", 5146b723ddSLudovic Barre data->sg->offset, data->sg->length); 5246b723ddSLudovic Barre return -EINVAL; 5346b723ddSLudovic Barre } 5446b723ddSLudovic Barre 5546b723ddSLudovic Barre return 0; 5646b723ddSLudovic Barre } 5746b723ddSLudovic Barre 5846b723ddSLudovic Barre static int _sdmmc_idma_prep_data(struct mmci_host *host, 5946b723ddSLudovic Barre struct mmc_data *data) 6046b723ddSLudovic Barre { 6146b723ddSLudovic Barre int n_elem; 6246b723ddSLudovic Barre 6346b723ddSLudovic Barre n_elem = dma_map_sg(mmc_dev(host->mmc), 6446b723ddSLudovic Barre data->sg, 6546b723ddSLudovic Barre data->sg_len, 6646b723ddSLudovic Barre mmc_get_dma_dir(data)); 6746b723ddSLudovic Barre 6846b723ddSLudovic Barre if (!n_elem) { 6946b723ddSLudovic Barre dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n"); 7046b723ddSLudovic Barre return -EINVAL; 7146b723ddSLudovic Barre } 7246b723ddSLudovic Barre 7346b723ddSLudovic Barre return 0; 7446b723ddSLudovic Barre } 7546b723ddSLudovic Barre 7646b723ddSLudovic Barre static int sdmmc_idma_prep_data(struct mmci_host *host, 7746b723ddSLudovic Barre struct mmc_data *data, bool next) 7846b723ddSLudovic Barre { 7946b723ddSLudovic Barre /* Check if job is already prepared. */ 8046b723ddSLudovic Barre if (!next && data->host_cookie == host->next_cookie) 8146b723ddSLudovic Barre return 0; 8246b723ddSLudovic Barre 8346b723ddSLudovic Barre return _sdmmc_idma_prep_data(host, data); 8446b723ddSLudovic Barre } 8546b723ddSLudovic Barre 8646b723ddSLudovic Barre static void sdmmc_idma_unprep_data(struct mmci_host *host, 8746b723ddSLudovic Barre struct mmc_data *data, int err) 8846b723ddSLudovic Barre { 8946b723ddSLudovic Barre dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, 9046b723ddSLudovic Barre mmc_get_dma_dir(data)); 9146b723ddSLudovic Barre } 9246b723ddSLudovic Barre 9346b723ddSLudovic Barre static int sdmmc_idma_setup(struct mmci_host *host) 9446b723ddSLudovic Barre { 9546b723ddSLudovic Barre struct sdmmc_priv *idma; 9646b723ddSLudovic Barre 9746b723ddSLudovic Barre idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); 9846b723ddSLudovic Barre if (!idma) 9946b723ddSLudovic Barre return -ENOMEM; 10046b723ddSLudovic Barre 10146b723ddSLudovic Barre host->dma_priv = idma; 10246b723ddSLudovic Barre 10346b723ddSLudovic Barre if (host->variant->dma_lli) { 10446b723ddSLudovic Barre idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), 10546b723ddSLudovic Barre SDMMC_LLI_BUF_LEN, 10646b723ddSLudovic Barre &idma->sg_dma, GFP_KERNEL); 10746b723ddSLudovic Barre if (!idma->sg_cpu) { 10846b723ddSLudovic Barre dev_err(mmc_dev(host->mmc), 10946b723ddSLudovic Barre "Failed to alloc IDMA descriptor\n"); 11046b723ddSLudovic Barre return -ENOMEM; 11146b723ddSLudovic Barre } 11246b723ddSLudovic Barre host->mmc->max_segs = SDMMC_LLI_BUF_LEN / 11346b723ddSLudovic Barre sizeof(struct sdmmc_lli_desc); 11446b723ddSLudovic Barre host->mmc->max_seg_size = host->variant->stm32_idmabsize_mask; 11546b723ddSLudovic Barre } else { 11646b723ddSLudovic Barre host->mmc->max_segs = 1; 11746b723ddSLudovic Barre host->mmc->max_seg_size = host->mmc->max_req_size; 11846b723ddSLudovic Barre } 11946b723ddSLudovic Barre 12046b723ddSLudovic Barre return 0; 12146b723ddSLudovic Barre } 12246b723ddSLudovic Barre 12346b723ddSLudovic Barre static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) 12446b723ddSLudovic Barre 12546b723ddSLudovic Barre { 12646b723ddSLudovic Barre struct sdmmc_priv *idma = host->dma_priv; 12746b723ddSLudovic Barre struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; 12846b723ddSLudovic Barre struct mmc_data *data = host->data; 12946b723ddSLudovic Barre struct scatterlist *sg; 13046b723ddSLudovic Barre int i; 13146b723ddSLudovic Barre 13246b723ddSLudovic Barre if (!host->variant->dma_lli || data->sg_len == 1) { 13346b723ddSLudovic Barre writel_relaxed(sg_dma_address(data->sg), 13446b723ddSLudovic Barre host->base + MMCI_STM32_IDMABASE0R); 13546b723ddSLudovic Barre writel_relaxed(MMCI_STM32_IDMAEN, 13646b723ddSLudovic Barre host->base + MMCI_STM32_IDMACTRLR); 13746b723ddSLudovic Barre return 0; 13846b723ddSLudovic Barre } 13946b723ddSLudovic Barre 14046b723ddSLudovic Barre for_each_sg(data->sg, sg, data->sg_len, i) { 14146b723ddSLudovic Barre desc[i].idmalar = (i + 1) * sizeof(struct sdmmc_lli_desc); 14246b723ddSLudovic Barre desc[i].idmalar |= MMCI_STM32_ULA | MMCI_STM32_ULS 14346b723ddSLudovic Barre | MMCI_STM32_ABR; 14446b723ddSLudovic Barre desc[i].idmabase = sg_dma_address(sg); 14546b723ddSLudovic Barre desc[i].idmasize = sg_dma_len(sg); 14646b723ddSLudovic Barre } 14746b723ddSLudovic Barre 14846b723ddSLudovic Barre /* notice the end of link list */ 14946b723ddSLudovic Barre desc[data->sg_len - 1].idmalar &= ~MMCI_STM32_ULA; 15046b723ddSLudovic Barre 15146b723ddSLudovic Barre dma_wmb(); 15246b723ddSLudovic Barre writel_relaxed(idma->sg_dma, host->base + MMCI_STM32_IDMABAR); 15346b723ddSLudovic Barre writel_relaxed(desc[0].idmalar, host->base + MMCI_STM32_IDMALAR); 15446b723ddSLudovic Barre writel_relaxed(desc[0].idmabase, host->base + MMCI_STM32_IDMABASE0R); 15546b723ddSLudovic Barre writel_relaxed(desc[0].idmasize, host->base + MMCI_STM32_IDMABSIZER); 15646b723ddSLudovic Barre writel_relaxed(MMCI_STM32_IDMAEN | MMCI_STM32_IDMALLIEN, 15746b723ddSLudovic Barre host->base + MMCI_STM32_IDMACTRLR); 15846b723ddSLudovic Barre 15946b723ddSLudovic Barre return 0; 16046b723ddSLudovic Barre } 16146b723ddSLudovic Barre 16246b723ddSLudovic Barre static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) 16346b723ddSLudovic Barre { 16446b723ddSLudovic Barre writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); 16546b723ddSLudovic Barre } 16646b723ddSLudovic Barre 16746b723ddSLudovic Barre static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) 16846b723ddSLudovic Barre { 16946b723ddSLudovic Barre unsigned int clk = 0, ddr = 0; 17046b723ddSLudovic Barre 17146b723ddSLudovic Barre if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52 || 17246b723ddSLudovic Barre host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) 17346b723ddSLudovic Barre ddr = MCI_STM32_CLK_DDR; 17446b723ddSLudovic Barre 17546b723ddSLudovic Barre /* 17646b723ddSLudovic Barre * cclk = mclk / (2 * clkdiv) 17746b723ddSLudovic Barre * clkdiv 0 => bypass 17846b723ddSLudovic Barre * in ddr mode bypass is not possible 17946b723ddSLudovic Barre */ 18046b723ddSLudovic Barre if (desired) { 18146b723ddSLudovic Barre if (desired >= host->mclk && !ddr) { 18246b723ddSLudovic Barre host->cclk = host->mclk; 18346b723ddSLudovic Barre } else { 18446b723ddSLudovic Barre clk = DIV_ROUND_UP(host->mclk, 2 * desired); 18546b723ddSLudovic Barre if (clk > MCI_STM32_CLK_CLKDIV_MSK) 18646b723ddSLudovic Barre clk = MCI_STM32_CLK_CLKDIV_MSK; 18746b723ddSLudovic Barre host->cclk = host->mclk / (2 * clk); 18846b723ddSLudovic Barre } 18946b723ddSLudovic Barre } else { 19046b723ddSLudovic Barre /* 19146b723ddSLudovic Barre * while power-on phase the clock can't be define to 0, 19246b723ddSLudovic Barre * Only power-off and power-cyc deactivate the clock. 19346b723ddSLudovic Barre * if desired clock is 0, set max divider 19446b723ddSLudovic Barre */ 19546b723ddSLudovic Barre clk = MCI_STM32_CLK_CLKDIV_MSK; 19646b723ddSLudovic Barre host->cclk = host->mclk / (2 * clk); 19746b723ddSLudovic Barre } 19846b723ddSLudovic Barre 19946b723ddSLudovic Barre /* Set actual clock for debug */ 20046b723ddSLudovic Barre if (host->mmc->ios.power_mode == MMC_POWER_ON) 20146b723ddSLudovic Barre host->mmc->actual_clock = host->cclk; 20246b723ddSLudovic Barre else 20346b723ddSLudovic Barre host->mmc->actual_clock = 0; 20446b723ddSLudovic Barre 20546b723ddSLudovic Barre if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) 20646b723ddSLudovic Barre clk |= MCI_STM32_CLK_WIDEBUS_4; 20746b723ddSLudovic Barre if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) 20846b723ddSLudovic Barre clk |= MCI_STM32_CLK_WIDEBUS_8; 20946b723ddSLudovic Barre 21046b723ddSLudovic Barre clk |= MCI_STM32_CLK_HWFCEN; 21146b723ddSLudovic Barre clk |= host->clk_reg_add; 21246b723ddSLudovic Barre clk |= ddr; 21346b723ddSLudovic Barre 21446b723ddSLudovic Barre /* 21546b723ddSLudovic Barre * SDMMC_FBCK is selected when an external Delay Block is needed 21646b723ddSLudovic Barre * with SDR104. 21746b723ddSLudovic Barre */ 21846b723ddSLudovic Barre if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) { 21946b723ddSLudovic Barre clk |= MCI_STM32_CLK_BUSSPEED; 22046b723ddSLudovic Barre if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) { 22146b723ddSLudovic Barre clk &= ~MCI_STM32_CLK_SEL_MSK; 22246b723ddSLudovic Barre clk |= MCI_STM32_CLK_SELFBCK; 22346b723ddSLudovic Barre } 22446b723ddSLudovic Barre } 22546b723ddSLudovic Barre 22646b723ddSLudovic Barre mmci_write_clkreg(host, clk); 22746b723ddSLudovic Barre } 22846b723ddSLudovic Barre 22946b723ddSLudovic Barre static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) 23046b723ddSLudovic Barre { 23146b723ddSLudovic Barre struct mmc_ios ios = host->mmc->ios; 23246b723ddSLudovic Barre 23346b723ddSLudovic Barre pwr = host->pwr_reg_add; 23446b723ddSLudovic Barre 23546b723ddSLudovic Barre if (ios.power_mode == MMC_POWER_OFF) { 23646b723ddSLudovic Barre /* Only a reset could power-off sdmmc */ 23746b723ddSLudovic Barre reset_control_assert(host->rst); 23846b723ddSLudovic Barre udelay(2); 23946b723ddSLudovic Barre reset_control_deassert(host->rst); 24046b723ddSLudovic Barre 24146b723ddSLudovic Barre /* 24246b723ddSLudovic Barre * Set the SDMMC in Power-cycle state. 24346b723ddSLudovic Barre * This will make that the SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK 24446b723ddSLudovic Barre * are driven low, to prevent the Card from being supplied 24546b723ddSLudovic Barre * through the signal lines. 24646b723ddSLudovic Barre */ 24746b723ddSLudovic Barre mmci_write_pwrreg(host, MCI_STM32_PWR_CYC | pwr); 24846b723ddSLudovic Barre } else if (ios.power_mode == MMC_POWER_ON) { 24946b723ddSLudovic Barre /* 25046b723ddSLudovic Barre * After power-off (reset): the irq mask defined in probe 25146b723ddSLudovic Barre * functionis lost 25246b723ddSLudovic Barre * ault irq mask (probe) must be activated 25346b723ddSLudovic Barre */ 25446b723ddSLudovic Barre writel(MCI_IRQENABLE | host->variant->start_err, 25546b723ddSLudovic Barre host->base + MMCIMASK0); 25646b723ddSLudovic Barre 25746b723ddSLudovic Barre /* 25846b723ddSLudovic Barre * After a power-cycle state, we must set the SDMMC in 25946b723ddSLudovic Barre * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are 26046b723ddSLudovic Barre * driven high. Then we can set the SDMMC to Power-on state 26146b723ddSLudovic Barre */ 26246b723ddSLudovic Barre mmci_write_pwrreg(host, MCI_PWR_OFF | pwr); 26346b723ddSLudovic Barre mdelay(1); 26446b723ddSLudovic Barre mmci_write_pwrreg(host, MCI_PWR_ON | pwr); 26546b723ddSLudovic Barre } 26646b723ddSLudovic Barre } 26746b723ddSLudovic Barre 2688372f9d0SLudovic Barre static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) 2698372f9d0SLudovic Barre { 2708372f9d0SLudovic Barre u32 datactrl; 2718372f9d0SLudovic Barre 2728372f9d0SLudovic Barre datactrl = mmci_dctrl_blksz(host); 2738372f9d0SLudovic Barre 2748372f9d0SLudovic Barre if (host->mmc->card && mmc_card_sdio(host->mmc->card) && 2758372f9d0SLudovic Barre host->data->blocks == 1) 2768372f9d0SLudovic Barre datactrl |= MCI_DPSM_STM32_MODE_SDIO; 2778372f9d0SLudovic Barre else if (host->data->stop && !host->mrq->sbc) 2788372f9d0SLudovic Barre datactrl |= MCI_DPSM_STM32_MODE_BLOCK_STOP; 2798372f9d0SLudovic Barre else 2808372f9d0SLudovic Barre datactrl |= MCI_DPSM_STM32_MODE_BLOCK; 2818372f9d0SLudovic Barre 2828372f9d0SLudovic Barre return datactrl; 2838372f9d0SLudovic Barre } 2848372f9d0SLudovic Barre 28546b723ddSLudovic Barre static struct mmci_host_ops sdmmc_variant_ops = { 28646b723ddSLudovic Barre .validate_data = sdmmc_idma_validate_data, 28746b723ddSLudovic Barre .prep_data = sdmmc_idma_prep_data, 28846b723ddSLudovic Barre .unprep_data = sdmmc_idma_unprep_data, 2898372f9d0SLudovic Barre .get_datactrl_cfg = sdmmc_get_dctrl_cfg, 29046b723ddSLudovic Barre .dma_setup = sdmmc_idma_setup, 29146b723ddSLudovic Barre .dma_start = sdmmc_idma_start, 29246b723ddSLudovic Barre .dma_finalize = sdmmc_idma_finalize, 29346b723ddSLudovic Barre .set_clkreg = mmci_sdmmc_set_clkreg, 29446b723ddSLudovic Barre .set_pwrreg = mmci_sdmmc_set_pwrreg, 29546b723ddSLudovic Barre }; 29646b723ddSLudovic Barre 29746b723ddSLudovic Barre void sdmmc_variant_init(struct mmci_host *host) 29846b723ddSLudovic Barre { 29946b723ddSLudovic Barre host->ops = &sdmmc_variant_ops; 30046b723ddSLudovic Barre } 301