18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Freescale eSDHC ColdFire family controller driver, platform bus. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2020 Timesys Corporation 68c2ecf20Sopenharmony_ci * Author: Angelo Dureghello <angelo.dureghello@timesys.it> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_data/mmc-esdhc-mcf.h> 128c2ecf20Sopenharmony_ci#include <linux/mmc/mmc.h> 138c2ecf20Sopenharmony_ci#include "sdhci-pltfm.h" 148c2ecf20Sopenharmony_ci#include "sdhci-esdhc.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define ESDHC_PROCTL_D3CD 0x08 178c2ecf20Sopenharmony_ci#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f 188c2ecf20Sopenharmony_ci#define ESDHC_DEFAULT_HOST_CONTROL 0x28 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * Freescale eSDHC has DMA ERR flag at bit 28, not as std spec says, bit 25. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#define ESDHC_INT_VENDOR_SPEC_DMA_ERR BIT(28) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct pltfm_mcf_data { 268c2ecf20Sopenharmony_ci struct clk *clk_ipg; 278c2ecf20Sopenharmony_ci struct clk *clk_ahb; 288c2ecf20Sopenharmony_ci struct clk *clk_per; 298c2ecf20Sopenharmony_ci int aside; 308c2ecf20Sopenharmony_ci int current_bus_width; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic inline void esdhc_mcf_buffer_swap32(u32 *buf, int len) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci int i; 368c2ecf20Sopenharmony_ci u32 temp; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci len = (len + 3) >> 2; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 418c2ecf20Sopenharmony_ci temp = swab32(*buf); 428c2ecf20Sopenharmony_ci *buf++ = temp; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic inline void esdhc_clrset_be(struct sdhci_host *host, 478c2ecf20Sopenharmony_ci u32 mask, u32 val, int reg) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci void __iomem *base = host->ioaddr + (reg & ~3); 508c2ecf20Sopenharmony_ci u8 shift = (reg & 3) << 3; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci mask <<= shift; 538c2ecf20Sopenharmony_ci val <<= shift; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (reg == SDHCI_HOST_CONTROL) 568c2ecf20Sopenharmony_ci val |= ESDHC_PROCTL_D3CD; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci writel((readl(base) & ~mask) | val, base); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Note: mcf is big-endian, single bytes need to be accessed at big endian 638c2ecf20Sopenharmony_ci * offsets. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic void esdhc_mcf_writeb_be(struct sdhci_host *host, u8 val, int reg) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci void __iomem *base = host->ioaddr + (reg & ~3); 688c2ecf20Sopenharmony_ci u8 shift = (reg & 3) << 3; 698c2ecf20Sopenharmony_ci u32 mask = ~(0xff << shift); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (reg == SDHCI_HOST_CONTROL) { 728c2ecf20Sopenharmony_ci u32 host_ctrl = ESDHC_DEFAULT_HOST_CONTROL; 738c2ecf20Sopenharmony_ci u8 dma_bits = (val & SDHCI_CTRL_DMA_MASK) >> 3; 748c2ecf20Sopenharmony_ci u8 tmp = readb(host->ioaddr + SDHCI_HOST_CONTROL + 1); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci tmp &= ~0x03; 778c2ecf20Sopenharmony_ci tmp |= dma_bits; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * Recomposition needed, restore always endianness and 818c2ecf20Sopenharmony_ci * keep D3CD and AI, just setting bus width. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci host_ctrl |= val; 848c2ecf20Sopenharmony_ci host_ctrl |= (dma_bits << 8); 858c2ecf20Sopenharmony_ci writel(host_ctrl, host->ioaddr + SDHCI_HOST_CONTROL); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci writel((readl(base) & mask) | (val << shift), base); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void esdhc_mcf_writew_be(struct sdhci_host *host, u16 val, int reg) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 968c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); 978c2ecf20Sopenharmony_ci void __iomem *base = host->ioaddr + (reg & ~3); 988c2ecf20Sopenharmony_ci u8 shift = (reg & 3) << 3; 998c2ecf20Sopenharmony_ci u32 mask = ~(0xffff << shift); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci switch (reg) { 1028c2ecf20Sopenharmony_ci case SDHCI_TRANSFER_MODE: 1038c2ecf20Sopenharmony_ci mcf_data->aside = val; 1048c2ecf20Sopenharmony_ci return; 1058c2ecf20Sopenharmony_ci case SDHCI_COMMAND: 1068c2ecf20Sopenharmony_ci if (host->cmd->opcode == MMC_STOP_TRANSMISSION) 1078c2ecf20Sopenharmony_ci val |= SDHCI_CMD_ABORTCMD; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * As for the fsl driver, 1118c2ecf20Sopenharmony_ci * we have to set the mode in a single write here. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci writel(val << 16 | mcf_data->aside, 1148c2ecf20Sopenharmony_ci host->ioaddr + SDHCI_TRANSFER_MODE); 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci writel((readl(base) & mask) | (val << shift), base); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void esdhc_mcf_writel_be(struct sdhci_host *host, u32 val, int reg) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci writel(val, host->ioaddr + reg); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic u8 esdhc_mcf_readb_be(struct sdhci_host *host, int reg) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (reg == SDHCI_HOST_CONTROL) { 1298c2ecf20Sopenharmony_ci u8 __iomem *base = host->ioaddr + (reg & ~3); 1308c2ecf20Sopenharmony_ci u16 val = readw(base + 2); 1318c2ecf20Sopenharmony_ci u8 dma_bits = (val >> 5) & SDHCI_CTRL_DMA_MASK; 1328c2ecf20Sopenharmony_ci u8 host_ctrl = val & 0xff; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci host_ctrl &= ~SDHCI_CTRL_DMA_MASK; 1358c2ecf20Sopenharmony_ci host_ctrl |= dma_bits; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return host_ctrl; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return readb(host->ioaddr + (reg ^ 0x3)); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic u16 esdhc_mcf_readw_be(struct sdhci_host *host, int reg) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * For SDHCI_HOST_VERSION, sdhci specs defines 0xFE, 1478c2ecf20Sopenharmony_ci * a wrong offset for us, we are at 0xFC. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ci if (reg == SDHCI_HOST_VERSION) 1508c2ecf20Sopenharmony_ci reg -= 2; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return readw(host->ioaddr + (reg ^ 0x2)); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic u32 esdhc_mcf_readl_be(struct sdhci_host *host, int reg) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci u32 val; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci val = readl(host->ioaddr + reg); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * RM (25.3.9) sd pin clock must never exceed 25Mhz. 1638c2ecf20Sopenharmony_ci * So forcing legacy mode at 25Mhz. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci if (unlikely(reg == SDHCI_CAPABILITIES)) 1668c2ecf20Sopenharmony_ci val &= ~SDHCI_CAN_DO_HISPD; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (unlikely(reg == SDHCI_INT_STATUS)) { 1698c2ecf20Sopenharmony_ci if (val & ESDHC_INT_VENDOR_SPEC_DMA_ERR) { 1708c2ecf20Sopenharmony_ci val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR; 1718c2ecf20Sopenharmony_ci val |= SDHCI_INT_ADMA_ERROR; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return val; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic unsigned int esdhc_mcf_get_max_timeout_count(struct sdhci_host *host) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return 1 << 27; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic void esdhc_mcf_set_timeout(struct sdhci_host *host, 1848c2ecf20Sopenharmony_ci struct mmc_command *cmd) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci /* Use maximum timeout counter */ 1878c2ecf20Sopenharmony_ci esdhc_clrset_be(host, ESDHC_SYS_CTRL_DTOCV_MASK, 0xE, 1888c2ecf20Sopenharmony_ci SDHCI_TIMEOUT_CONTROL); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void esdhc_mcf_reset(struct sdhci_host *host, u8 mask) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 1948c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci sdhci_reset(host, mask); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, 1998c2ecf20Sopenharmony_ci mcf_data->current_bus_width, SDHCI_HOST_CONTROL); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); 2028c2ecf20Sopenharmony_ci sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic unsigned int esdhc_mcf_pltfm_get_max_clock(struct sdhci_host *host) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return pltfm_host->clock; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic unsigned int esdhc_mcf_pltfm_get_min_clock(struct sdhci_host *host) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return pltfm_host->clock / 256 / 16; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic void esdhc_mcf_pltfm_set_clock(struct sdhci_host *host, 2208c2ecf20Sopenharmony_ci unsigned int clock) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2238c2ecf20Sopenharmony_ci unsigned long *pll_dr = (unsigned long *)MCF_PLL_DR; 2248c2ecf20Sopenharmony_ci u32 fvco, fsys, fesdhc, temp; 2258c2ecf20Sopenharmony_ci const int sdclkfs[] = {2, 4, 8, 16, 32, 64, 128, 256}; 2268c2ecf20Sopenharmony_ci int delta, old_delta = clock; 2278c2ecf20Sopenharmony_ci int i, q, ri, rq; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (clock == 0) { 2308c2ecf20Sopenharmony_ci host->mmc->actual_clock = 0; 2318c2ecf20Sopenharmony_ci return; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* 2358c2ecf20Sopenharmony_ci * ColdFire eSDHC clock.s 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * pll -+-> / outdiv1 --> fsys 2388c2ecf20Sopenharmony_ci * +-> / outdiv3 --> eSDHC clock ---> / SDCCLKFS / DVS 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * mcf5441x datasheet says: 2418c2ecf20Sopenharmony_ci * (8.1.2) eSDHC should be 40 MHz max 2428c2ecf20Sopenharmony_ci * (25.3.9) eSDHC input is, as example, 96 Mhz ... 2438c2ecf20Sopenharmony_ci * (25.3.9) sd pin clock must never exceed 25Mhz 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * fvco = fsys * outdvi1 + 1 2468c2ecf20Sopenharmony_ci * fshdc = fvco / outdiv3 + 1 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci temp = readl(pll_dr); 2498c2ecf20Sopenharmony_ci fsys = pltfm_host->clock; 2508c2ecf20Sopenharmony_ci fvco = fsys * ((temp & 0x1f) + 1); 2518c2ecf20Sopenharmony_ci fesdhc = fvco / (((temp >> 10) & 0x1f) + 1); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (i = 0; i < 8; ++i) { 2548c2ecf20Sopenharmony_ci int result = fesdhc / sdclkfs[i]; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (q = 1; q < 17; ++q) { 2578c2ecf20Sopenharmony_ci int finale = result / q; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci delta = abs(clock - finale); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (delta < old_delta) { 2628c2ecf20Sopenharmony_ci old_delta = delta; 2638c2ecf20Sopenharmony_ci ri = i; 2648c2ecf20Sopenharmony_ci rq = q; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* 2708c2ecf20Sopenharmony_ci * Apply divisors and re-enable all the clocks 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci temp = ((sdclkfs[ri] >> 1) << 8) | ((rq - 1) << 4) | 2738c2ecf20Sopenharmony_ci (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN); 2748c2ecf20Sopenharmony_ci esdhc_clrset_be(host, 0x0000fff7, temp, SDHCI_CLOCK_CONTROL); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci host->mmc->actual_clock = clock; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci mdelay(1); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic void esdhc_mcf_pltfm_set_bus_width(struct sdhci_host *host, int width) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2848c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci switch (width) { 2878c2ecf20Sopenharmony_ci case MMC_BUS_WIDTH_4: 2888c2ecf20Sopenharmony_ci mcf_data->current_bus_width = ESDHC_CTRL_4BITBUS; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci default: 2918c2ecf20Sopenharmony_ci mcf_data->current_bus_width = 0; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci esdhc_clrset_be(host, ESDHC_CTRL_BUSWIDTH_MASK, 2968c2ecf20Sopenharmony_ci mcf_data->current_bus_width, SDHCI_HOST_CONTROL); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void esdhc_mcf_request_done(struct sdhci_host *host, 3008c2ecf20Sopenharmony_ci struct mmc_request *mrq) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct scatterlist *sg; 3038c2ecf20Sopenharmony_ci u32 *buffer; 3048c2ecf20Sopenharmony_ci int i; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!mrq->data || !mrq->data->bytes_xfered) 3078c2ecf20Sopenharmony_ci goto exit_done; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (mmc_get_dma_dir(mrq->data) != DMA_FROM_DEVICE) 3108c2ecf20Sopenharmony_ci goto exit_done; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * On mcf5441x there is no hw sdma option/flag to select the dma 3148c2ecf20Sopenharmony_ci * transfer endiannes. A swap after the transfer is needed. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i) { 3178c2ecf20Sopenharmony_ci buffer = (u32 *)sg_virt(sg); 3188c2ecf20Sopenharmony_ci esdhc_mcf_buffer_swap32(buffer, sg->length); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciexit_done: 3228c2ecf20Sopenharmony_ci mmc_request_done(host->mmc, mrq); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host, 3268c2ecf20Sopenharmony_ci struct mmc_data *data, 3278c2ecf20Sopenharmony_ci unsigned int length) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci sg_copy_to_buffer(data->sg, data->sg_len, 3308c2ecf20Sopenharmony_ci host->bounce_buffer, length); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci esdhc_mcf_buffer_swap32((u32 *)host->bounce_buffer, 3338c2ecf20Sopenharmony_ci data->blksz * data->blocks); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic struct sdhci_ops sdhci_esdhc_ops = { 3378c2ecf20Sopenharmony_ci .reset = esdhc_mcf_reset, 3388c2ecf20Sopenharmony_ci .set_clock = esdhc_mcf_pltfm_set_clock, 3398c2ecf20Sopenharmony_ci .get_max_clock = esdhc_mcf_pltfm_get_max_clock, 3408c2ecf20Sopenharmony_ci .get_min_clock = esdhc_mcf_pltfm_get_min_clock, 3418c2ecf20Sopenharmony_ci .set_bus_width = esdhc_mcf_pltfm_set_bus_width, 3428c2ecf20Sopenharmony_ci .get_max_timeout_count = esdhc_mcf_get_max_timeout_count, 3438c2ecf20Sopenharmony_ci .set_timeout = esdhc_mcf_set_timeout, 3448c2ecf20Sopenharmony_ci .write_b = esdhc_mcf_writeb_be, 3458c2ecf20Sopenharmony_ci .write_w = esdhc_mcf_writew_be, 3468c2ecf20Sopenharmony_ci .write_l = esdhc_mcf_writel_be, 3478c2ecf20Sopenharmony_ci .read_b = esdhc_mcf_readb_be, 3488c2ecf20Sopenharmony_ci .read_w = esdhc_mcf_readw_be, 3498c2ecf20Sopenharmony_ci .read_l = esdhc_mcf_readl_be, 3508c2ecf20Sopenharmony_ci .copy_to_bounce_buffer = esdhc_mcf_copy_to_bounce_buffer, 3518c2ecf20Sopenharmony_ci .request_done = esdhc_mcf_request_done, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_esdhc_mcf_pdata = { 3558c2ecf20Sopenharmony_ci .ops = &sdhci_esdhc_ops, 3568c2ecf20Sopenharmony_ci .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_FORCE_DMA, 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Mandatory quirk, 3598c2ecf20Sopenharmony_ci * controller does not support cmd23, 3608c2ecf20Sopenharmony_ci * without, on > 8G cards cmd23 is used, and 3618c2ecf20Sopenharmony_ci * driver times out. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci SDHCI_QUIRK2_HOST_NO_CMD23, 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int esdhc_mcf_plat_init(struct sdhci_host *host, 3678c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct mcf_esdhc_platform_data *plat_data; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (!host->mmc->parent->platform_data) { 3728c2ecf20Sopenharmony_ci dev_err(mmc_dev(host->mmc), "no platform data!\n"); 3738c2ecf20Sopenharmony_ci return -EINVAL; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci plat_data = (struct mcf_esdhc_platform_data *) 3778c2ecf20Sopenharmony_ci host->mmc->parent->platform_data; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Card_detect */ 3808c2ecf20Sopenharmony_ci switch (plat_data->cd_type) { 3818c2ecf20Sopenharmony_ci default: 3828c2ecf20Sopenharmony_ci case ESDHC_CD_CONTROLLER: 3838c2ecf20Sopenharmony_ci /* We have a working card_detect back */ 3848c2ecf20Sopenharmony_ci host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case ESDHC_CD_PERMANENT: 3878c2ecf20Sopenharmony_ci host->mmc->caps |= MMC_CAP_NONREMOVABLE; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case ESDHC_CD_NONE: 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci switch (plat_data->max_bus_width) { 3948c2ecf20Sopenharmony_ci case 4: 3958c2ecf20Sopenharmony_ci host->mmc->caps |= MMC_CAP_4_BIT_DATA; 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci case 1: 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int sdhci_esdhc_mcf_probe(struct platform_device *pdev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct sdhci_host *host; 4098c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host; 4108c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data; 4118c2ecf20Sopenharmony_ci int err; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci host = sdhci_pltfm_init(pdev, &sdhci_esdhc_mcf_pdata, 4148c2ecf20Sopenharmony_ci sizeof(*mcf_data)); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (IS_ERR(host)) 4178c2ecf20Sopenharmony_ci return PTR_ERR(host); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pltfm_host = sdhci_priv(host); 4208c2ecf20Sopenharmony_ci mcf_data = sdhci_pltfm_priv(pltfm_host); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci host->sdma_boundary = 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci host->flags |= SDHCI_AUTO_CMD12; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci mcf_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 4278c2ecf20Sopenharmony_ci if (IS_ERR(mcf_data->clk_ipg)) { 4288c2ecf20Sopenharmony_ci err = PTR_ERR(mcf_data->clk_ipg); 4298c2ecf20Sopenharmony_ci goto err_exit; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mcf_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 4338c2ecf20Sopenharmony_ci if (IS_ERR(mcf_data->clk_ahb)) { 4348c2ecf20Sopenharmony_ci err = PTR_ERR(mcf_data->clk_ahb); 4358c2ecf20Sopenharmony_ci goto err_exit; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci mcf_data->clk_per = devm_clk_get(&pdev->dev, "per"); 4398c2ecf20Sopenharmony_ci if (IS_ERR(mcf_data->clk_per)) { 4408c2ecf20Sopenharmony_ci err = PTR_ERR(mcf_data->clk_per); 4418c2ecf20Sopenharmony_ci goto err_exit; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci pltfm_host->clk = mcf_data->clk_per; 4458c2ecf20Sopenharmony_ci pltfm_host->clock = clk_get_rate(pltfm_host->clk); 4468c2ecf20Sopenharmony_ci err = clk_prepare_enable(mcf_data->clk_per); 4478c2ecf20Sopenharmony_ci if (err) 4488c2ecf20Sopenharmony_ci goto err_exit; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci err = clk_prepare_enable(mcf_data->clk_ipg); 4518c2ecf20Sopenharmony_ci if (err) 4528c2ecf20Sopenharmony_ci goto unprep_per; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci err = clk_prepare_enable(mcf_data->clk_ahb); 4558c2ecf20Sopenharmony_ci if (err) 4568c2ecf20Sopenharmony_ci goto unprep_ipg; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci err = esdhc_mcf_plat_init(host, mcf_data); 4598c2ecf20Sopenharmony_ci if (err) 4608c2ecf20Sopenharmony_ci goto unprep_ahb; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci err = sdhci_setup_host(host); 4638c2ecf20Sopenharmony_ci if (err) 4648c2ecf20Sopenharmony_ci goto unprep_ahb; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!host->bounce_buffer) { 4678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "bounce buffer not allocated"); 4688c2ecf20Sopenharmony_ci err = -ENOMEM; 4698c2ecf20Sopenharmony_ci goto cleanup; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci err = __sdhci_add_host(host); 4738c2ecf20Sopenharmony_ci if (err) 4748c2ecf20Sopenharmony_ci goto cleanup; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cicleanup: 4798c2ecf20Sopenharmony_ci sdhci_cleanup_host(host); 4808c2ecf20Sopenharmony_ciunprep_ahb: 4818c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_ahb); 4828c2ecf20Sopenharmony_ciunprep_ipg: 4838c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_ipg); 4848c2ecf20Sopenharmony_ciunprep_per: 4858c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_per); 4868c2ecf20Sopenharmony_cierr_exit: 4878c2ecf20Sopenharmony_ci sdhci_pltfm_free(pdev); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return err; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int sdhci_esdhc_mcf_remove(struct platform_device *pdev) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct sdhci_host *host = platform_get_drvdata(pdev); 4958c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 4968c2ecf20Sopenharmony_ci struct pltfm_mcf_data *mcf_data = sdhci_pltfm_priv(pltfm_host); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci sdhci_remove_host(host, 0); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_ipg); 5018c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_ahb); 5028c2ecf20Sopenharmony_ci clk_disable_unprepare(mcf_data->clk_per); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci sdhci_pltfm_free(pdev); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic struct platform_driver sdhci_esdhc_mcf_driver = { 5108c2ecf20Sopenharmony_ci .driver = { 5118c2ecf20Sopenharmony_ci .name = "sdhci-esdhc-mcf", 5128c2ecf20Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 5138c2ecf20Sopenharmony_ci }, 5148c2ecf20Sopenharmony_ci .probe = sdhci_esdhc_mcf_probe, 5158c2ecf20Sopenharmony_ci .remove = sdhci_esdhc_mcf_remove, 5168c2ecf20Sopenharmony_ci}; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cimodule_platform_driver(sdhci_esdhc_mcf_driver); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SDHCI driver for Freescale ColdFire eSDHC"); 5218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Angelo Dureghello <angelo.dureghello@timesys.com>"); 5228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 523