18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Arasan Secure Digital Host Controller Interface. 48c2ecf20Sopenharmony_ci * Copyright (C) 2011 - 2012 Michal Simek <monstr@monstr.eu> 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Wind River Systems, Inc. 68c2ecf20Sopenharmony_ci * Copyright (C) 2013 Pengutronix e.K. 78c2ecf20Sopenharmony_ci * Copyright (C) 2013 Xilinx Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on sdhci-of-esdhc.c 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2007 Freescale Semiconductor, Inc. 128c2ecf20Sopenharmony_ci * Copyright (c) 2009 MontaVista Software, Inc. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Authors: Xiaobo Xie <X.Xie@freescale.com> 158c2ecf20Sopenharmony_ci * Anton Vorontsov <avorontsov@ru.mvista.com> 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 198c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/of_device.h> 228c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 238c2ecf20Sopenharmony_ci#include <linux/regmap.h> 248c2ecf20Sopenharmony_ci#include <linux/of.h> 258c2ecf20Sopenharmony_ci#include <linux/firmware/xlnx-zynqmp.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "cqhci.h" 288c2ecf20Sopenharmony_ci#include "sdhci-cqhci.h" 298c2ecf20Sopenharmony_ci#include "sdhci-pltfm.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_VENDOR_REGISTER 0x78 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 348c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_ITAPDLY_SEL_MASK 0xFF 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_OTAPDLY_REGISTER 0xF0FC 378c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_OTAPDLY_SEL_MASK 0x3F 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200 408c2ecf20Sopenharmony_ci#define VENDOR_ENHANCED_STROBE BIT(0) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define PHY_CLK_TOO_SLOW_HZ 400000 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define SDHCI_ITAPDLY_CHGWIN 0x200 458c2ecf20Sopenharmony_ci#define SDHCI_ITAPDLY_ENABLE 0x100 468c2ecf20Sopenharmony_ci#define SDHCI_OTAPDLY_ENABLE 0x40 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Default settings for ZynqMP Clock Phases */ 498c2ecf20Sopenharmony_ci#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} 508c2ecf20Sopenharmony_ci#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define VERSAL_ICLK_PHASE {0, 132, 132, 0, 132, 0, 0, 162, 90, 0, 0} 538c2ecf20Sopenharmony_ci#define VERSAL_OCLK_PHASE {0, 60, 48, 0, 48, 72, 90, 36, 60, 90, 0} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * On some SoCs the syscon area has a feature where the upper 16-bits of 578c2ecf20Sopenharmony_ci * each 32-bit register act as a write mask for the lower 16-bits. This allows 588c2ecf20Sopenharmony_ci * atomic updates of the register without locking. This macro is used on SoCs 598c2ecf20Sopenharmony_ci * that have that feature. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci#define HIWORD_UPDATE(val, mask, shift) \ 628c2ecf20Sopenharmony_ci ((val) << (shift) | (mask) << ((shift) + 16)) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * struct sdhci_arasan_soc_ctl_field - Field used in sdhci_arasan_soc_ctl_map 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * @reg: Offset within the syscon of the register containing this field 688c2ecf20Sopenharmony_ci * @width: Number of bits for this field 698c2ecf20Sopenharmony_ci * @shift: Bit offset within @reg of this field (or -1 if not avail) 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistruct sdhci_arasan_soc_ctl_field { 728c2ecf20Sopenharmony_ci u32 reg; 738c2ecf20Sopenharmony_ci u16 width; 748c2ecf20Sopenharmony_ci s16 shift; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/** 788c2ecf20Sopenharmony_ci * struct sdhci_arasan_soc_ctl_map - Map in syscon to corecfg registers 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * @baseclkfreq: Where to find corecfg_baseclkfreq 818c2ecf20Sopenharmony_ci * @clockmultiplier: Where to find corecfg_clockmultiplier 828c2ecf20Sopenharmony_ci * @support64b: Where to find SUPPORT64B bit 838c2ecf20Sopenharmony_ci * @hiword_update: If true, use HIWORD_UPDATE to access the syscon 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * It's up to the licensee of the Arsan IP block to make these available 868c2ecf20Sopenharmony_ci * somewhere if needed. Presumably these will be scattered somewhere that's 878c2ecf20Sopenharmony_ci * accessible via the syscon API. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistruct sdhci_arasan_soc_ctl_map { 908c2ecf20Sopenharmony_ci struct sdhci_arasan_soc_ctl_field baseclkfreq; 918c2ecf20Sopenharmony_ci struct sdhci_arasan_soc_ctl_field clockmultiplier; 928c2ecf20Sopenharmony_ci struct sdhci_arasan_soc_ctl_field support64b; 938c2ecf20Sopenharmony_ci bool hiword_update; 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * struct sdhci_arasan_clk_ops - Clock Operations for Arasan SD controller 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * @sdcardclk_ops: The output clock related operations 1008c2ecf20Sopenharmony_ci * @sampleclk_ops: The sample clock related operations 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistruct sdhci_arasan_clk_ops { 1038c2ecf20Sopenharmony_ci const struct clk_ops *sdcardclk_ops; 1048c2ecf20Sopenharmony_ci const struct clk_ops *sampleclk_ops; 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * struct sdhci_arasan_clk_data - Arasan Controller Clock Data. 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * @sdcardclk_hw: Struct for the clock we might provide to a PHY. 1118c2ecf20Sopenharmony_ci * @sdcardclk: Pointer to normal 'struct clock' for sdcardclk_hw. 1128c2ecf20Sopenharmony_ci * @sampleclk_hw: Struct for the clock we might provide to a PHY. 1138c2ecf20Sopenharmony_ci * @sampleclk: Pointer to normal 'struct clock' for sampleclk_hw. 1148c2ecf20Sopenharmony_ci * @clk_phase_in: Array of Input Clock Phase Delays for all speed modes 1158c2ecf20Sopenharmony_ci * @clk_phase_out: Array of Output Clock Phase Delays for all speed modes 1168c2ecf20Sopenharmony_ci * @set_clk_delays: Function pointer for setting Clock Delays 1178c2ecf20Sopenharmony_ci * @clk_of_data: Platform specific runtime clock data storage pointer 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistruct sdhci_arasan_clk_data { 1208c2ecf20Sopenharmony_ci struct clk_hw sdcardclk_hw; 1218c2ecf20Sopenharmony_ci struct clk *sdcardclk; 1228c2ecf20Sopenharmony_ci struct clk_hw sampleclk_hw; 1238c2ecf20Sopenharmony_ci struct clk *sampleclk; 1248c2ecf20Sopenharmony_ci int clk_phase_in[MMC_TIMING_MMC_HS400 + 1]; 1258c2ecf20Sopenharmony_ci int clk_phase_out[MMC_TIMING_MMC_HS400 + 1]; 1268c2ecf20Sopenharmony_ci void (*set_clk_delays)(struct sdhci_host *host); 1278c2ecf20Sopenharmony_ci void *clk_of_data; 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/** 1318c2ecf20Sopenharmony_ci * struct sdhci_arasan_data - Arasan Controller Data 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * @host: Pointer to the main SDHCI host structure. 1348c2ecf20Sopenharmony_ci * @clk_ahb: Pointer to the AHB clock 1358c2ecf20Sopenharmony_ci * @phy: Pointer to the generic phy 1368c2ecf20Sopenharmony_ci * @is_phy_on: True if the PHY is on; false if not. 1378c2ecf20Sopenharmony_ci * @has_cqe: True if controller has command queuing engine. 1388c2ecf20Sopenharmony_ci * @clk_data: Struct for the Arasan Controller Clock Data. 1398c2ecf20Sopenharmony_ci * @clk_ops: Struct for the Arasan Controller Clock Operations. 1408c2ecf20Sopenharmony_ci * @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers. 1418c2ecf20Sopenharmony_ci * @soc_ctl_map: Map to get offsets into soc_ctl registers. 1428c2ecf20Sopenharmony_ci * @quirks: Arasan deviations from spec. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cistruct sdhci_arasan_data { 1458c2ecf20Sopenharmony_ci struct sdhci_host *host; 1468c2ecf20Sopenharmony_ci struct clk *clk_ahb; 1478c2ecf20Sopenharmony_ci struct phy *phy; 1488c2ecf20Sopenharmony_ci bool is_phy_on; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci bool has_cqe; 1518c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data clk_data; 1528c2ecf20Sopenharmony_ci const struct sdhci_arasan_clk_ops *clk_ops; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci struct regmap *soc_ctl_base; 1558c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 1568c2ecf20Sopenharmony_ci unsigned int quirks; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Controller does not have CD wired and will not function normally without */ 1598c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0) 1608c2ecf20Sopenharmony_ci/* Controller immediately reports SDHCI_CLOCK_INT_STABLE after enabling the 1618c2ecf20Sopenharmony_ci * internal clock even when the clock isn't stable */ 1628c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE BIT(1) 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * Some of the Arasan variations might not have timing requirements 1658c2ecf20Sopenharmony_ci * met at 25MHz for Default Speed mode, those controllers work at 1668c2ecf20Sopenharmony_ci * 19MHz instead 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci#define SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN BIT(2) 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct sdhci_arasan_of_data { 1728c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_map *soc_ctl_map; 1738c2ecf20Sopenharmony_ci const struct sdhci_pltfm_data *pdata; 1748c2ecf20Sopenharmony_ci const struct sdhci_arasan_clk_ops *clk_ops; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map rk3399_soc_ctl_map = { 1788c2ecf20Sopenharmony_ci .baseclkfreq = { .reg = 0xf000, .width = 8, .shift = 8 }, 1798c2ecf20Sopenharmony_ci .clockmultiplier = { .reg = 0xf02c, .width = 8, .shift = 0}, 1808c2ecf20Sopenharmony_ci .hiword_update = true, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_lgm_emmc_soc_ctl_map = { 1848c2ecf20Sopenharmony_ci .baseclkfreq = { .reg = 0xa0, .width = 8, .shift = 2 }, 1858c2ecf20Sopenharmony_ci .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 1868c2ecf20Sopenharmony_ci .hiword_update = false, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_lgm_sdxc_soc_ctl_map = { 1908c2ecf20Sopenharmony_ci .baseclkfreq = { .reg = 0x80, .width = 8, .shift = 2 }, 1918c2ecf20Sopenharmony_ci .clockmultiplier = { .reg = 0, .width = -1, .shift = -1 }, 1928c2ecf20Sopenharmony_ci .hiword_update = false, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_soc_ctl_map intel_keembay_soc_ctl_map = { 1968c2ecf20Sopenharmony_ci .baseclkfreq = { .reg = 0x0, .width = 8, .shift = 14 }, 1978c2ecf20Sopenharmony_ci .clockmultiplier = { .reg = 0x4, .width = 8, .shift = 14 }, 1988c2ecf20Sopenharmony_ci .support64b = { .reg = 0x4, .width = 1, .shift = 24 }, 1998c2ecf20Sopenharmony_ci .hiword_update = false, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/** 2038c2ecf20Sopenharmony_ci * sdhci_arasan_syscon_write - Write to a field in soc_ctl registers 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * @host: The sdhci_host 2068c2ecf20Sopenharmony_ci * @fld: The field to write to 2078c2ecf20Sopenharmony_ci * @val: The value to write 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * This function allows writing to fields in sdhci_arasan_soc_ctl_map. 2108c2ecf20Sopenharmony_ci * Note that if a field is specified as not available (shift < 0) then 2118c2ecf20Sopenharmony_ci * this function will silently return an error code. It will be noisy 2128c2ecf20Sopenharmony_ci * and print errors for any other (unexpected) errors. 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistatic int sdhci_arasan_syscon_write(struct sdhci_host *host, 2178c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_field *fld, 2188c2ecf20Sopenharmony_ci u32 val) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2218c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 2228c2ecf20Sopenharmony_ci struct regmap *soc_ctl_base = sdhci_arasan->soc_ctl_base; 2238c2ecf20Sopenharmony_ci u32 reg = fld->reg; 2248c2ecf20Sopenharmony_ci u16 width = fld->width; 2258c2ecf20Sopenharmony_ci s16 shift = fld->shift; 2268c2ecf20Sopenharmony_ci int ret; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Silently return errors for shift < 0 so caller doesn't have 2308c2ecf20Sopenharmony_ci * to check for fields which are optional. For fields that 2318c2ecf20Sopenharmony_ci * are required then caller needs to do something special 2328c2ecf20Sopenharmony_ci * anyway. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (shift < 0) 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (sdhci_arasan->soc_ctl_map->hiword_update) 2388c2ecf20Sopenharmony_ci ret = regmap_write(soc_ctl_base, reg, 2398c2ecf20Sopenharmony_ci HIWORD_UPDATE(val, GENMASK(width, 0), 2408c2ecf20Sopenharmony_ci shift)); 2418c2ecf20Sopenharmony_ci else 2428c2ecf20Sopenharmony_ci ret = regmap_update_bits(soc_ctl_base, reg, 2438c2ecf20Sopenharmony_ci GENMASK(shift + width, shift), 2448c2ecf20Sopenharmony_ci val << shift); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* Yell about (unexpected) regmap errors */ 2478c2ecf20Sopenharmony_ci if (ret) 2488c2ecf20Sopenharmony_ci pr_warn("%s: Regmap write fail: %d\n", 2498c2ecf20Sopenharmony_ci mmc_hostname(host->mmc), ret); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ret; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 2578c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 2588c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 2598c2ecf20Sopenharmony_ci bool ctrl_phy = false; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!IS_ERR(sdhci_arasan->phy)) { 2628c2ecf20Sopenharmony_ci if (!sdhci_arasan->is_phy_on && clock <= PHY_CLK_TOO_SLOW_HZ) { 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * If PHY off, set clock to max speed and power PHY on. 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Although PHY docs apparently suggest power cycling 2678c2ecf20Sopenharmony_ci * when changing the clock the PHY doesn't like to be 2688c2ecf20Sopenharmony_ci * powered on while at low speeds like those used in ID 2698c2ecf20Sopenharmony_ci * mode. Even worse is powering the PHY on while the 2708c2ecf20Sopenharmony_ci * clock is off. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * To workaround the PHY limitations, the best we can 2738c2ecf20Sopenharmony_ci * do is to power it on at a faster speed and then slam 2748c2ecf20Sopenharmony_ci * through low speeds without power cycling. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci sdhci_set_clock(host, host->max_clk); 2778c2ecf20Sopenharmony_ci if (phy_power_on(sdhci_arasan->phy)) { 2788c2ecf20Sopenharmony_ci pr_err("%s: Cannot power on phy.\n", 2798c2ecf20Sopenharmony_ci mmc_hostname(host->mmc)); 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci sdhci_arasan->is_phy_on = true; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * We'll now fall through to the below case with 2878c2ecf20Sopenharmony_ci * ctrl_phy = false (so we won't turn off/on). The 2888c2ecf20Sopenharmony_ci * sdhci_set_clock() will set the real clock. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci } else if (clock > PHY_CLK_TOO_SLOW_HZ) { 2918c2ecf20Sopenharmony_ci /* 2928c2ecf20Sopenharmony_ci * At higher clock speeds the PHY is fine being power 2938c2ecf20Sopenharmony_ci * cycled and docs say you _should_ power cycle when 2948c2ecf20Sopenharmony_ci * changing clock speeds. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci ctrl_phy = true; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (ctrl_phy && sdhci_arasan->is_phy_on) { 3018c2ecf20Sopenharmony_ci phy_power_off(sdhci_arasan->phy); 3028c2ecf20Sopenharmony_ci sdhci_arasan->is_phy_on = false; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN) { 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Some of the Arasan variations might not have timing 3088c2ecf20Sopenharmony_ci * requirements met at 25MHz for Default Speed mode, 3098c2ecf20Sopenharmony_ci * those controllers work at 19MHz instead. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci if (clock == DEFAULT_SPEED_MAX_DTR) 3128c2ecf20Sopenharmony_ci clock = (DEFAULT_SPEED_MAX_DTR * 19) / 25; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Set the Input and Output Clock Phase Delays */ 3168c2ecf20Sopenharmony_ci if (clk_data->set_clk_delays) 3178c2ecf20Sopenharmony_ci clk_data->set_clk_delays(host); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci sdhci_set_clock(host, clock); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE) 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * Some controllers immediately report SDHCI_CLOCK_INT_STABLE 3248c2ecf20Sopenharmony_ci * after enabling the clock even though the clock is not 3258c2ecf20Sopenharmony_ci * stable. Trying to use a clock without waiting here results 3268c2ecf20Sopenharmony_ci * in EILSEQ while detecting some older/slower cards. The 3278c2ecf20Sopenharmony_ci * chosen delay is the maximum delay from sdhci_set_clock. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci msleep(20); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (ctrl_phy) { 3328c2ecf20Sopenharmony_ci if (phy_power_on(sdhci_arasan->phy)) { 3338c2ecf20Sopenharmony_ci pr_err("%s: Cannot power on phy.\n", 3348c2ecf20Sopenharmony_ci mmc_hostname(host->mmc)); 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci sdhci_arasan->is_phy_on = true; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc, 3438c2ecf20Sopenharmony_ci struct mmc_ios *ios) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci u32 vendor; 3468c2ecf20Sopenharmony_ci struct sdhci_host *host = mmc_priv(mmc); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER); 3498c2ecf20Sopenharmony_ci if (ios->enhanced_strobe) 3508c2ecf20Sopenharmony_ci vendor |= VENDOR_ENHANCED_STROBE; 3518c2ecf20Sopenharmony_ci else 3528c2ecf20Sopenharmony_ci vendor &= ~VENDOR_ENHANCED_STROBE; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic void sdhci_arasan_reset(struct sdhci_host *host, u8 mask) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u8 ctrl; 3608c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 3618c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci sdhci_and_cqhci_reset(host, mask); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) { 3668c2ecf20Sopenharmony_ci ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); 3678c2ecf20Sopenharmony_ci ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN; 3688c2ecf20Sopenharmony_ci sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic int sdhci_arasan_voltage_switch(struct mmc_host *mmc, 3738c2ecf20Sopenharmony_ci struct mmc_ios *ios) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci switch (ios->signal_voltage) { 3768c2ecf20Sopenharmony_ci case MMC_SIGNAL_VOLTAGE_180: 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Plese don't switch to 1V8 as arasan,5.1 doesn't 3798c2ecf20Sopenharmony_ci * actually refer to this setting to indicate the 3808c2ecf20Sopenharmony_ci * signal voltage and the state machine will be broken 3818c2ecf20Sopenharmony_ci * actually if we force to enable 1V8. That's something 3828c2ecf20Sopenharmony_ci * like broken quirk but we could work around here. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci case MMC_SIGNAL_VOLTAGE_330: 3868c2ecf20Sopenharmony_ci case MMC_SIGNAL_VOLTAGE_120: 3878c2ecf20Sopenharmony_ci /* We don't support 3V3 and 1V2 */ 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic const struct sdhci_ops sdhci_arasan_ops = { 3958c2ecf20Sopenharmony_ci .set_clock = sdhci_arasan_set_clock, 3968c2ecf20Sopenharmony_ci .get_max_clock = sdhci_pltfm_clk_get_max_clock, 3978c2ecf20Sopenharmony_ci .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 3988c2ecf20Sopenharmony_ci .set_bus_width = sdhci_set_bus_width, 3998c2ecf20Sopenharmony_ci .reset = sdhci_arasan_reset, 4008c2ecf20Sopenharmony_ci .set_uhs_signaling = sdhci_set_uhs_signaling, 4018c2ecf20Sopenharmony_ci .set_power = sdhci_set_power_and_bus_voltage, 4028c2ecf20Sopenharmony_ci}; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci int cmd_error = 0; 4078c2ecf20Sopenharmony_ci int data_error = 0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) 4108c2ecf20Sopenharmony_ci return intmask; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci cqhci_irq(host->mmc, intmask, cmd_error, data_error); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void sdhci_arasan_dumpregs(struct mmc_host *mmc) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci sdhci_dumpregs(mmc_priv(mmc)); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void sdhci_arasan_cqe_enable(struct mmc_host *mmc) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct sdhci_host *host = mmc_priv(mmc); 4258c2ecf20Sopenharmony_ci u32 reg; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 4288c2ecf20Sopenharmony_ci while (reg & SDHCI_DATA_AVAILABLE) { 4298c2ecf20Sopenharmony_ci sdhci_readl(host, SDHCI_BUFFER); 4308c2ecf20Sopenharmony_ci reg = sdhci_readl(host, SDHCI_PRESENT_STATE); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci sdhci_cqe_enable(mmc); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic const struct cqhci_host_ops sdhci_arasan_cqhci_ops = { 4378c2ecf20Sopenharmony_ci .enable = sdhci_arasan_cqe_enable, 4388c2ecf20Sopenharmony_ci .disable = sdhci_cqe_disable, 4398c2ecf20Sopenharmony_ci .dumpregs = sdhci_arasan_dumpregs, 4408c2ecf20Sopenharmony_ci}; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic const struct sdhci_ops sdhci_arasan_cqe_ops = { 4438c2ecf20Sopenharmony_ci .set_clock = sdhci_arasan_set_clock, 4448c2ecf20Sopenharmony_ci .get_max_clock = sdhci_pltfm_clk_get_max_clock, 4458c2ecf20Sopenharmony_ci .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 4468c2ecf20Sopenharmony_ci .set_bus_width = sdhci_set_bus_width, 4478c2ecf20Sopenharmony_ci .reset = sdhci_arasan_reset, 4488c2ecf20Sopenharmony_ci .set_uhs_signaling = sdhci_set_uhs_signaling, 4498c2ecf20Sopenharmony_ci .set_power = sdhci_set_power_and_bus_voltage, 4508c2ecf20Sopenharmony_ci .irq = sdhci_arasan_cqhci_irq, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_cqe_pdata = { 4548c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_cqe_ops, 4558c2ecf20Sopenharmony_ci .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 4568c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 4578c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4618c2ecf20Sopenharmony_ci/** 4628c2ecf20Sopenharmony_ci * sdhci_arasan_suspend - Suspend method for the driver 4638c2ecf20Sopenharmony_ci * @dev: Address of the device structure 4648c2ecf20Sopenharmony_ci * 4658c2ecf20Sopenharmony_ci * Put the device in a low power state. 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_cistatic int sdhci_arasan_suspend(struct device *dev) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct sdhci_host *host = dev_get_drvdata(dev); 4728c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 4738c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 4748c2ecf20Sopenharmony_ci int ret; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (host->tuning_mode != SDHCI_TUNING_MODE_3) 4778c2ecf20Sopenharmony_ci mmc_retune_needed(host->mmc); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (sdhci_arasan->has_cqe) { 4808c2ecf20Sopenharmony_ci ret = cqhci_suspend(host->mmc); 4818c2ecf20Sopenharmony_ci if (ret) 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci ret = sdhci_suspend_host(host); 4868c2ecf20Sopenharmony_ci if (ret) 4878c2ecf20Sopenharmony_ci return ret; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (!IS_ERR(sdhci_arasan->phy) && sdhci_arasan->is_phy_on) { 4908c2ecf20Sopenharmony_ci ret = phy_power_off(sdhci_arasan->phy); 4918c2ecf20Sopenharmony_ci if (ret) { 4928c2ecf20Sopenharmony_ci dev_err(dev, "Cannot power off phy.\n"); 4938c2ecf20Sopenharmony_ci if (sdhci_resume_host(host)) 4948c2ecf20Sopenharmony_ci dev_err(dev, "Cannot resume host.\n"); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci sdhci_arasan->is_phy_on = false; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci clk_disable(pltfm_host->clk); 5028c2ecf20Sopenharmony_ci clk_disable(sdhci_arasan->clk_ahb); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/** 5088c2ecf20Sopenharmony_ci * sdhci_arasan_resume - Resume method for the driver 5098c2ecf20Sopenharmony_ci * @dev: Address of the device structure 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * Resume operation after suspend 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistatic int sdhci_arasan_resume(struct device *dev) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct sdhci_host *host = dev_get_drvdata(dev); 5188c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 5198c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 5208c2ecf20Sopenharmony_ci int ret; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci ret = clk_enable(sdhci_arasan->clk_ahb); 5238c2ecf20Sopenharmony_ci if (ret) { 5248c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable AHB clock.\n"); 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = clk_enable(pltfm_host->clk); 5298c2ecf20Sopenharmony_ci if (ret) { 5308c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable SD clock.\n"); 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (!IS_ERR(sdhci_arasan->phy) && host->mmc->actual_clock) { 5358c2ecf20Sopenharmony_ci ret = phy_power_on(sdhci_arasan->phy); 5368c2ecf20Sopenharmony_ci if (ret) { 5378c2ecf20Sopenharmony_ci dev_err(dev, "Cannot power on phy.\n"); 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci sdhci_arasan->is_phy_on = true; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci ret = sdhci_resume_host(host); 5448c2ecf20Sopenharmony_ci if (ret) { 5458c2ecf20Sopenharmony_ci dev_err(dev, "Cannot resume host.\n"); 5468c2ecf20Sopenharmony_ci return ret; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (sdhci_arasan->has_cqe) 5508c2ecf20Sopenharmony_ci return cqhci_resume(host->mmc); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci#endif /* ! CONFIG_PM_SLEEP */ 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, 5578c2ecf20Sopenharmony_ci sdhci_arasan_resume); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 5638c2ecf20Sopenharmony_ci * @parent_rate: The parent rate (should be rate of clk_xin). 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * Return the current actual rate of the SD card clock. This can be used 5668c2ecf20Sopenharmony_ci * to communicate with out PHY. 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * Return: The card clock rate. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_cistatic unsigned long sdhci_arasan_sdcardclk_recalc_rate(struct clk_hw *hw, 5718c2ecf20Sopenharmony_ci unsigned long parent_rate) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 5748c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 5758c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 5768c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 5778c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return host->mmc->actual_clock; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic const struct clk_ops arasan_sdcardclk_ops = { 5838c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 5848c2ecf20Sopenharmony_ci}; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci/** 5878c2ecf20Sopenharmony_ci * sdhci_arasan_sampleclk_recalc_rate - Return the sampling clock rate 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 5908c2ecf20Sopenharmony_ci * @parent_rate: The parent rate (should be rate of clk_xin). 5918c2ecf20Sopenharmony_ci * 5928c2ecf20Sopenharmony_ci * Return the current actual rate of the sampling clock. This can be used 5938c2ecf20Sopenharmony_ci * to communicate with out PHY. 5948c2ecf20Sopenharmony_ci * 5958c2ecf20Sopenharmony_ci * Return: The sample clock rate. 5968c2ecf20Sopenharmony_ci */ 5978c2ecf20Sopenharmony_cistatic unsigned long sdhci_arasan_sampleclk_recalc_rate(struct clk_hw *hw, 5988c2ecf20Sopenharmony_ci unsigned long parent_rate) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 6018c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 6028c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 6038c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 6048c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci return host->mmc->actual_clock; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic const struct clk_ops arasan_sampleclk_ops = { 6108c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 6118c2ecf20Sopenharmony_ci}; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/** 6148c2ecf20Sopenharmony_ci * sdhci_zynqmp_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 6178c2ecf20Sopenharmony_ci * @degrees: The clock phase shift between 0 - 359. 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * Set the SD Output Clock Tap Delays for Output path 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_cistatic int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 6268c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 6278c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 6288c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 6298c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 6308c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 6318c2ecf20Sopenharmony_ci u32 node_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : NODE_SD_1; 6328c2ecf20Sopenharmony_ci u8 tap_delay, tap_max = 0; 6338c2ecf20Sopenharmony_ci int ret; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* This is applicable for SDHCI_SPEC_300 and above */ 6368c2ecf20Sopenharmony_ci if (host->version < SDHCI_SPEC_300) 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci switch (host->timing) { 6408c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS: 6418c2ecf20Sopenharmony_ci case MMC_TIMING_SD_HS: 6428c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR25: 6438c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_DDR50: 6448c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_DDR52: 6458c2ecf20Sopenharmony_ci /* For 50MHz clock, 30 Taps are available */ 6468c2ecf20Sopenharmony_ci tap_max = 30; 6478c2ecf20Sopenharmony_ci break; 6488c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR50: 6498c2ecf20Sopenharmony_ci /* For 100MHz clock, 15 Taps are available */ 6508c2ecf20Sopenharmony_ci tap_max = 15; 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR104: 6538c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS200: 6548c2ecf20Sopenharmony_ci /* For 200MHz clock, 8 Taps are available */ 6558c2ecf20Sopenharmony_ci tap_max = 8; 6568c2ecf20Sopenharmony_ci default: 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci tap_delay = (degrees * tap_max) / 360; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* Set the Clock Phase */ 6638c2ecf20Sopenharmony_ci ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_OUTPUT, tap_delay); 6648c2ecf20Sopenharmony_ci if (ret) 6658c2ecf20Sopenharmony_ci pr_err("Error setting Output Tap Delay\n"); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Release DLL Reset */ 6688c2ecf20Sopenharmony_ci zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_RELEASE); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return ret; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic const struct clk_ops zynqmp_sdcardclk_ops = { 6748c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 6758c2ecf20Sopenharmony_ci .set_phase = sdhci_zynqmp_sdcardclk_set_phase, 6768c2ecf20Sopenharmony_ci}; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/** 6798c2ecf20Sopenharmony_ci * sdhci_zynqmp_sampleclk_set_phase - Set the SD Input Clock Tap Delays 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 6828c2ecf20Sopenharmony_ci * @degrees: The clock phase shift between 0 - 359. 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * Set the SD Input Clock Tap Delays for Input path 6858c2ecf20Sopenharmony_ci * 6868c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_cistatic int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 6918c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 6928c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 6938c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 6948c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 6958c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 6968c2ecf20Sopenharmony_ci u32 node_id = !strcmp(clk_name, "clk_in_sd0") ? NODE_SD_0 : NODE_SD_1; 6978c2ecf20Sopenharmony_ci u8 tap_delay, tap_max = 0; 6988c2ecf20Sopenharmony_ci int ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* This is applicable for SDHCI_SPEC_300 and above */ 7018c2ecf20Sopenharmony_ci if (host->version < SDHCI_SPEC_300) 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* Assert DLL Reset */ 7058c2ecf20Sopenharmony_ci zynqmp_pm_sd_dll_reset(node_id, PM_DLL_RESET_ASSERT); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci switch (host->timing) { 7088c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS: 7098c2ecf20Sopenharmony_ci case MMC_TIMING_SD_HS: 7108c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR25: 7118c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_DDR50: 7128c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_DDR52: 7138c2ecf20Sopenharmony_ci /* For 50MHz clock, 120 Taps are available */ 7148c2ecf20Sopenharmony_ci tap_max = 120; 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR50: 7178c2ecf20Sopenharmony_ci /* For 100MHz clock, 60 Taps are available */ 7188c2ecf20Sopenharmony_ci tap_max = 60; 7198c2ecf20Sopenharmony_ci break; 7208c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR104: 7218c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS200: 7228c2ecf20Sopenharmony_ci /* For 200MHz clock, 30 Taps are available */ 7238c2ecf20Sopenharmony_ci tap_max = 30; 7248c2ecf20Sopenharmony_ci default: 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci tap_delay = (degrees * tap_max) / 360; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* Set the Clock Phase */ 7318c2ecf20Sopenharmony_ci ret = zynqmp_pm_set_sd_tapdelay(node_id, PM_TAPDELAY_INPUT, tap_delay); 7328c2ecf20Sopenharmony_ci if (ret) 7338c2ecf20Sopenharmony_ci pr_err("Error setting Input Tap Delay\n"); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic const struct clk_ops zynqmp_sampleclk_ops = { 7398c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 7408c2ecf20Sopenharmony_ci .set_phase = sdhci_zynqmp_sampleclk_set_phase, 7418c2ecf20Sopenharmony_ci}; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/** 7448c2ecf20Sopenharmony_ci * sdhci_versal_sdcardclk_set_phase - Set the SD Output Clock Tap Delays 7458c2ecf20Sopenharmony_ci * 7468c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 7478c2ecf20Sopenharmony_ci * @degrees: The clock phase shift between 0 - 359. 7488c2ecf20Sopenharmony_ci * 7498c2ecf20Sopenharmony_ci * Set the SD Output Clock Tap Delays for Output path 7508c2ecf20Sopenharmony_ci * 7518c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_cistatic int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 7568c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sdcardclk_hw); 7578c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 7588c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 7598c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 7608c2ecf20Sopenharmony_ci u8 tap_delay, tap_max = 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* This is applicable for SDHCI_SPEC_300 and above */ 7638c2ecf20Sopenharmony_ci if (host->version < SDHCI_SPEC_300) 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci switch (host->timing) { 7678c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS: 7688c2ecf20Sopenharmony_ci case MMC_TIMING_SD_HS: 7698c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR25: 7708c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_DDR50: 7718c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_DDR52: 7728c2ecf20Sopenharmony_ci /* For 50MHz clock, 30 Taps are available */ 7738c2ecf20Sopenharmony_ci tap_max = 30; 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR50: 7768c2ecf20Sopenharmony_ci /* For 100MHz clock, 15 Taps are available */ 7778c2ecf20Sopenharmony_ci tap_max = 15; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR104: 7808c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS200: 7818c2ecf20Sopenharmony_ci /* For 200MHz clock, 8 Taps are available */ 7828c2ecf20Sopenharmony_ci tap_max = 8; 7838c2ecf20Sopenharmony_ci default: 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci tap_delay = (degrees * tap_max) / 360; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* Set the Clock Phase */ 7908c2ecf20Sopenharmony_ci if (tap_delay) { 7918c2ecf20Sopenharmony_ci u32 regval; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci regval = sdhci_readl(host, SDHCI_ARASAN_OTAPDLY_REGISTER); 7948c2ecf20Sopenharmony_ci regval |= SDHCI_OTAPDLY_ENABLE; 7958c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 7968c2ecf20Sopenharmony_ci regval &= ~SDHCI_ARASAN_OTAPDLY_SEL_MASK; 7978c2ecf20Sopenharmony_ci regval |= tap_delay; 7988c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_OTAPDLY_REGISTER); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic const struct clk_ops versal_sdcardclk_ops = { 8058c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sdcardclk_recalc_rate, 8068c2ecf20Sopenharmony_ci .set_phase = sdhci_versal_sdcardclk_set_phase, 8078c2ecf20Sopenharmony_ci}; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/** 8108c2ecf20Sopenharmony_ci * sdhci_versal_sampleclk_set_phase - Set the SD Input Clock Tap Delays 8118c2ecf20Sopenharmony_ci * 8128c2ecf20Sopenharmony_ci * @hw: Pointer to the hardware clock structure. 8138c2ecf20Sopenharmony_ci * @degrees: The clock phase shift between 0 - 359. 8148c2ecf20Sopenharmony_ci * 8158c2ecf20Sopenharmony_ci * Set the SD Input Clock Tap Delays for Input path 8168c2ecf20Sopenharmony_ci * 8178c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 8188c2ecf20Sopenharmony_ci */ 8198c2ecf20Sopenharmony_cistatic int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = 8228c2ecf20Sopenharmony_ci container_of(hw, struct sdhci_arasan_clk_data, sampleclk_hw); 8238c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = 8248c2ecf20Sopenharmony_ci container_of(clk_data, struct sdhci_arasan_data, clk_data); 8258c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 8268c2ecf20Sopenharmony_ci u8 tap_delay, tap_max = 0; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* This is applicable for SDHCI_SPEC_300 and above */ 8298c2ecf20Sopenharmony_ci if (host->version < SDHCI_SPEC_300) 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci switch (host->timing) { 8338c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS: 8348c2ecf20Sopenharmony_ci case MMC_TIMING_SD_HS: 8358c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR25: 8368c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_DDR50: 8378c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_DDR52: 8388c2ecf20Sopenharmony_ci /* For 50MHz clock, 120 Taps are available */ 8398c2ecf20Sopenharmony_ci tap_max = 120; 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR50: 8428c2ecf20Sopenharmony_ci /* For 100MHz clock, 60 Taps are available */ 8438c2ecf20Sopenharmony_ci tap_max = 60; 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci case MMC_TIMING_UHS_SDR104: 8468c2ecf20Sopenharmony_ci case MMC_TIMING_MMC_HS200: 8478c2ecf20Sopenharmony_ci /* For 200MHz clock, 30 Taps are available */ 8488c2ecf20Sopenharmony_ci tap_max = 30; 8498c2ecf20Sopenharmony_ci default: 8508c2ecf20Sopenharmony_ci break; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci tap_delay = (degrees * tap_max) / 360; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* Set the Clock Phase */ 8568c2ecf20Sopenharmony_ci if (tap_delay) { 8578c2ecf20Sopenharmony_ci u32 regval; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci regval = sdhci_readl(host, SDHCI_ARASAN_ITAPDLY_REGISTER); 8608c2ecf20Sopenharmony_ci regval |= SDHCI_ITAPDLY_CHGWIN; 8618c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8628c2ecf20Sopenharmony_ci regval |= SDHCI_ITAPDLY_ENABLE; 8638c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8648c2ecf20Sopenharmony_ci regval &= ~SDHCI_ARASAN_ITAPDLY_SEL_MASK; 8658c2ecf20Sopenharmony_ci regval |= tap_delay; 8668c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8678c2ecf20Sopenharmony_ci regval &= ~SDHCI_ITAPDLY_CHGWIN; 8688c2ecf20Sopenharmony_ci sdhci_writel(host, regval, SDHCI_ARASAN_ITAPDLY_REGISTER); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic const struct clk_ops versal_sampleclk_ops = { 8758c2ecf20Sopenharmony_ci .recalc_rate = sdhci_arasan_sampleclk_recalc_rate, 8768c2ecf20Sopenharmony_ci .set_phase = sdhci_versal_sampleclk_set_phase, 8778c2ecf20Sopenharmony_ci}; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic void arasan_zynqmp_dll_reset(struct sdhci_host *host, u32 deviceid) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci u16 clk; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8848c2ecf20Sopenharmony_ci clk &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN); 8858c2ecf20Sopenharmony_ci sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Issue DLL Reset */ 8888c2ecf20Sopenharmony_ci zynqmp_pm_sd_dll_reset(deviceid, PM_DLL_RESET_PULSE); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci sdhci_enable_clk(host, clk); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int arasan_zynqmp_execute_tuning(struct mmc_host *mmc, u32 opcode) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct sdhci_host *host = mmc_priv(mmc); 8988c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 8998c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9008c2ecf20Sopenharmony_ci struct clk_hw *hw = &sdhci_arasan->clk_data.sdcardclk_hw; 9018c2ecf20Sopenharmony_ci const char *clk_name = clk_hw_get_name(hw); 9028c2ecf20Sopenharmony_ci u32 device_id = !strcmp(clk_name, "clk_out_sd0") ? NODE_SD_0 : 9038c2ecf20Sopenharmony_ci NODE_SD_1; 9048c2ecf20Sopenharmony_ci int err; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci arasan_zynqmp_dll_reset(host, device_id); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci err = sdhci_execute_tuning(mmc, opcode); 9098c2ecf20Sopenharmony_ci if (err) 9108c2ecf20Sopenharmony_ci return err; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci arasan_zynqmp_dll_reset(host, device_id); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci/** 9188c2ecf20Sopenharmony_ci * sdhci_arasan_update_clockmultiplier - Set corecfg_clockmultiplier 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * @host: The sdhci_host 9218c2ecf20Sopenharmony_ci * @value: The value to write 9228c2ecf20Sopenharmony_ci * 9238c2ecf20Sopenharmony_ci * The corecfg_clockmultiplier is supposed to contain clock multiplier 9248c2ecf20Sopenharmony_ci * value of programmable clock generator. 9258c2ecf20Sopenharmony_ci * 9268c2ecf20Sopenharmony_ci * NOTES: 9278c2ecf20Sopenharmony_ci * - Many existing devices don't seem to do this and work fine. To keep 9288c2ecf20Sopenharmony_ci * compatibility for old hardware where the device tree doesn't provide a 9298c2ecf20Sopenharmony_ci * register map, this function is a noop if a soc_ctl_map hasn't been provided 9308c2ecf20Sopenharmony_ci * for this platform. 9318c2ecf20Sopenharmony_ci * - The value of corecfg_clockmultiplier should sync with that of corresponding 9328c2ecf20Sopenharmony_ci * value reading from sdhci_capability_register. So this function is called 9338c2ecf20Sopenharmony_ci * once at probe time and never called again. 9348c2ecf20Sopenharmony_ci */ 9358c2ecf20Sopenharmony_cistatic void sdhci_arasan_update_clockmultiplier(struct sdhci_host *host, 9368c2ecf20Sopenharmony_ci u32 value) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9398c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9408c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 9418c2ecf20Sopenharmony_ci sdhci_arasan->soc_ctl_map; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Having a map is optional */ 9448c2ecf20Sopenharmony_ci if (!soc_ctl_map) 9458c2ecf20Sopenharmony_ci return; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* If we have a map, we expect to have a syscon */ 9488c2ecf20Sopenharmony_ci if (!sdhci_arasan->soc_ctl_base) { 9498c2ecf20Sopenharmony_ci pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 9508c2ecf20Sopenharmony_ci mmc_hostname(host->mmc)); 9518c2ecf20Sopenharmony_ci return; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci sdhci_arasan_syscon_write(host, &soc_ctl_map->clockmultiplier, value); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/** 9588c2ecf20Sopenharmony_ci * sdhci_arasan_update_baseclkfreq - Set corecfg_baseclkfreq 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * @host: The sdhci_host 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * The corecfg_baseclkfreq is supposed to contain the MHz of clk_xin. This 9638c2ecf20Sopenharmony_ci * function can be used to make that happen. 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * NOTES: 9668c2ecf20Sopenharmony_ci * - Many existing devices don't seem to do this and work fine. To keep 9678c2ecf20Sopenharmony_ci * compatibility for old hardware where the device tree doesn't provide a 9688c2ecf20Sopenharmony_ci * register map, this function is a noop if a soc_ctl_map hasn't been provided 9698c2ecf20Sopenharmony_ci * for this platform. 9708c2ecf20Sopenharmony_ci * - It's assumed that clk_xin is not dynamic and that we use the SDHCI divider 9718c2ecf20Sopenharmony_ci * to achieve lower clock rates. That means that this function is called once 9728c2ecf20Sopenharmony_ci * at probe time and never called again. 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_cistatic void sdhci_arasan_update_baseclkfreq(struct sdhci_host *host) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9778c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 9788c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 9798c2ecf20Sopenharmony_ci sdhci_arasan->soc_ctl_map; 9808c2ecf20Sopenharmony_ci u32 mhz = DIV_ROUND_CLOSEST(clk_get_rate(pltfm_host->clk), 1000000); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* Having a map is optional */ 9838c2ecf20Sopenharmony_ci if (!soc_ctl_map) 9848c2ecf20Sopenharmony_ci return; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* If we have a map, we expect to have a syscon */ 9878c2ecf20Sopenharmony_ci if (!sdhci_arasan->soc_ctl_base) { 9888c2ecf20Sopenharmony_ci pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 9898c2ecf20Sopenharmony_ci mmc_hostname(host->mmc)); 9908c2ecf20Sopenharmony_ci return; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci sdhci_arasan_syscon_write(host, &soc_ctl_map->baseclkfreq, mhz); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic void sdhci_arasan_set_clk_delays(struct sdhci_host *host) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 9998c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 10008c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci clk_set_phase(clk_data->sampleclk, 10038c2ecf20Sopenharmony_ci clk_data->clk_phase_in[host->timing]); 10048c2ecf20Sopenharmony_ci clk_set_phase(clk_data->sdcardclk, 10058c2ecf20Sopenharmony_ci clk_data->clk_phase_out[host->timing]); 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic void arasan_dt_read_clk_phase(struct device *dev, 10098c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data, 10108c2ecf20Sopenharmony_ci unsigned int timing, const char *prop) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci int clk_phase[2] = {0}; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci /* 10178c2ecf20Sopenharmony_ci * Read Tap Delay values from DT, if the DT does not contain the 10188c2ecf20Sopenharmony_ci * Tap Values then use the pre-defined values. 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_ci if (of_property_read_variable_u32_array(np, prop, &clk_phase[0], 10218c2ecf20Sopenharmony_ci 2, 0)) { 10228c2ecf20Sopenharmony_ci dev_dbg(dev, "Using predefined clock phase for %s = %d %d\n", 10238c2ecf20Sopenharmony_ci prop, clk_data->clk_phase_in[timing], 10248c2ecf20Sopenharmony_ci clk_data->clk_phase_out[timing]); 10258c2ecf20Sopenharmony_ci return; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* The values read are Input and Output Clock Delays in order */ 10298c2ecf20Sopenharmony_ci clk_data->clk_phase_in[timing] = clk_phase[0]; 10308c2ecf20Sopenharmony_ci clk_data->clk_phase_out[timing] = clk_phase[1]; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci/** 10348c2ecf20Sopenharmony_ci * arasan_dt_parse_clk_phases - Read Clock Delay values from DT 10358c2ecf20Sopenharmony_ci * 10368c2ecf20Sopenharmony_ci * @dev: Pointer to our struct device. 10378c2ecf20Sopenharmony_ci * @clk_data: Pointer to the Clock Data structure 10388c2ecf20Sopenharmony_ci * 10398c2ecf20Sopenharmony_ci * Called at initialization to parse the values of Clock Delays. 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_cistatic void arasan_dt_parse_clk_phases(struct device *dev, 10428c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data) 10438c2ecf20Sopenharmony_ci{ 10448c2ecf20Sopenharmony_ci u32 mio_bank = 0; 10458c2ecf20Sopenharmony_ci int i; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* 10488c2ecf20Sopenharmony_ci * This has been kept as a pointer and is assigned a function here. 10498c2ecf20Sopenharmony_ci * So that different controller variants can assign their own handling 10508c2ecf20Sopenharmony_ci * function. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_ci clk_data->set_clk_delays = sdhci_arasan_set_clk_delays; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (of_device_is_compatible(dev->of_node, "xlnx,zynqmp-8.9a")) { 10558c2ecf20Sopenharmony_ci u32 zynqmp_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 10568c2ecf20Sopenharmony_ci ZYNQMP_ICLK_PHASE; 10578c2ecf20Sopenharmony_ci u32 zynqmp_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 10588c2ecf20Sopenharmony_ci ZYNQMP_OCLK_PHASE; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci of_property_read_u32(dev->of_node, "xlnx,mio-bank", &mio_bank); 10618c2ecf20Sopenharmony_ci if (mio_bank == 2) { 10628c2ecf20Sopenharmony_ci zynqmp_oclk_phase[MMC_TIMING_UHS_SDR104] = 90; 10638c2ecf20Sopenharmony_ci zynqmp_oclk_phase[MMC_TIMING_MMC_HS200] = 90; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 10678c2ecf20Sopenharmony_ci clk_data->clk_phase_in[i] = zynqmp_iclk_phase[i]; 10688c2ecf20Sopenharmony_ci clk_data->clk_phase_out[i] = zynqmp_oclk_phase[i]; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (of_device_is_compatible(dev->of_node, "xlnx,versal-8.9a")) { 10738c2ecf20Sopenharmony_ci u32 versal_iclk_phase[MMC_TIMING_MMC_HS400 + 1] = 10748c2ecf20Sopenharmony_ci VERSAL_ICLK_PHASE; 10758c2ecf20Sopenharmony_ci u32 versal_oclk_phase[MMC_TIMING_MMC_HS400 + 1] = 10768c2ecf20Sopenharmony_ci VERSAL_OCLK_PHASE; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci for (i = 0; i <= MMC_TIMING_MMC_HS400; i++) { 10798c2ecf20Sopenharmony_ci clk_data->clk_phase_in[i] = versal_iclk_phase[i]; 10808c2ecf20Sopenharmony_ci clk_data->clk_phase_out[i] = versal_oclk_phase[i]; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_LEGACY, 10858c2ecf20Sopenharmony_ci "clk-phase-legacy"); 10868c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS, 10878c2ecf20Sopenharmony_ci "clk-phase-mmc-hs"); 10888c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_SD_HS, 10898c2ecf20Sopenharmony_ci "clk-phase-sd-hs"); 10908c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR12, 10918c2ecf20Sopenharmony_ci "clk-phase-uhs-sdr12"); 10928c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR25, 10938c2ecf20Sopenharmony_ci "clk-phase-uhs-sdr25"); 10948c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR50, 10958c2ecf20Sopenharmony_ci "clk-phase-uhs-sdr50"); 10968c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_SDR104, 10978c2ecf20Sopenharmony_ci "clk-phase-uhs-sdr104"); 10988c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_UHS_DDR50, 10998c2ecf20Sopenharmony_ci "clk-phase-uhs-ddr50"); 11008c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_DDR52, 11018c2ecf20Sopenharmony_ci "clk-phase-mmc-ddr52"); 11028c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS200, 11038c2ecf20Sopenharmony_ci "clk-phase-mmc-hs200"); 11048c2ecf20Sopenharmony_ci arasan_dt_read_clk_phase(dev, clk_data, MMC_TIMING_MMC_HS400, 11058c2ecf20Sopenharmony_ci "clk-phase-mmc-hs400"); 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_pdata = { 11098c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_ops, 11108c2ecf20Sopenharmony_ci .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 11118c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 11128c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 11138c2ecf20Sopenharmony_ci SDHCI_QUIRK2_STOP_WITH_TC, 11148c2ecf20Sopenharmony_ci}; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_clk_ops arasan_clk_ops = { 11178c2ecf20Sopenharmony_ci .sdcardclk_ops = &arasan_sdcardclk_ops, 11188c2ecf20Sopenharmony_ci .sampleclk_ops = &arasan_sampleclk_ops, 11198c2ecf20Sopenharmony_ci}; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_generic_data = { 11228c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_pdata, 11238c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 11248c2ecf20Sopenharmony_ci}; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_emmc_pdata = { 11278c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_cqe_ops, 11288c2ecf20Sopenharmony_ci .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 11298c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 11308c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_LED | 11318c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_ADDR | 11328c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_SIZE | 11338c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_ADMA_SIZE, 11348c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 11358c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 11368c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 | 11378c2ecf20Sopenharmony_ci SDHCI_QUIRK2_STOP_WITH_TC | 11388c2ecf20Sopenharmony_ci SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 11398c2ecf20Sopenharmony_ci}; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_sd_pdata = { 11428c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_ops, 11438c2ecf20Sopenharmony_ci .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 11448c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 11458c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_LED | 11468c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_ADDR | 11478c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_SIZE | 11488c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_ADMA_SIZE, 11498c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 11508c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 11518c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | 11528c2ecf20Sopenharmony_ci SDHCI_QUIRK2_STOP_WITH_TC | 11538c2ecf20Sopenharmony_ci SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 11548c2ecf20Sopenharmony_ci}; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_keembay_sdio_pdata = { 11578c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_ops, 11588c2ecf20Sopenharmony_ci .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | 11598c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 11608c2ecf20Sopenharmony_ci SDHCI_QUIRK_NO_LED | 11618c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_ADDR | 11628c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_SIZE | 11638c2ecf20Sopenharmony_ci SDHCI_QUIRK_32BIT_ADMA_SIZE, 11648c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 11658c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 11668c2ecf20Sopenharmony_ci SDHCI_QUIRK2_HOST_OFF_CARD_ON | 11678c2ecf20Sopenharmony_ci SDHCI_QUIRK2_BROKEN_64_BIT_DMA, 11688c2ecf20Sopenharmony_ci}; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_rk3399_data = { 11718c2ecf20Sopenharmony_ci .soc_ctl_map = &rk3399_soc_ctl_map, 11728c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_cqe_pdata, 11738c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 11748c2ecf20Sopenharmony_ci}; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data intel_lgm_emmc_data = { 11778c2ecf20Sopenharmony_ci .soc_ctl_map = &intel_lgm_emmc_soc_ctl_map, 11788c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_cqe_pdata, 11798c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 11808c2ecf20Sopenharmony_ci}; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data intel_lgm_sdxc_data = { 11838c2ecf20Sopenharmony_ci .soc_ctl_map = &intel_lgm_sdxc_soc_ctl_map, 11848c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_cqe_pdata, 11858c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 11868c2ecf20Sopenharmony_ci}; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_arasan_zynqmp_pdata = { 11898c2ecf20Sopenharmony_ci .ops = &sdhci_arasan_ops, 11908c2ecf20Sopenharmony_ci .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | 11918c2ecf20Sopenharmony_ci SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN | 11928c2ecf20Sopenharmony_ci SDHCI_QUIRK2_STOP_WITH_TC, 11938c2ecf20Sopenharmony_ci}; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_clk_ops zynqmp_clk_ops = { 11968c2ecf20Sopenharmony_ci .sdcardclk_ops = &zynqmp_sdcardclk_ops, 11978c2ecf20Sopenharmony_ci .sampleclk_ops = &zynqmp_sampleclk_ops, 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_zynqmp_data = { 12018c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_zynqmp_pdata, 12028c2ecf20Sopenharmony_ci .clk_ops = &zynqmp_clk_ops, 12038c2ecf20Sopenharmony_ci}; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic const struct sdhci_arasan_clk_ops versal_clk_ops = { 12068c2ecf20Sopenharmony_ci .sdcardclk_ops = &versal_sdcardclk_ops, 12078c2ecf20Sopenharmony_ci .sampleclk_ops = &versal_sampleclk_ops, 12088c2ecf20Sopenharmony_ci}; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data sdhci_arasan_versal_data = { 12118c2ecf20Sopenharmony_ci .pdata = &sdhci_arasan_zynqmp_pdata, 12128c2ecf20Sopenharmony_ci .clk_ops = &versal_clk_ops, 12138c2ecf20Sopenharmony_ci}; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_emmc_data = { 12168c2ecf20Sopenharmony_ci .soc_ctl_map = &intel_keembay_soc_ctl_map, 12178c2ecf20Sopenharmony_ci .pdata = &sdhci_keembay_emmc_pdata, 12188c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 12198c2ecf20Sopenharmony_ci}; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_sd_data = { 12228c2ecf20Sopenharmony_ci .soc_ctl_map = &intel_keembay_soc_ctl_map, 12238c2ecf20Sopenharmony_ci .pdata = &sdhci_keembay_sd_pdata, 12248c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 12258c2ecf20Sopenharmony_ci}; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic struct sdhci_arasan_of_data intel_keembay_sdio_data = { 12288c2ecf20Sopenharmony_ci .soc_ctl_map = &intel_keembay_soc_ctl_map, 12298c2ecf20Sopenharmony_ci .pdata = &sdhci_keembay_sdio_pdata, 12308c2ecf20Sopenharmony_ci .clk_ops = &arasan_clk_ops, 12318c2ecf20Sopenharmony_ci}; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic const struct of_device_id sdhci_arasan_of_match[] = { 12348c2ecf20Sopenharmony_ci /* SoC-specific compatible strings w/ soc_ctl_map */ 12358c2ecf20Sopenharmony_ci { 12368c2ecf20Sopenharmony_ci .compatible = "rockchip,rk3399-sdhci-5.1", 12378c2ecf20Sopenharmony_ci .data = &sdhci_arasan_rk3399_data, 12388c2ecf20Sopenharmony_ci }, 12398c2ecf20Sopenharmony_ci { 12408c2ecf20Sopenharmony_ci .compatible = "intel,lgm-sdhci-5.1-emmc", 12418c2ecf20Sopenharmony_ci .data = &intel_lgm_emmc_data, 12428c2ecf20Sopenharmony_ci }, 12438c2ecf20Sopenharmony_ci { 12448c2ecf20Sopenharmony_ci .compatible = "intel,lgm-sdhci-5.1-sdxc", 12458c2ecf20Sopenharmony_ci .data = &intel_lgm_sdxc_data, 12468c2ecf20Sopenharmony_ci }, 12478c2ecf20Sopenharmony_ci { 12488c2ecf20Sopenharmony_ci .compatible = "intel,keembay-sdhci-5.1-emmc", 12498c2ecf20Sopenharmony_ci .data = &intel_keembay_emmc_data, 12508c2ecf20Sopenharmony_ci }, 12518c2ecf20Sopenharmony_ci { 12528c2ecf20Sopenharmony_ci .compatible = "intel,keembay-sdhci-5.1-sd", 12538c2ecf20Sopenharmony_ci .data = &intel_keembay_sd_data, 12548c2ecf20Sopenharmony_ci }, 12558c2ecf20Sopenharmony_ci { 12568c2ecf20Sopenharmony_ci .compatible = "intel,keembay-sdhci-5.1-sdio", 12578c2ecf20Sopenharmony_ci .data = &intel_keembay_sdio_data, 12588c2ecf20Sopenharmony_ci }, 12598c2ecf20Sopenharmony_ci /* Generic compatible below here */ 12608c2ecf20Sopenharmony_ci { 12618c2ecf20Sopenharmony_ci .compatible = "arasan,sdhci-8.9a", 12628c2ecf20Sopenharmony_ci .data = &sdhci_arasan_generic_data, 12638c2ecf20Sopenharmony_ci }, 12648c2ecf20Sopenharmony_ci { 12658c2ecf20Sopenharmony_ci .compatible = "arasan,sdhci-5.1", 12668c2ecf20Sopenharmony_ci .data = &sdhci_arasan_generic_data, 12678c2ecf20Sopenharmony_ci }, 12688c2ecf20Sopenharmony_ci { 12698c2ecf20Sopenharmony_ci .compatible = "arasan,sdhci-4.9a", 12708c2ecf20Sopenharmony_ci .data = &sdhci_arasan_generic_data, 12718c2ecf20Sopenharmony_ci }, 12728c2ecf20Sopenharmony_ci { 12738c2ecf20Sopenharmony_ci .compatible = "xlnx,zynqmp-8.9a", 12748c2ecf20Sopenharmony_ci .data = &sdhci_arasan_zynqmp_data, 12758c2ecf20Sopenharmony_ci }, 12768c2ecf20Sopenharmony_ci { 12778c2ecf20Sopenharmony_ci .compatible = "xlnx,versal-8.9a", 12788c2ecf20Sopenharmony_ci .data = &sdhci_arasan_versal_data, 12798c2ecf20Sopenharmony_ci }, 12808c2ecf20Sopenharmony_ci { /* sentinel */ } 12818c2ecf20Sopenharmony_ci}; 12828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sdhci_arasan_of_match); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/** 12858c2ecf20Sopenharmony_ci * sdhci_arasan_register_sdcardclk - Register the sdcardclk for a PHY to use 12868c2ecf20Sopenharmony_ci * 12878c2ecf20Sopenharmony_ci * @sdhci_arasan: Our private data structure. 12888c2ecf20Sopenharmony_ci * @clk_xin: Pointer to the functional clock 12898c2ecf20Sopenharmony_ci * @dev: Pointer to our struct device. 12908c2ecf20Sopenharmony_ci * 12918c2ecf20Sopenharmony_ci * Some PHY devices need to know what the actual card clock is. In order for 12928c2ecf20Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework 12938c2ecf20Sopenharmony_ci * for them to query. 12948c2ecf20Sopenharmony_ci * 12958c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 12968c2ecf20Sopenharmony_ci */ 12978c2ecf20Sopenharmony_cistatic int 12988c2ecf20Sopenharmony_cisdhci_arasan_register_sdcardclk(struct sdhci_arasan_data *sdhci_arasan, 12998c2ecf20Sopenharmony_ci struct clk *clk_xin, 13008c2ecf20Sopenharmony_ci struct device *dev) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 13038c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 13048c2ecf20Sopenharmony_ci struct clk_init_data sdcardclk_init; 13058c2ecf20Sopenharmony_ci const char *parent_clk_name; 13068c2ecf20Sopenharmony_ci int ret; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci ret = of_property_read_string_index(np, "clock-output-names", 0, 13098c2ecf20Sopenharmony_ci &sdcardclk_init.name); 13108c2ecf20Sopenharmony_ci if (ret) { 13118c2ecf20Sopenharmony_ci dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 13128c2ecf20Sopenharmony_ci return ret; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci parent_clk_name = __clk_get_name(clk_xin); 13168c2ecf20Sopenharmony_ci sdcardclk_init.parent_names = &parent_clk_name; 13178c2ecf20Sopenharmony_ci sdcardclk_init.num_parents = 1; 13188c2ecf20Sopenharmony_ci sdcardclk_init.flags = CLK_GET_RATE_NOCACHE; 13198c2ecf20Sopenharmony_ci sdcardclk_init.ops = sdhci_arasan->clk_ops->sdcardclk_ops; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci clk_data->sdcardclk_hw.init = &sdcardclk_init; 13228c2ecf20Sopenharmony_ci clk_data->sdcardclk = 13238c2ecf20Sopenharmony_ci devm_clk_register(dev, &clk_data->sdcardclk_hw); 13248c2ecf20Sopenharmony_ci if (IS_ERR(clk_data->sdcardclk)) 13258c2ecf20Sopenharmony_ci return PTR_ERR(clk_data->sdcardclk); 13268c2ecf20Sopenharmony_ci clk_data->sdcardclk_hw.init = NULL; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci ret = of_clk_add_provider(np, of_clk_src_simple_get, 13298c2ecf20Sopenharmony_ci clk_data->sdcardclk); 13308c2ecf20Sopenharmony_ci if (ret) 13318c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add sdcard clock provider\n"); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return ret; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci/** 13378c2ecf20Sopenharmony_ci * sdhci_arasan_register_sampleclk - Register the sampleclk for a PHY to use 13388c2ecf20Sopenharmony_ci * 13398c2ecf20Sopenharmony_ci * @sdhci_arasan: Our private data structure. 13408c2ecf20Sopenharmony_ci * @clk_xin: Pointer to the functional clock 13418c2ecf20Sopenharmony_ci * @dev: Pointer to our struct device. 13428c2ecf20Sopenharmony_ci * 13438c2ecf20Sopenharmony_ci * Some PHY devices need to know what the actual card clock is. In order for 13448c2ecf20Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework 13458c2ecf20Sopenharmony_ci * for them to query. 13468c2ecf20Sopenharmony_ci * 13478c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_cistatic int 13508c2ecf20Sopenharmony_cisdhci_arasan_register_sampleclk(struct sdhci_arasan_data *sdhci_arasan, 13518c2ecf20Sopenharmony_ci struct clk *clk_xin, 13528c2ecf20Sopenharmony_ci struct device *dev) 13538c2ecf20Sopenharmony_ci{ 13548c2ecf20Sopenharmony_ci struct sdhci_arasan_clk_data *clk_data = &sdhci_arasan->clk_data; 13558c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 13568c2ecf20Sopenharmony_ci struct clk_init_data sampleclk_init; 13578c2ecf20Sopenharmony_ci const char *parent_clk_name; 13588c2ecf20Sopenharmony_ci int ret; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci ret = of_property_read_string_index(np, "clock-output-names", 1, 13618c2ecf20Sopenharmony_ci &sampleclk_init.name); 13628c2ecf20Sopenharmony_ci if (ret) { 13638c2ecf20Sopenharmony_ci dev_err(dev, "DT has #clock-cells but no clock-output-names\n"); 13648c2ecf20Sopenharmony_ci return ret; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci parent_clk_name = __clk_get_name(clk_xin); 13688c2ecf20Sopenharmony_ci sampleclk_init.parent_names = &parent_clk_name; 13698c2ecf20Sopenharmony_ci sampleclk_init.num_parents = 1; 13708c2ecf20Sopenharmony_ci sampleclk_init.flags = CLK_GET_RATE_NOCACHE; 13718c2ecf20Sopenharmony_ci sampleclk_init.ops = sdhci_arasan->clk_ops->sampleclk_ops; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci clk_data->sampleclk_hw.init = &sampleclk_init; 13748c2ecf20Sopenharmony_ci clk_data->sampleclk = 13758c2ecf20Sopenharmony_ci devm_clk_register(dev, &clk_data->sampleclk_hw); 13768c2ecf20Sopenharmony_ci if (IS_ERR(clk_data->sampleclk)) 13778c2ecf20Sopenharmony_ci return PTR_ERR(clk_data->sampleclk); 13788c2ecf20Sopenharmony_ci clk_data->sampleclk_hw.init = NULL; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci ret = of_clk_add_provider(np, of_clk_src_simple_get, 13818c2ecf20Sopenharmony_ci clk_data->sampleclk); 13828c2ecf20Sopenharmony_ci if (ret) 13838c2ecf20Sopenharmony_ci dev_err(dev, "Failed to add sample clock provider\n"); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci return ret; 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci/** 13898c2ecf20Sopenharmony_ci * sdhci_arasan_unregister_sdclk - Undoes sdhci_arasan_register_sdclk() 13908c2ecf20Sopenharmony_ci * 13918c2ecf20Sopenharmony_ci * @dev: Pointer to our struct device. 13928c2ecf20Sopenharmony_ci * 13938c2ecf20Sopenharmony_ci * Should be called any time we're exiting and sdhci_arasan_register_sdclk() 13948c2ecf20Sopenharmony_ci * returned success. 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_cistatic void sdhci_arasan_unregister_sdclk(struct device *dev) 13978c2ecf20Sopenharmony_ci{ 13988c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!of_find_property(np, "#clock-cells", NULL)) 14018c2ecf20Sopenharmony_ci return; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci of_clk_del_provider(dev->of_node); 14048c2ecf20Sopenharmony_ci} 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci/** 14078c2ecf20Sopenharmony_ci * sdhci_arasan_update_support64b - Set SUPPORT_64B (64-bit System Bus Support) 14088c2ecf20Sopenharmony_ci * 14098c2ecf20Sopenharmony_ci * This should be set based on the System Address Bus. 14108c2ecf20Sopenharmony_ci * 0: the Core supports only 32-bit System Address Bus. 14118c2ecf20Sopenharmony_ci * 1: the Core supports 64-bit System Address Bus. 14128c2ecf20Sopenharmony_ci * 14138c2ecf20Sopenharmony_ci * NOTES: 14148c2ecf20Sopenharmony_ci * - For Keem Bay, it is required to clear this bit. Its default value is 1'b1. 14158c2ecf20Sopenharmony_ci * Keem Bay does not support 64-bit access. 14168c2ecf20Sopenharmony_ci * 14178c2ecf20Sopenharmony_ci * @host: The sdhci_host 14188c2ecf20Sopenharmony_ci * @value: The value to write 14198c2ecf20Sopenharmony_ci */ 14208c2ecf20Sopenharmony_cistatic void sdhci_arasan_update_support64b(struct sdhci_host *host, u32 value) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 14238c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 14248c2ecf20Sopenharmony_ci const struct sdhci_arasan_soc_ctl_map *soc_ctl_map = 14258c2ecf20Sopenharmony_ci sdhci_arasan->soc_ctl_map; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci /* Having a map is optional */ 14288c2ecf20Sopenharmony_ci if (!soc_ctl_map) 14298c2ecf20Sopenharmony_ci return; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci /* If we have a map, we expect to have a syscon */ 14328c2ecf20Sopenharmony_ci if (!sdhci_arasan->soc_ctl_base) { 14338c2ecf20Sopenharmony_ci pr_warn("%s: Have regmap, but no soc-ctl-syscon\n", 14348c2ecf20Sopenharmony_ci mmc_hostname(host->mmc)); 14358c2ecf20Sopenharmony_ci return; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci sdhci_arasan_syscon_write(host, &soc_ctl_map->support64b, value); 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci/** 14428c2ecf20Sopenharmony_ci * sdhci_arasan_register_sdclk - Register the sdcardclk for a PHY to use 14438c2ecf20Sopenharmony_ci * 14448c2ecf20Sopenharmony_ci * @sdhci_arasan: Our private data structure. 14458c2ecf20Sopenharmony_ci * @clk_xin: Pointer to the functional clock 14468c2ecf20Sopenharmony_ci * @dev: Pointer to our struct device. 14478c2ecf20Sopenharmony_ci * 14488c2ecf20Sopenharmony_ci * Some PHY devices need to know what the actual card clock is. In order for 14498c2ecf20Sopenharmony_ci * them to find out, we'll provide a clock through the common clock framework 14508c2ecf20Sopenharmony_ci * for them to query. 14518c2ecf20Sopenharmony_ci * 14528c2ecf20Sopenharmony_ci * Note: without seriously re-architecting SDHCI's clock code and testing on 14538c2ecf20Sopenharmony_ci * all platforms, there's no way to create a totally beautiful clock here 14548c2ecf20Sopenharmony_ci * with all clock ops implemented. Instead, we'll just create a clock that can 14558c2ecf20Sopenharmony_ci * be queried and set the CLK_GET_RATE_NOCACHE attribute to tell common clock 14568c2ecf20Sopenharmony_ci * framework that we're doing things behind its back. This should be sufficient 14578c2ecf20Sopenharmony_ci * to create nice clean device tree bindings and later (if needed) we can try 14588c2ecf20Sopenharmony_ci * re-architecting SDHCI if we see some benefit to it. 14598c2ecf20Sopenharmony_ci * 14608c2ecf20Sopenharmony_ci * Return: 0 on success and error value on error 14618c2ecf20Sopenharmony_ci */ 14628c2ecf20Sopenharmony_cistatic int sdhci_arasan_register_sdclk(struct sdhci_arasan_data *sdhci_arasan, 14638c2ecf20Sopenharmony_ci struct clk *clk_xin, 14648c2ecf20Sopenharmony_ci struct device *dev) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 14678c2ecf20Sopenharmony_ci u32 num_clks = 0; 14688c2ecf20Sopenharmony_ci int ret; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Providing a clock to the PHY is optional; no error if missing */ 14718c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0) 14728c2ecf20Sopenharmony_ci return 0; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci ret = sdhci_arasan_register_sdcardclk(sdhci_arasan, clk_xin, dev); 14758c2ecf20Sopenharmony_ci if (ret) 14768c2ecf20Sopenharmony_ci return ret; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (num_clks) { 14798c2ecf20Sopenharmony_ci ret = sdhci_arasan_register_sampleclk(sdhci_arasan, clk_xin, 14808c2ecf20Sopenharmony_ci dev); 14818c2ecf20Sopenharmony_ci if (ret) { 14828c2ecf20Sopenharmony_ci sdhci_arasan_unregister_sdclk(dev); 14838c2ecf20Sopenharmony_ci return ret; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return 0; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic int sdhci_arasan_add_host(struct sdhci_arasan_data *sdhci_arasan) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci struct sdhci_host *host = sdhci_arasan->host; 14938c2ecf20Sopenharmony_ci struct cqhci_host *cq_host; 14948c2ecf20Sopenharmony_ci bool dma64; 14958c2ecf20Sopenharmony_ci int ret; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci if (!sdhci_arasan->has_cqe) 14988c2ecf20Sopenharmony_ci return sdhci_add_host(host); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci ret = sdhci_setup_host(host); 15018c2ecf20Sopenharmony_ci if (ret) 15028c2ecf20Sopenharmony_ci return ret; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci cq_host = devm_kzalloc(host->mmc->parent, 15058c2ecf20Sopenharmony_ci sizeof(*cq_host), GFP_KERNEL); 15068c2ecf20Sopenharmony_ci if (!cq_host) { 15078c2ecf20Sopenharmony_ci ret = -ENOMEM; 15088c2ecf20Sopenharmony_ci goto cleanup; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci cq_host->mmio = host->ioaddr + SDHCI_ARASAN_CQE_BASE_ADDR; 15128c2ecf20Sopenharmony_ci cq_host->ops = &sdhci_arasan_cqhci_ops; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci dma64 = host->flags & SDHCI_USE_64_BIT_DMA; 15158c2ecf20Sopenharmony_ci if (dma64) 15168c2ecf20Sopenharmony_ci cq_host->caps |= CQHCI_TASK_DESC_SZ_128; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci ret = cqhci_init(cq_host, host->mmc, dma64); 15198c2ecf20Sopenharmony_ci if (ret) 15208c2ecf20Sopenharmony_ci goto cleanup; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci ret = __sdhci_add_host(host); 15238c2ecf20Sopenharmony_ci if (ret) 15248c2ecf20Sopenharmony_ci goto cleanup; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci return 0; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cicleanup: 15298c2ecf20Sopenharmony_ci sdhci_cleanup_host(host); 15308c2ecf20Sopenharmony_ci return ret; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic int sdhci_arasan_probe(struct platform_device *pdev) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci int ret; 15368c2ecf20Sopenharmony_ci const struct of_device_id *match; 15378c2ecf20Sopenharmony_ci struct device_node *node; 15388c2ecf20Sopenharmony_ci struct clk *clk_xin; 15398c2ecf20Sopenharmony_ci struct sdhci_host *host; 15408c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host; 15418c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan; 15428c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 15438c2ecf20Sopenharmony_ci const struct sdhci_arasan_of_data *data; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node); 15468c2ecf20Sopenharmony_ci data = match->data; 15478c2ecf20Sopenharmony_ci host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan)); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (IS_ERR(host)) 15508c2ecf20Sopenharmony_ci return PTR_ERR(host); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci pltfm_host = sdhci_priv(host); 15538c2ecf20Sopenharmony_ci sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 15548c2ecf20Sopenharmony_ci sdhci_arasan->host = host; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci sdhci_arasan->soc_ctl_map = data->soc_ctl_map; 15578c2ecf20Sopenharmony_ci sdhci_arasan->clk_ops = data->clk_ops; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0); 15608c2ecf20Sopenharmony_ci if (node) { 15618c2ecf20Sopenharmony_ci sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); 15628c2ecf20Sopenharmony_ci of_node_put(node); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci if (IS_ERR(sdhci_arasan->soc_ctl_base)) { 15658c2ecf20Sopenharmony_ci ret = dev_err_probe(&pdev->dev, 15668c2ecf20Sopenharmony_ci PTR_ERR(sdhci_arasan->soc_ctl_base), 15678c2ecf20Sopenharmony_ci "Can't get syscon\n"); 15688c2ecf20Sopenharmony_ci goto err_pltfm_free; 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); 15738c2ecf20Sopenharmony_ci if (IS_ERR(sdhci_arasan->clk_ahb)) { 15748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "clk_ahb clock not found.\n"); 15758c2ecf20Sopenharmony_ci ret = PTR_ERR(sdhci_arasan->clk_ahb); 15768c2ecf20Sopenharmony_ci goto err_pltfm_free; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); 15808c2ecf20Sopenharmony_ci if (IS_ERR(clk_xin)) { 15818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "clk_xin clock not found.\n"); 15828c2ecf20Sopenharmony_ci ret = PTR_ERR(clk_xin); 15838c2ecf20Sopenharmony_ci goto err_pltfm_free; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci ret = clk_prepare_enable(sdhci_arasan->clk_ahb); 15878c2ecf20Sopenharmony_ci if (ret) { 15888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); 15898c2ecf20Sopenharmony_ci goto err_pltfm_free; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk_xin); 15938c2ecf20Sopenharmony_ci if (ret) { 15948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to enable SD clock.\n"); 15958c2ecf20Sopenharmony_ci goto clk_dis_ahb; 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci sdhci_get_of_property(pdev); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "xlnx,fails-without-test-cd")) 16018c2ecf20Sopenharmony_ci sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "xlnx,int-clock-stable-broken")) 16048c2ecf20Sopenharmony_ci sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci pltfm_host->clk = clk_xin; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (of_device_is_compatible(pdev->dev.of_node, 16098c2ecf20Sopenharmony_ci "rockchip,rk3399-sdhci-5.1")) 16108c2ecf20Sopenharmony_ci sdhci_arasan_update_clockmultiplier(host, 0x0); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") || 16138c2ecf20Sopenharmony_ci of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") || 16148c2ecf20Sopenharmony_ci of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio")) { 16158c2ecf20Sopenharmony_ci sdhci_arasan_update_clockmultiplier(host, 0x0); 16168c2ecf20Sopenharmony_ci sdhci_arasan_update_support64b(host, 0x0); 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci sdhci_arasan_update_baseclkfreq(host); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev); 16248c2ecf20Sopenharmony_ci if (ret) 16258c2ecf20Sopenharmony_ci goto clk_disable_all; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) { 16288c2ecf20Sopenharmony_ci host->mmc_host_ops.execute_tuning = 16298c2ecf20Sopenharmony_ci arasan_zynqmp_execute_tuning; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci ret = mmc_of_parse(host->mmc); 16378c2ecf20Sopenharmony_ci if (ret) { 16388c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 16398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret); 16408c2ecf20Sopenharmony_ci goto unreg_clk; 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci sdhci_arasan->phy = ERR_PTR(-ENODEV); 16448c2ecf20Sopenharmony_ci if (of_device_is_compatible(pdev->dev.of_node, 16458c2ecf20Sopenharmony_ci "arasan,sdhci-5.1")) { 16468c2ecf20Sopenharmony_ci sdhci_arasan->phy = devm_phy_get(&pdev->dev, 16478c2ecf20Sopenharmony_ci "phy_arasan"); 16488c2ecf20Sopenharmony_ci if (IS_ERR(sdhci_arasan->phy)) { 16498c2ecf20Sopenharmony_ci ret = PTR_ERR(sdhci_arasan->phy); 16508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n"); 16518c2ecf20Sopenharmony_ci goto unreg_clk; 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci ret = phy_init(sdhci_arasan->phy); 16558c2ecf20Sopenharmony_ci if (ret < 0) { 16568c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "phy_init err.\n"); 16578c2ecf20Sopenharmony_ci goto unreg_clk; 16588c2ecf20Sopenharmony_ci } 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci host->mmc_host_ops.hs400_enhanced_strobe = 16618c2ecf20Sopenharmony_ci sdhci_arasan_hs400_enhanced_strobe; 16628c2ecf20Sopenharmony_ci host->mmc_host_ops.start_signal_voltage_switch = 16638c2ecf20Sopenharmony_ci sdhci_arasan_voltage_switch; 16648c2ecf20Sopenharmony_ci sdhci_arasan->has_cqe = true; 16658c2ecf20Sopenharmony_ci host->mmc->caps2 |= MMC_CAP2_CQE; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (!of_property_read_bool(np, "disable-cqe-dcmd")) 16688c2ecf20Sopenharmony_ci host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci ret = sdhci_arasan_add_host(sdhci_arasan); 16728c2ecf20Sopenharmony_ci if (ret) 16738c2ecf20Sopenharmony_ci goto err_add_host; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci return 0; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_cierr_add_host: 16788c2ecf20Sopenharmony_ci if (!IS_ERR(sdhci_arasan->phy)) 16798c2ecf20Sopenharmony_ci phy_exit(sdhci_arasan->phy); 16808c2ecf20Sopenharmony_ciunreg_clk: 16818c2ecf20Sopenharmony_ci sdhci_arasan_unregister_sdclk(&pdev->dev); 16828c2ecf20Sopenharmony_ciclk_disable_all: 16838c2ecf20Sopenharmony_ci clk_disable_unprepare(clk_xin); 16848c2ecf20Sopenharmony_ciclk_dis_ahb: 16858c2ecf20Sopenharmony_ci clk_disable_unprepare(sdhci_arasan->clk_ahb); 16868c2ecf20Sopenharmony_cierr_pltfm_free: 16878c2ecf20Sopenharmony_ci sdhci_pltfm_free(pdev); 16888c2ecf20Sopenharmony_ci return ret; 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic int sdhci_arasan_remove(struct platform_device *pdev) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci int ret; 16948c2ecf20Sopenharmony_ci struct sdhci_host *host = platform_get_drvdata(pdev); 16958c2ecf20Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 16968c2ecf20Sopenharmony_ci struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); 16978c2ecf20Sopenharmony_ci struct clk *clk_ahb = sdhci_arasan->clk_ahb; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (!IS_ERR(sdhci_arasan->phy)) { 17008c2ecf20Sopenharmony_ci if (sdhci_arasan->is_phy_on) 17018c2ecf20Sopenharmony_ci phy_power_off(sdhci_arasan->phy); 17028c2ecf20Sopenharmony_ci phy_exit(sdhci_arasan->phy); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci sdhci_arasan_unregister_sdclk(&pdev->dev); 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci ret = sdhci_pltfm_unregister(pdev); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci clk_disable_unprepare(clk_ahb); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci return ret; 17128c2ecf20Sopenharmony_ci} 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic struct platform_driver sdhci_arasan_driver = { 17158c2ecf20Sopenharmony_ci .driver = { 17168c2ecf20Sopenharmony_ci .name = "sdhci-arasan", 17178c2ecf20Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 17188c2ecf20Sopenharmony_ci .of_match_table = sdhci_arasan_of_match, 17198c2ecf20Sopenharmony_ci .pm = &sdhci_arasan_dev_pm_ops, 17208c2ecf20Sopenharmony_ci }, 17218c2ecf20Sopenharmony_ci .probe = sdhci_arasan_probe, 17228c2ecf20Sopenharmony_ci .remove = sdhci_arasan_remove, 17238c2ecf20Sopenharmony_ci}; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cimodule_platform_driver(sdhci_arasan_driver); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for the Arasan SDHCI Controller"); 17288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>"); 17298c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1730