1f707079dSWolfram Sang // SPDX-License-Identifier: GPL-2.0 2b5b6a5f4SSimon Horman /* 39d08428aSSimon Horman * Renesas SDHI 4b5b6a5f4SSimon Horman * 5f49bdcdeSWolfram Sang * Copyright (C) 2015-19 Renesas Electronics Corporation 6f49bdcdeSWolfram Sang * Copyright (C) 2016-19 Sang Engineering, Wolfram Sang 787317c4dSSimon Horman * Copyright (C) 2016-17 Horms Solutions, Simon Horman 8b5b6a5f4SSimon Horman * Copyright (C) 2009 Magnus Damm 9b5b6a5f4SSimon Horman * 10b5b6a5f4SSimon Horman * Based on "Compaq ASIC3 support": 11b5b6a5f4SSimon Horman * 12b5b6a5f4SSimon Horman * Copyright 2001 Compaq Computer Corporation. 13b5b6a5f4SSimon Horman * Copyright 2004-2005 Phil Blundell 14b5b6a5f4SSimon Horman * Copyright 2007-2008 OpenedHand Ltd. 15b5b6a5f4SSimon Horman * 16b5b6a5f4SSimon Horman * Authors: Phil Blundell <pb@handhelds.org>, 17b5b6a5f4SSimon Horman * Samuel Ortiz <sameo@openedhand.com> 18b5b6a5f4SSimon Horman * 19b5b6a5f4SSimon Horman */ 20b5b6a5f4SSimon Horman 21b5b6a5f4SSimon Horman #include <linux/kernel.h> 22b5b6a5f4SSimon Horman #include <linux/clk.h> 23b5b6a5f4SSimon Horman #include <linux/slab.h> 24967a6a07SMasaharu Hayakawa #include <linux/module.h> 25b5b6a5f4SSimon Horman #include <linux/of_device.h> 26b5b6a5f4SSimon Horman #include <linux/platform_device.h> 27b5b6a5f4SSimon Horman #include <linux/mmc/host.h> 28ef5332c1SWolfram Sang #include <linux/mmc/slot-gpio.h> 29b5b6a5f4SSimon Horman #include <linux/mfd/tmio.h> 30b5b6a5f4SSimon Horman #include <linux/sh_dma.h> 31b5b6a5f4SSimon Horman #include <linux/delay.h> 32b5b6a5f4SSimon Horman #include <linux/pinctrl/consumer.h> 33b5b6a5f4SSimon Horman #include <linux/pinctrl/pinctrl-state.h> 34b5b6a5f4SSimon Horman #include <linux/regulator/consumer.h> 35164691aaSNiklas Söderlund #include <linux/sys_soc.h> 36b5b6a5f4SSimon Horman 37b5b6a5f4SSimon Horman #include "renesas_sdhi.h" 38b5b6a5f4SSimon Horman #include "tmio_mmc.h" 39b5b6a5f4SSimon Horman 404472f0fcSMasaharu Hayakawa #define HOST_MODE 0xe4 41b5b6a5f4SSimon Horman 42b5b6a5f4SSimon Horman #define SDHI_VER_GEN2_SDR50 0x490c 43c7825151SWolfram Sang #define SDHI_VER_RZ_A1 0x820b 44b5b6a5f4SSimon Horman /* very old datasheets said 0x490c for SDR104, too. They are wrong! */ 45b5b6a5f4SSimon Horman #define SDHI_VER_GEN2_SDR104 0xcb0d 46b5b6a5f4SSimon Horman #define SDHI_VER_GEN3_SD 0xcc10 47b5b6a5f4SSimon Horman #define SDHI_VER_GEN3_SDMMC 0xcd10 48b5b6a5f4SSimon Horman 49b5b6a5f4SSimon Horman static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) 50b5b6a5f4SSimon Horman { 51b5b6a5f4SSimon Horman u32 val; 52b5b6a5f4SSimon Horman 53b5b6a5f4SSimon Horman /* 54b5b6a5f4SSimon Horman * see also 55b5b6a5f4SSimon Horman * renesas_sdhi_of_data :: dma_buswidth 56b5b6a5f4SSimon Horman */ 57b5b6a5f4SSimon Horman switch (sd_ctrl_read16(host, CTL_VERSION)) { 58b5b6a5f4SSimon Horman case SDHI_VER_GEN2_SDR50: 59b5b6a5f4SSimon Horman val = (width == 32) ? 0x0001 : 0x0000; 60b5b6a5f4SSimon Horman break; 61b5b6a5f4SSimon Horman case SDHI_VER_GEN2_SDR104: 62b5b6a5f4SSimon Horman val = (width == 32) ? 0x0000 : 0x0001; 63b5b6a5f4SSimon Horman break; 64b5b6a5f4SSimon Horman case SDHI_VER_GEN3_SD: 65b5b6a5f4SSimon Horman case SDHI_VER_GEN3_SDMMC: 66b5b6a5f4SSimon Horman if (width == 64) 67b5b6a5f4SSimon Horman val = 0x0000; 68b5b6a5f4SSimon Horman else if (width == 32) 69b5b6a5f4SSimon Horman val = 0x0101; 70b5b6a5f4SSimon Horman else 71b5b6a5f4SSimon Horman val = 0x0001; 72b5b6a5f4SSimon Horman break; 73b5b6a5f4SSimon Horman default: 74b5b6a5f4SSimon Horman /* nothing to do */ 75b5b6a5f4SSimon Horman return; 76b5b6a5f4SSimon Horman } 77b5b6a5f4SSimon Horman 784472f0fcSMasaharu Hayakawa sd_ctrl_write16(host, HOST_MODE, val); 79b5b6a5f4SSimon Horman } 80b5b6a5f4SSimon Horman 81b5b6a5f4SSimon Horman static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host) 82b5b6a5f4SSimon Horman { 83b5b6a5f4SSimon Horman struct mmc_host *mmc = host->mmc; 84b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 85b5b6a5f4SSimon Horman int ret = clk_prepare_enable(priv->clk); 862fe35968SSimon Horman 87b5b6a5f4SSimon Horman if (ret < 0) 88b5b6a5f4SSimon Horman return ret; 89b5b6a5f4SSimon Horman 90b5b6a5f4SSimon Horman ret = clk_prepare_enable(priv->clk_cd); 91b5b6a5f4SSimon Horman if (ret < 0) { 92b5b6a5f4SSimon Horman clk_disable_unprepare(priv->clk); 93b5b6a5f4SSimon Horman return ret; 94b5b6a5f4SSimon Horman } 95b5b6a5f4SSimon Horman 96b5b6a5f4SSimon Horman /* 97b5b6a5f4SSimon Horman * The clock driver may not know what maximum frequency 98b5b6a5f4SSimon Horman * actually works, so it should be set with the max-frequency 99b5b6a5f4SSimon Horman * property which will already have been read to f_max. If it 100b5b6a5f4SSimon Horman * was missing, assume the current frequency is the maximum. 101b5b6a5f4SSimon Horman */ 102b5b6a5f4SSimon Horman if (!mmc->f_max) 103b5b6a5f4SSimon Horman mmc->f_max = clk_get_rate(priv->clk); 104b5b6a5f4SSimon Horman 105b5b6a5f4SSimon Horman /* 106b5b6a5f4SSimon Horman * Minimum frequency is the minimum input clock frequency 107b5b6a5f4SSimon Horman * divided by our maximum divider. 108b5b6a5f4SSimon Horman */ 109b5b6a5f4SSimon Horman mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); 110b5b6a5f4SSimon Horman 111b5b6a5f4SSimon Horman /* enable 16bit data access on SDBUF as default */ 112b5b6a5f4SSimon Horman renesas_sdhi_sdbuf_width(host, 16); 113b5b6a5f4SSimon Horman 114b5b6a5f4SSimon Horman return 0; 115b5b6a5f4SSimon Horman } 116b5b6a5f4SSimon Horman 117b5b6a5f4SSimon Horman static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host, 118b5b6a5f4SSimon Horman unsigned int new_clock) 119b5b6a5f4SSimon Horman { 120b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 121b5b6a5f4SSimon Horman unsigned int freq, diff, best_freq = 0, diff_min = ~0; 12275eaf49fSTamás Szűcs int i; 123b5b6a5f4SSimon Horman 124d63c2bf4SWolfram Sang /* tested only on R-Car Gen2+ currently; may work for others */ 125b5b6a5f4SSimon Horman if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) 126b5b6a5f4SSimon Horman return clk_get_rate(priv->clk); 127b5b6a5f4SSimon Horman 128b5b6a5f4SSimon Horman /* 129b5b6a5f4SSimon Horman * We want the bus clock to be as close as possible to, but no 130b5b6a5f4SSimon Horman * greater than, new_clock. As we can divide by 1 << i for 131b5b6a5f4SSimon Horman * any i in [0, 9] we want the input clock to be as close as 132b5b6a5f4SSimon Horman * possible, but no greater than, new_clock << i. 133b5b6a5f4SSimon Horman */ 134b5b6a5f4SSimon Horman for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { 135b5b6a5f4SSimon Horman freq = clk_round_rate(priv->clk, new_clock << i); 136b5b6a5f4SSimon Horman if (freq > (new_clock << i)) { 137b5b6a5f4SSimon Horman /* Too fast; look for a slightly slower option */ 138b5b6a5f4SSimon Horman freq = clk_round_rate(priv->clk, 139b5b6a5f4SSimon Horman (new_clock << i) / 4 * 3); 140b5b6a5f4SSimon Horman if (freq > (new_clock << i)) 141b5b6a5f4SSimon Horman continue; 142b5b6a5f4SSimon Horman } 143b5b6a5f4SSimon Horman 144b5b6a5f4SSimon Horman diff = new_clock - (freq >> i); 145b5b6a5f4SSimon Horman if (diff <= diff_min) { 146b5b6a5f4SSimon Horman best_freq = freq; 147b5b6a5f4SSimon Horman diff_min = diff; 148b5b6a5f4SSimon Horman } 149b5b6a5f4SSimon Horman } 150b5b6a5f4SSimon Horman 15175eaf49fSTamás Szűcs clk_set_rate(priv->clk, best_freq); 152b5b6a5f4SSimon Horman 15375eaf49fSTamás Szűcs return clk_get_rate(priv->clk); 154b5b6a5f4SSimon Horman } 155b5b6a5f4SSimon Horman 1560196c8dbSMasahiro Yamada static void renesas_sdhi_set_clock(struct tmio_mmc_host *host, 1570196c8dbSMasahiro Yamada unsigned int new_clock) 1580196c8dbSMasahiro Yamada { 1590196c8dbSMasahiro Yamada u32 clk = 0, clock; 1600196c8dbSMasahiro Yamada 16168f83127SMasahiro Yamada sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 16268f83127SMasahiro Yamada sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 16368f83127SMasahiro Yamada 16475eaf49fSTamás Szűcs if (new_clock == 0) { 16575eaf49fSTamás Szűcs host->mmc->actual_clock = 0; 16668f83127SMasahiro Yamada goto out; 16775eaf49fSTamás Szűcs } 16868f83127SMasahiro Yamada 16975eaf49fSTamás Szűcs host->mmc->actual_clock = renesas_sdhi_clk_update(host, new_clock); 17075eaf49fSTamás Szűcs clock = host->mmc->actual_clock / 512; 1710196c8dbSMasahiro Yamada 1720196c8dbSMasahiro Yamada for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) 1730196c8dbSMasahiro Yamada clock <<= 1; 1740196c8dbSMasahiro Yamada 1750196c8dbSMasahiro Yamada /* 1/1 clock is option */ 1760196c8dbSMasahiro Yamada if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) { 1770196c8dbSMasahiro Yamada if (!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400)) 1780196c8dbSMasahiro Yamada clk |= 0xff; 1790196c8dbSMasahiro Yamada else 1800196c8dbSMasahiro Yamada clk &= ~0xff; 1810196c8dbSMasahiro Yamada } 1820196c8dbSMasahiro Yamada 1830196c8dbSMasahiro Yamada sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); 1840196c8dbSMasahiro Yamada if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) 1850196c8dbSMasahiro Yamada usleep_range(10000, 11000); 1860196c8dbSMasahiro Yamada 18768f83127SMasahiro Yamada sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 18868f83127SMasahiro Yamada sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 18968f83127SMasahiro Yamada 19068f83127SMasahiro Yamada out: 19168f83127SMasahiro Yamada /* HW engineers overrode docs: no sleep needed on R-Car2+ */ 19268f83127SMasahiro Yamada if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) 19368f83127SMasahiro Yamada usleep_range(10000, 11000); 1940196c8dbSMasahiro Yamada } 1950196c8dbSMasahiro Yamada 196b5b6a5f4SSimon Horman static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host) 197b5b6a5f4SSimon Horman { 198b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 199b5b6a5f4SSimon Horman 200b5b6a5f4SSimon Horman clk_disable_unprepare(priv->clk); 201b5b6a5f4SSimon Horman clk_disable_unprepare(priv->clk_cd); 202b5b6a5f4SSimon Horman } 203b5b6a5f4SSimon Horman 204b5b6a5f4SSimon Horman static int renesas_sdhi_card_busy(struct mmc_host *mmc) 205b5b6a5f4SSimon Horman { 206b5b6a5f4SSimon Horman struct tmio_mmc_host *host = mmc_priv(mmc); 207b5b6a5f4SSimon Horman 2082fe35968SSimon Horman return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & 2092fe35968SSimon Horman TMIO_STAT_DAT0); 210b5b6a5f4SSimon Horman } 211b5b6a5f4SSimon Horman 212b5b6a5f4SSimon Horman static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, 213b5b6a5f4SSimon Horman struct mmc_ios *ios) 214b5b6a5f4SSimon Horman { 215b5b6a5f4SSimon Horman struct tmio_mmc_host *host = mmc_priv(mmc); 216b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 217b5b6a5f4SSimon Horman struct pinctrl_state *pin_state; 218b5b6a5f4SSimon Horman int ret; 219b5b6a5f4SSimon Horman 220b5b6a5f4SSimon Horman switch (ios->signal_voltage) { 221b5b6a5f4SSimon Horman case MMC_SIGNAL_VOLTAGE_330: 222b5b6a5f4SSimon Horman pin_state = priv->pins_default; 223b5b6a5f4SSimon Horman break; 224b5b6a5f4SSimon Horman case MMC_SIGNAL_VOLTAGE_180: 225b5b6a5f4SSimon Horman pin_state = priv->pins_uhs; 226b5b6a5f4SSimon Horman break; 227b5b6a5f4SSimon Horman default: 228b5b6a5f4SSimon Horman return -EINVAL; 229b5b6a5f4SSimon Horman } 230b5b6a5f4SSimon Horman 231b5b6a5f4SSimon Horman /* 232b5b6a5f4SSimon Horman * If anything is missing, assume signal voltage is fixed at 233b5b6a5f4SSimon Horman * 3.3V and succeed/fail accordingly. 234b5b6a5f4SSimon Horman */ 235b5b6a5f4SSimon Horman if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) 236b5b6a5f4SSimon Horman return ios->signal_voltage == 237b5b6a5f4SSimon Horman MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; 238b5b6a5f4SSimon Horman 239b5b6a5f4SSimon Horman ret = mmc_regulator_set_vqmmc(host->mmc, ios); 240b5b6a5f4SSimon Horman if (ret) 241b5b6a5f4SSimon Horman return ret; 242b5b6a5f4SSimon Horman 243b5b6a5f4SSimon Horman return pinctrl_select_state(priv->pinctrl, pin_state); 244b5b6a5f4SSimon Horman } 245b5b6a5f4SSimon Horman 246b5b6a5f4SSimon Horman /* SCC registers */ 247b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_DTCNTL 0x000 248b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_TAPSET 0x002 249b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_DT2FF 0x004 250b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_CKSEL 0x006 251b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008 252b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A 25371cfc927STakeshi Saito #define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C 25426eb2607SMasaharu Hayakawa #define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E 255b5b6a5f4SSimon Horman 256b5b6a5f4SSimon Horman /* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */ 257b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) 258b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 259b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff 260b5b6a5f4SSimon Horman 261b5b6a5f4SSimon Horman /* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */ 262b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) 263b5b6a5f4SSimon Horman /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */ 264b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) 265b5b6a5f4SSimon Horman /* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */ 266b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) 26711a21960STakeshi Saito #define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP BIT(1) 26811a21960STakeshi Saito #define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0) 26971cfc927STakeshi Saito /* Definitions for values the SH_MOBILE_SDHI_SCC_SMPCMP register */ 27071cfc927STakeshi Saito #define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR (BIT(24) | BIT(8)) 27171cfc927STakeshi Saito #define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP BIT(24) 27271cfc927STakeshi Saito #define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN BIT(8) 27326eb2607SMasaharu Hayakawa /* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */ 27426eb2607SMasaharu Hayakawa #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4) 27526eb2607SMasaharu Hayakawa #define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31) 276b5b6a5f4SSimon Horman 277b5b6a5f4SSimon Horman static inline u32 sd_scc_read32(struct tmio_mmc_host *host, 278b5b6a5f4SSimon Horman struct renesas_sdhi *priv, int addr) 279b5b6a5f4SSimon Horman { 280b5b6a5f4SSimon Horman return readl(priv->scc_ctl + (addr << host->bus_shift)); 281b5b6a5f4SSimon Horman } 282b5b6a5f4SSimon Horman 283b5b6a5f4SSimon Horman static inline void sd_scc_write32(struct tmio_mmc_host *host, 284b5b6a5f4SSimon Horman struct renesas_sdhi *priv, 285b5b6a5f4SSimon Horman int addr, u32 val) 286b5b6a5f4SSimon Horman { 287b5b6a5f4SSimon Horman writel(val, priv->scc_ctl + (addr << host->bus_shift)); 288b5b6a5f4SSimon Horman } 289b5b6a5f4SSimon Horman 290b5b6a5f4SSimon Horman static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host) 291b5b6a5f4SSimon Horman { 292b5b6a5f4SSimon Horman struct renesas_sdhi *priv; 293b5b6a5f4SSimon Horman 294b5b6a5f4SSimon Horman priv = host_to_priv(host); 295b5b6a5f4SSimon Horman 296b5b6a5f4SSimon Horman /* Initialize SCC */ 297b5b6a5f4SSimon Horman sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0); 298b5b6a5f4SSimon Horman 299b5b6a5f4SSimon Horman sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 300b5b6a5f4SSimon Horman sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 301b5b6a5f4SSimon Horman 30226eb2607SMasaharu Hayakawa /* set sampling clock selection range */ 30326eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, 30426eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | 30526eb2607SMasaharu Hayakawa 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); 30626eb2607SMasaharu Hayakawa 307b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 308b5b6a5f4SSimon Horman SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | 309b5b6a5f4SSimon Horman sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); 310b5b6a5f4SSimon Horman 311b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 312b5b6a5f4SSimon Horman ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & 313b5b6a5f4SSimon Horman sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 314b5b6a5f4SSimon Horman 315852d258fSMasahiro Yamada sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos); 316b5b6a5f4SSimon Horman 31726eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 31826eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 31926eb2607SMasaharu Hayakawa 320b5b6a5f4SSimon Horman /* Read TAPNUM */ 321b5b6a5f4SSimon Horman return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >> 322b5b6a5f4SSimon Horman SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & 323b5b6a5f4SSimon Horman SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; 324b5b6a5f4SSimon Horman } 325b5b6a5f4SSimon Horman 326b5b6a5f4SSimon Horman static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host, 327b5b6a5f4SSimon Horman unsigned long tap) 328b5b6a5f4SSimon Horman { 329b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 330b5b6a5f4SSimon Horman 33111a21960STakeshi Saito priv->doing_tune = true; 33211a21960STakeshi Saito 333b5b6a5f4SSimon Horman /* Set sampling clock position */ 334b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap); 335b5b6a5f4SSimon Horman } 336b5b6a5f4SSimon Horman 33726eb2607SMasaharu Hayakawa static void renesas_sdhi_hs400_complete(struct tmio_mmc_host *host) 33826eb2607SMasaharu Hayakawa { 33926eb2607SMasaharu Hayakawa struct renesas_sdhi *priv = host_to_priv(host); 34026eb2607SMasaharu Hayakawa 34126eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 34226eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 34326eb2607SMasaharu Hayakawa 34426eb2607SMasaharu Hayakawa /* Set HS400 mode */ 34526eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 | 34626eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SDIF_MODE)); 347f0c8234cSTakeshi Saito 348f0c8234cSTakeshi Saito sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, 349f0c8234cSTakeshi Saito priv->scc_tappos_hs400); 350f0c8234cSTakeshi Saito 35126eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 35226eb2607SMasaharu Hayakawa (SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | 35326eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) | 35426eb2607SMasaharu Hayakawa sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); 35526eb2607SMasaharu Hayakawa 35626eb2607SMasaharu Hayakawa /* Set the sampling clock selection range of HS400 mode */ 35726eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, 35826eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN | 35926eb2607SMasaharu Hayakawa 0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT); 36026eb2607SMasaharu Hayakawa 36126eb2607SMasaharu Hayakawa 36212e3c55dSWolfram Sang if (priv->quirks && priv->quirks->hs400_4taps) 36326eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, 36426eb2607SMasaharu Hayakawa host->tap_set / 2); 36526eb2607SMasaharu Hayakawa 36626eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 36726eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_CKSEL_DTSEL | 36826eb2607SMasaharu Hayakawa sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL)); 36926eb2607SMasaharu Hayakawa 37026eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 37126eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 37226eb2607SMasaharu Hayakawa } 37326eb2607SMasaharu Hayakawa 37426eb2607SMasaharu Hayakawa static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host, 37526eb2607SMasaharu Hayakawa struct renesas_sdhi *priv) 37626eb2607SMasaharu Hayakawa { 37726eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 37826eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 37926eb2607SMasaharu Hayakawa 38026eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL, 38126eb2607SMasaharu Hayakawa ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL & 38226eb2607SMasaharu Hayakawa sd_scc_read32(host, priv, 38326eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_CKSEL)); 38426eb2607SMasaharu Hayakawa } 38526eb2607SMasaharu Hayakawa 38626eb2607SMasaharu Hayakawa static void renesas_sdhi_disable_scc(struct tmio_mmc_host *host) 38726eb2607SMasaharu Hayakawa { 38826eb2607SMasaharu Hayakawa struct renesas_sdhi *priv = host_to_priv(host); 38926eb2607SMasaharu Hayakawa 39026eb2607SMasaharu Hayakawa renesas_sdhi_reset_scc(host, priv); 39126eb2607SMasaharu Hayakawa 39226eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL, 39326eb2607SMasaharu Hayakawa ~SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN & 39426eb2607SMasaharu Hayakawa sd_scc_read32(host, priv, 39526eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_DTCNTL)); 39626eb2607SMasaharu Hayakawa 39726eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 39826eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 39926eb2607SMasaharu Hayakawa } 40026eb2607SMasaharu Hayakawa 40126eb2607SMasaharu Hayakawa static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host, 40226eb2607SMasaharu Hayakawa struct renesas_sdhi *priv) 40326eb2607SMasaharu Hayakawa { 40426eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & 40526eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 40626eb2607SMasaharu Hayakawa 40726eb2607SMasaharu Hayakawa /* Reset HS400 mode */ 40826eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 & 40926eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SDIF_MODE)); 410f0c8234cSTakeshi Saito 411f0c8234cSTakeshi Saito sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos); 412f0c8234cSTakeshi Saito 41326eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2, 41426eb2607SMasaharu Hayakawa ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN | 41526eb2607SMasaharu Hayakawa SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) & 41626eb2607SMasaharu Hayakawa sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2)); 41726eb2607SMasaharu Hayakawa 41826eb2607SMasaharu Hayakawa sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 41926eb2607SMasaharu Hayakawa sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 42026eb2607SMasaharu Hayakawa } 42126eb2607SMasaharu Hayakawa 42226eb2607SMasaharu Hayakawa static void renesas_sdhi_prepare_hs400_tuning(struct tmio_mmc_host *host) 42326eb2607SMasaharu Hayakawa { 42426eb2607SMasaharu Hayakawa renesas_sdhi_reset_hs400_mode(host, host_to_priv(host)); 42526eb2607SMasaharu Hayakawa } 42626eb2607SMasaharu Hayakawa 427b5b6a5f4SSimon Horman #define SH_MOBILE_SDHI_MAX_TAP 3 428b5b6a5f4SSimon Horman 429b5b6a5f4SSimon Horman static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) 430b5b6a5f4SSimon Horman { 431b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 432b5b6a5f4SSimon Horman unsigned long tap_cnt; /* counter of tuning success */ 433b5b6a5f4SSimon Horman unsigned long tap_start;/* start position of tuning success */ 434b5b6a5f4SSimon Horman unsigned long tap_end; /* end position of tuning success */ 435b5b6a5f4SSimon Horman unsigned long ntap; /* temporary counter of tuning success */ 436b5b6a5f4SSimon Horman unsigned long i; 437b5b6a5f4SSimon Horman 43811a21960STakeshi Saito priv->doing_tune = false; 43911a21960STakeshi Saito 440b5b6a5f4SSimon Horman /* Clear SCC_RVSREQ */ 441b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); 442b5b6a5f4SSimon Horman 443b5b6a5f4SSimon Horman /* 4445c99826bSNiklas Söderlund * When tuning CMD19 is issued twice for each tap, merge the 4455c99826bSNiklas Söderlund * result requiring the tap to be good in both runs before 4465c99826bSNiklas Söderlund * considering it for tuning selection. 4475c99826bSNiklas Söderlund */ 4485c99826bSNiklas Söderlund for (i = 0; i < host->tap_num * 2; i++) { 4495c99826bSNiklas Söderlund int offset = host->tap_num * (i < host->tap_num ? 1 : -1); 4505c99826bSNiklas Söderlund 4515c99826bSNiklas Söderlund if (!test_bit(i, host->taps)) 4525c99826bSNiklas Söderlund clear_bit(i + offset, host->taps); 4535c99826bSNiklas Söderlund } 4545c99826bSNiklas Söderlund 4555c99826bSNiklas Söderlund /* 456b5b6a5f4SSimon Horman * Find the longest consecutive run of successful probes. If that 457b5b6a5f4SSimon Horman * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the 458b5b6a5f4SSimon Horman * center index as the tap. 459b5b6a5f4SSimon Horman */ 460b5b6a5f4SSimon Horman tap_cnt = 0; 461b5b6a5f4SSimon Horman ntap = 0; 462b5b6a5f4SSimon Horman tap_start = 0; 463b5b6a5f4SSimon Horman tap_end = 0; 464b5b6a5f4SSimon Horman for (i = 0; i < host->tap_num * 2; i++) { 4652fe35968SSimon Horman if (test_bit(i, host->taps)) { 466b5b6a5f4SSimon Horman ntap++; 4672fe35968SSimon Horman } else { 468b5b6a5f4SSimon Horman if (ntap > tap_cnt) { 469b5b6a5f4SSimon Horman tap_start = i - ntap; 470b5b6a5f4SSimon Horman tap_end = i - 1; 471b5b6a5f4SSimon Horman tap_cnt = ntap; 472b5b6a5f4SSimon Horman } 473b5b6a5f4SSimon Horman ntap = 0; 474b5b6a5f4SSimon Horman } 475b5b6a5f4SSimon Horman } 476b5b6a5f4SSimon Horman 477b5b6a5f4SSimon Horman if (ntap > tap_cnt) { 478b5b6a5f4SSimon Horman tap_start = i - ntap; 479b5b6a5f4SSimon Horman tap_end = i - 1; 480b5b6a5f4SSimon Horman tap_cnt = ntap; 481b5b6a5f4SSimon Horman } 482b5b6a5f4SSimon Horman 483b5b6a5f4SSimon Horman if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) 48426eb2607SMasaharu Hayakawa host->tap_set = (tap_start + tap_end) / 2 % host->tap_num; 485b5b6a5f4SSimon Horman else 486b5b6a5f4SSimon Horman return -EIO; 487b5b6a5f4SSimon Horman 488b5b6a5f4SSimon Horman /* Set SCC */ 48926eb2607SMasaharu Hayakawa sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, host->tap_set); 490b5b6a5f4SSimon Horman 491b5b6a5f4SSimon Horman /* Enable auto re-tuning */ 492b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 493b5b6a5f4SSimon Horman SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | 494b5b6a5f4SSimon Horman sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 495b5b6a5f4SSimon Horman 496b5b6a5f4SSimon Horman return 0; 497b5b6a5f4SSimon Horman } 498b5b6a5f4SSimon Horman 49911a21960STakeshi Saito static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap) 50011a21960STakeshi Saito { 50111a21960STakeshi Saito struct renesas_sdhi *priv = host_to_priv(host); 50271cfc927STakeshi Saito unsigned long new_tap = host->tap_set; 50311a21960STakeshi Saito u32 val; 50411a21960STakeshi Saito 50511a21960STakeshi Saito val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ); 50611a21960STakeshi Saito if (!val) 50711a21960STakeshi Saito return false; 50811a21960STakeshi Saito 50911a21960STakeshi Saito sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); 51011a21960STakeshi Saito 51111a21960STakeshi Saito /* Change TAP position according to correction status */ 51271cfc927STakeshi Saito if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC && 51371cfc927STakeshi Saito host->mmc->ios.timing == MMC_TIMING_MMC_HS400) { 51471cfc927STakeshi Saito /* 51571cfc927STakeshi Saito * With HS400, the DAT signal is based on DS, not CLK. 51671cfc927STakeshi Saito * Therefore, use only CMD status. 51771cfc927STakeshi Saito */ 51871cfc927STakeshi Saito u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) & 51971cfc927STakeshi Saito SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR; 52071cfc927STakeshi Saito if (!smpcmp) 52171cfc927STakeshi Saito return false; /* no error in CMD signal */ 52271cfc927STakeshi Saito else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP) 52371cfc927STakeshi Saito new_tap++; 52471cfc927STakeshi Saito else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN) 52571cfc927STakeshi Saito new_tap--; 52671cfc927STakeshi Saito else 52771cfc927STakeshi Saito return true; /* need retune */ 52871cfc927STakeshi Saito } else { 52911a21960STakeshi Saito if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) 53071cfc927STakeshi Saito return true; /* need retune */ 53111a21960STakeshi Saito else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP) 53271cfc927STakeshi Saito new_tap++; 53311a21960STakeshi Saito else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN) 53471cfc927STakeshi Saito new_tap--; 53511a21960STakeshi Saito else 53611a21960STakeshi Saito return false; 53771cfc927STakeshi Saito } 53811a21960STakeshi Saito 53971cfc927STakeshi Saito host->tap_set = (new_tap % host->tap_num); 54011a21960STakeshi Saito sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, 54111a21960STakeshi Saito host->tap_set / (use_4tap ? 2 : 1)); 54211a21960STakeshi Saito 54311a21960STakeshi Saito return false; 54411a21960STakeshi Saito } 54511a21960STakeshi Saito 54611a21960STakeshi Saito static bool renesas_sdhi_auto_correction(struct tmio_mmc_host *host) 54711a21960STakeshi Saito { 54811a21960STakeshi Saito struct renesas_sdhi *priv = host_to_priv(host); 54911a21960STakeshi Saito 55011a21960STakeshi Saito /* Check SCC error */ 55111a21960STakeshi Saito if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) & 55211a21960STakeshi Saito SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) { 55311a21960STakeshi Saito sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0); 55411a21960STakeshi Saito return true; 55511a21960STakeshi Saito } 55611a21960STakeshi Saito 55711a21960STakeshi Saito return false; 55811a21960STakeshi Saito } 55911a21960STakeshi Saito 560b5b6a5f4SSimon Horman static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host) 561b5b6a5f4SSimon Horman { 562b5b6a5f4SSimon Horman struct renesas_sdhi *priv = host_to_priv(host); 56312e3c55dSWolfram Sang bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; 56475f349a1SMasaharu Hayakawa 56575f349a1SMasaharu Hayakawa /* 56675f349a1SMasaharu Hayakawa * Skip checking SCC errors when running on 4 taps in HS400 mode as 56775f349a1SMasaharu Hayakawa * any retuning would still result in the same 4 taps being used. 56875f349a1SMasaharu Hayakawa */ 56975f349a1SMasaharu Hayakawa if (!(host->mmc->ios.timing == MMC_TIMING_UHS_SDR104) && 57075f349a1SMasaharu Hayakawa !(host->mmc->ios.timing == MMC_TIMING_MMC_HS200) && 57175f349a1SMasaharu Hayakawa !(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap)) 57275f349a1SMasaharu Hayakawa return false; 57375f349a1SMasaharu Hayakawa 57411a21960STakeshi Saito if (mmc_doing_retune(host->mmc) || priv->doing_tune) 57575f349a1SMasaharu Hayakawa return false; 576b5b6a5f4SSimon Horman 577b5b6a5f4SSimon Horman if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & 57811a21960STakeshi Saito SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) 57911a21960STakeshi Saito return renesas_sdhi_auto_correction(host); 580b5b6a5f4SSimon Horman 58111a21960STakeshi Saito return renesas_sdhi_manual_correction(host, use_4tap); 582b5b6a5f4SSimon Horman } 583b5b6a5f4SSimon Horman 584b5b6a5f4SSimon Horman static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host) 585b5b6a5f4SSimon Horman { 586b5b6a5f4SSimon Horman struct renesas_sdhi *priv; 587b5b6a5f4SSimon Horman 588b5b6a5f4SSimon Horman priv = host_to_priv(host); 589b5b6a5f4SSimon Horman 59026eb2607SMasaharu Hayakawa renesas_sdhi_reset_scc(host, priv); 59126eb2607SMasaharu Hayakawa renesas_sdhi_reset_hs400_mode(host, priv); 592b5b6a5f4SSimon Horman 593b5b6a5f4SSimon Horman sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | 594b5b6a5f4SSimon Horman sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); 595b5b6a5f4SSimon Horman 596b5b6a5f4SSimon Horman sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, 597b5b6a5f4SSimon Horman ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN & 598b5b6a5f4SSimon Horman sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); 599b5b6a5f4SSimon Horman 600202367cbSNiklas Söderlund if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) 601202367cbSNiklas Söderlund sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, 602202367cbSNiklas Söderlund TMIO_MASK_INIT_RCAR2); 603b5b6a5f4SSimon Horman } 604b5b6a5f4SSimon Horman 6054dc48a95SWolfram Sang static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) 606b5b6a5f4SSimon Horman { 607b5b6a5f4SSimon Horman int timeout = 1000; 6084dc48a95SWolfram Sang /* CBSY is set when busy, SCLKDIVEN is cleared when busy */ 6094dc48a95SWolfram Sang u32 wait_state = (bit == TMIO_STAT_CMD_BUSY ? TMIO_STAT_CMD_BUSY : 0); 610b5b6a5f4SSimon Horman 6114dc48a95SWolfram Sang while (--timeout && (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) 6124dc48a95SWolfram Sang & bit) == wait_state) 613b5b6a5f4SSimon Horman udelay(1); 614b5b6a5f4SSimon Horman 615b5b6a5f4SSimon Horman if (!timeout) { 616b5b6a5f4SSimon Horman dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); 617b5b6a5f4SSimon Horman return -EBUSY; 618b5b6a5f4SSimon Horman } 619b5b6a5f4SSimon Horman 620b5b6a5f4SSimon Horman return 0; 621b5b6a5f4SSimon Horman } 622b5b6a5f4SSimon Horman 623b5b6a5f4SSimon Horman static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr) 624b5b6a5f4SSimon Horman { 6254dc48a95SWolfram Sang u32 bit = TMIO_STAT_SCLKDIVEN; 6264dc48a95SWolfram Sang 6272fe35968SSimon Horman switch (addr) { 628b5b6a5f4SSimon Horman case CTL_SD_CMD: 629b5b6a5f4SSimon Horman case CTL_STOP_INTERNAL_ACTION: 630b5b6a5f4SSimon Horman case CTL_XFER_BLK_COUNT: 631b5b6a5f4SSimon Horman case CTL_SD_XFER_LEN: 632b5b6a5f4SSimon Horman case CTL_SD_MEM_CARD_OPT: 633b5b6a5f4SSimon Horman case CTL_TRANSACTION_CTL: 634b5b6a5f4SSimon Horman case CTL_DMA_ENABLE: 6354472f0fcSMasaharu Hayakawa case HOST_MODE: 6365124b592SWolfram Sang if (host->pdata->flags & TMIO_MMC_HAVE_CBSY) 6374dc48a95SWolfram Sang bit = TMIO_STAT_CMD_BUSY; 6384dc48a95SWolfram Sang /* fallthrough */ 6394dc48a95SWolfram Sang case CTL_SD_CARD_CLK_CTL: 6404dc48a95SWolfram Sang return renesas_sdhi_wait_idle(host, bit); 641b5b6a5f4SSimon Horman } 642b5b6a5f4SSimon Horman 643b5b6a5f4SSimon Horman return 0; 644b5b6a5f4SSimon Horman } 645b5b6a5f4SSimon Horman 646b5b6a5f4SSimon Horman static int renesas_sdhi_multi_io_quirk(struct mmc_card *card, 647b5b6a5f4SSimon Horman unsigned int direction, int blk_size) 648b5b6a5f4SSimon Horman { 649b5b6a5f4SSimon Horman /* 650b5b6a5f4SSimon Horman * In Renesas controllers, when performing a 651b5b6a5f4SSimon Horman * multiple block read of one or two blocks, 652b5b6a5f4SSimon Horman * depending on the timing with which the 653b5b6a5f4SSimon Horman * response register is read, the response 654b5b6a5f4SSimon Horman * value may not be read properly. 655b5b6a5f4SSimon Horman * Use single block read for this HW bug 656b5b6a5f4SSimon Horman */ 657b5b6a5f4SSimon Horman if ((direction == MMC_DATA_READ) && 658b5b6a5f4SSimon Horman blk_size == 2) 659b5b6a5f4SSimon Horman return 1; 660b5b6a5f4SSimon Horman 661b5b6a5f4SSimon Horman return blk_size; 662b5b6a5f4SSimon Horman } 663b5b6a5f4SSimon Horman 664b5b6a5f4SSimon Horman static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) 665b5b6a5f4SSimon Horman { 66641279f01SWolfram Sang /* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */ 66741279f01SWolfram Sang int width = (host->bus_shift == 2) ? 64 : 32; 668b5b6a5f4SSimon Horman 66941279f01SWolfram Sang sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0); 67041279f01SWolfram Sang renesas_sdhi_sdbuf_width(host, enable ? width : 16); 671b5b6a5f4SSimon Horman } 672b5b6a5f4SSimon Horman 6736a686986SWolfram Sang static const struct renesas_sdhi_quirks sdhi_quirks_4tap_nohs400 = { 6740f4e2054SNiklas Söderlund .hs400_disabled = true, 6750f4e2054SNiklas Söderlund .hs400_4taps = true, 6760f4e2054SNiklas Söderlund }; 6770f4e2054SNiklas Söderlund 6786a686986SWolfram Sang static const struct renesas_sdhi_quirks sdhi_quirks_4tap = { 679164691aaSNiklas Söderlund .hs400_4taps = true, 680164691aaSNiklas Söderlund }; 681164691aaSNiklas Söderlund 68297bf85b6SWolfram Sang static const struct renesas_sdhi_quirks sdhi_quirks_nohs400 = { 68397bf85b6SWolfram Sang .hs400_disabled = true, 68497bf85b6SWolfram Sang }; 68597bf85b6SWolfram Sang 686164691aaSNiklas Söderlund static const struct soc_device_attribute sdhi_quirks_match[] = { 6876e3cbb05SWolfram Sang { .soc_id = "r8a774a1", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, 6886a686986SWolfram Sang { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_4tap_nohs400 }, 6896a686986SWolfram Sang { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_4tap }, 6906a686986SWolfram Sang { .soc_id = "r8a7796", .revision = "ES1.[012]", .data = &sdhi_quirks_4tap_nohs400 }, 69197bf85b6SWolfram Sang { .soc_id = "r8a77980", .data = &sdhi_quirks_nohs400 }, 692164691aaSNiklas Söderlund { /* Sentinel. */ }, 693164691aaSNiklas Söderlund }; 694164691aaSNiklas Söderlund 6959d08428aSSimon Horman int renesas_sdhi_probe(struct platform_device *pdev, 6969d08428aSSimon Horman const struct tmio_mmc_dma_ops *dma_ops) 697b5b6a5f4SSimon Horman { 698b5b6a5f4SSimon Horman struct tmio_mmc_data *mmd = pdev->dev.platform_data; 699164691aaSNiklas Söderlund const struct renesas_sdhi_quirks *quirks = NULL; 7002fe35968SSimon Horman const struct renesas_sdhi_of_data *of_data; 701164691aaSNiklas Söderlund const struct soc_device_attribute *attr; 7022fe35968SSimon Horman struct tmio_mmc_data *mmc_data; 7032fe35968SSimon Horman struct tmio_mmc_dma *dma_priv; 704b5b6a5f4SSimon Horman struct tmio_mmc_host *host; 7052fe35968SSimon Horman struct renesas_sdhi *priv; 706e8307ec5SGeert Uytterhoeven int num_irqs, irq, ret, i; 707b5b6a5f4SSimon Horman struct resource *res; 708c9a9497cSWolfram Sang u16 ver; 7092fe35968SSimon Horman 7102fe35968SSimon Horman of_data = of_device_get_match_data(&pdev->dev); 711b5b6a5f4SSimon Horman 712164691aaSNiklas Söderlund attr = soc_device_match(sdhi_quirks_match); 713164691aaSNiklas Söderlund if (attr) 714164691aaSNiklas Söderlund quirks = attr->data; 715164691aaSNiklas Söderlund 716b5b6a5f4SSimon Horman res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 717b5b6a5f4SSimon Horman if (!res) 718b5b6a5f4SSimon Horman return -EINVAL; 719b5b6a5f4SSimon Horman 7202fe35968SSimon Horman priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi), 7212fe35968SSimon Horman GFP_KERNEL); 722b5b6a5f4SSimon Horman if (!priv) 723b5b6a5f4SSimon Horman return -ENOMEM; 724b5b6a5f4SSimon Horman 7257af08206SWolfram Sang priv->quirks = quirks; 726b5b6a5f4SSimon Horman mmc_data = &priv->mmc_data; 727b5b6a5f4SSimon Horman dma_priv = &priv->dma_priv; 728b5b6a5f4SSimon Horman 729b5b6a5f4SSimon Horman priv->clk = devm_clk_get(&pdev->dev, NULL); 730b5b6a5f4SSimon Horman if (IS_ERR(priv->clk)) { 731b5b6a5f4SSimon Horman ret = PTR_ERR(priv->clk); 732b5b6a5f4SSimon Horman dev_err(&pdev->dev, "cannot get clock: %d\n", ret); 7334ce62817SMasahiro Yamada return ret; 734b5b6a5f4SSimon Horman } 735b5b6a5f4SSimon Horman 736b5b6a5f4SSimon Horman /* 737b5b6a5f4SSimon Horman * Some controllers provide a 2nd clock just to run the internal card 738b5b6a5f4SSimon Horman * detection logic. Unfortunately, the existing driver architecture does 739b5b6a5f4SSimon Horman * not support a separation of clocks for runtime PM usage. When 740b5b6a5f4SSimon Horman * native hotplug is used, the tmio driver assumes that the core 741b5b6a5f4SSimon Horman * must continue to run for card detect to stay active, so we cannot 742b5b6a5f4SSimon Horman * disable it. 743b5b6a5f4SSimon Horman * Additionally, it is prohibited to supply a clock to the core but not 744b5b6a5f4SSimon Horman * to the card detect circuit. That leaves us with if separate clocks 745b5b6a5f4SSimon Horman * are presented, we must treat them both as virtually 1 clock. 746b5b6a5f4SSimon Horman */ 747b5b6a5f4SSimon Horman priv->clk_cd = devm_clk_get(&pdev->dev, "cd"); 748b5b6a5f4SSimon Horman if (IS_ERR(priv->clk_cd)) 749b5b6a5f4SSimon Horman priv->clk_cd = NULL; 750b5b6a5f4SSimon Horman 751b5b6a5f4SSimon Horman priv->pinctrl = devm_pinctrl_get(&pdev->dev); 752b5b6a5f4SSimon Horman if (!IS_ERR(priv->pinctrl)) { 753b5b6a5f4SSimon Horman priv->pins_default = pinctrl_lookup_state(priv->pinctrl, 754b5b6a5f4SSimon Horman PINCTRL_STATE_DEFAULT); 755b5b6a5f4SSimon Horman priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, 756b5b6a5f4SSimon Horman "state_uhs"); 757b5b6a5f4SSimon Horman } 758b5b6a5f4SSimon Horman 759b21fc294SMasahiro Yamada host = tmio_mmc_host_alloc(pdev, mmc_data); 7608d09a133SMasahiro Yamada if (IS_ERR(host)) 7618d09a133SMasahiro Yamada return PTR_ERR(host); 762b5b6a5f4SSimon Horman 763b5b6a5f4SSimon Horman if (of_data) { 764b5b6a5f4SSimon Horman mmc_data->flags |= of_data->tmio_flags; 765b5b6a5f4SSimon Horman mmc_data->ocr_mask = of_data->tmio_ocr_mask; 766b5b6a5f4SSimon Horman mmc_data->capabilities |= of_data->capabilities; 767b5b6a5f4SSimon Horman mmc_data->capabilities2 |= of_data->capabilities2; 768b5b6a5f4SSimon Horman mmc_data->dma_rx_offset = of_data->dma_rx_offset; 769603aa14dSYoshihiro Shimoda mmc_data->max_blk_count = of_data->max_blk_count; 770603aa14dSYoshihiro Shimoda mmc_data->max_segs = of_data->max_segs; 771b5b6a5f4SSimon Horman dma_priv->dma_buswidth = of_data->dma_buswidth; 772b5b6a5f4SSimon Horman host->bus_shift = of_data->bus_shift; 773b5b6a5f4SSimon Horman } 774b5b6a5f4SSimon Horman 775b5b6a5f4SSimon Horman host->write16_hook = renesas_sdhi_write16_hook; 776b5b6a5f4SSimon Horman host->clk_enable = renesas_sdhi_clk_enable; 777b5b6a5f4SSimon Horman host->clk_disable = renesas_sdhi_clk_disable; 7780196c8dbSMasahiro Yamada host->set_clock = renesas_sdhi_set_clock; 779b5b6a5f4SSimon Horman host->multi_io_quirk = renesas_sdhi_multi_io_quirk; 780bc45719cSMasahiro Yamada host->dma_ops = dma_ops; 781b5b6a5f4SSimon Horman 7820f4e2054SNiklas Söderlund if (quirks && quirks->hs400_disabled) 7830f4e2054SNiklas Söderlund host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); 7840f4e2054SNiklas Söderlund 785ef5332c1SWolfram Sang /* For some SoC, we disable internal WP. GPIO may override this */ 786ef5332c1SWolfram Sang if (mmc_can_gpio_ro(host->mmc)) 787ef5332c1SWolfram Sang mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT; 788ef5332c1SWolfram Sang 789b5b6a5f4SSimon Horman /* SDR speeds are only available on Gen2+ */ 790b5b6a5f4SSimon Horman if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) { 791b5b6a5f4SSimon Horman /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */ 7922aaa3c51SMasahiro Yamada host->ops.card_busy = renesas_sdhi_card_busy; 7932aaa3c51SMasahiro Yamada host->ops.start_signal_voltage_switch = 794b5b6a5f4SSimon Horman renesas_sdhi_start_signal_voltage_switch; 7951970701fSWolfram Sang host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27; 796d30ae056STakeshi Saito 797d30ae056STakeshi Saito /* SDR and HS200/400 registers requires HW reset */ 798d30ae056STakeshi Saito if (of_data && of_data->scc_offset) { 799d30ae056STakeshi Saito priv->scc_ctl = host->ctl + of_data->scc_offset; 800d30ae056STakeshi Saito host->mmc->caps |= MMC_CAP_HW_RESET; 801d30ae056STakeshi Saito host->hw_reset = renesas_sdhi_hw_reset; 802d30ae056STakeshi Saito } 803b5b6a5f4SSimon Horman } 804b5b6a5f4SSimon Horman 805b5b6a5f4SSimon Horman /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ 806b5b6a5f4SSimon Horman if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ 807b5b6a5f4SSimon Horman host->bus_shift = 1; 808b5b6a5f4SSimon Horman 809b5b6a5f4SSimon Horman if (mmd) 810b5b6a5f4SSimon Horman *mmc_data = *mmd; 811b5b6a5f4SSimon Horman 812b5b6a5f4SSimon Horman dma_priv->filter = shdma_chan_filter; 813b5b6a5f4SSimon Horman dma_priv->enable = renesas_sdhi_enable_dma; 814b5b6a5f4SSimon Horman 815b5b6a5f4SSimon Horman mmc_data->alignment_shift = 1; /* 2-byte alignment */ 816b5b6a5f4SSimon Horman mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED; 817b5b6a5f4SSimon Horman 818b5b6a5f4SSimon Horman /* 819b5b6a5f4SSimon Horman * All SDHI blocks support 2-byte and larger block sizes in 4-bit 820b5b6a5f4SSimon Horman * bus width mode. 821b5b6a5f4SSimon Horman */ 822b5b6a5f4SSimon Horman mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; 823b5b6a5f4SSimon Horman 824b5b6a5f4SSimon Horman /* 825b5b6a5f4SSimon Horman * All SDHI blocks support SDIO IRQ signalling. 826b5b6a5f4SSimon Horman */ 827b5b6a5f4SSimon Horman mmc_data->flags |= TMIO_MMC_SDIO_IRQ; 828b5b6a5f4SSimon Horman 8292fe35968SSimon Horman /* All SDHI have CMD12 control bit */ 830b5b6a5f4SSimon Horman mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL; 831b5b6a5f4SSimon Horman 832b5b6a5f4SSimon Horman /* All SDHI have SDIO status bits which must be 1 */ 833b5b6a5f4SSimon Horman mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS; 834b5b6a5f4SSimon Horman 835b21fc294SMasahiro Yamada ret = renesas_sdhi_clk_enable(host); 836b21fc294SMasahiro Yamada if (ret) 837b5b6a5f4SSimon Horman goto efree; 838b5b6a5f4SSimon Horman 839c9a9497cSWolfram Sang ver = sd_ctrl_read16(host, CTL_VERSION); 840c9a9497cSWolfram Sang /* GEN2_SDR104 is first known SDHI to use 32bit block count */ 841c9a9497cSWolfram Sang if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) 842c9a9497cSWolfram Sang mmc_data->max_blk_count = U16_MAX; 843c9a9497cSWolfram Sang 8445124b592SWolfram Sang /* One Gen2 SDHI incarnation does NOT have a CBSY bit */ 845c9a9497cSWolfram Sang if (ver == SDHI_VER_GEN2_SDR50) 8465124b592SWolfram Sang mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY; 8475124b592SWolfram Sang 84891ecbe50SWolfram Sang ret = tmio_mmc_host_probe(host); 84991ecbe50SWolfram Sang if (ret < 0) 85091ecbe50SWolfram Sang goto edisclk; 85191ecbe50SWolfram Sang 852b5b6a5f4SSimon Horman /* Enable tuning iff we have an SCC and a supported mode */ 853b5b6a5f4SSimon Horman if (of_data && of_data->scc_offset && 854b5b6a5f4SSimon Horman (host->mmc->caps & MMC_CAP_UHS_SDR104 || 85526eb2607SMasaharu Hayakawa host->mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | 85626eb2607SMasaharu Hayakawa MMC_CAP2_HS400_1_8V))) { 857b5b6a5f4SSimon Horman const struct renesas_sdhi_scc *taps = of_data->taps; 858c1a49782SWolfram Sang bool use_4tap = priv->quirks && priv->quirks->hs400_4taps; 859b5b6a5f4SSimon Horman bool hit = false; 860b5b6a5f4SSimon Horman 861b5b6a5f4SSimon Horman for (i = 0; i < of_data->taps_num; i++) { 862b5b6a5f4SSimon Horman if (taps[i].clk_rate == 0 || 863b5b6a5f4SSimon Horman taps[i].clk_rate == host->mmc->f_max) { 864852d258fSMasahiro Yamada priv->scc_tappos = taps->tap; 865c1a49782SWolfram Sang priv->scc_tappos_hs400 = use_4tap ? 866c1a49782SWolfram Sang taps->tap_hs400_4tap : 867c1a49782SWolfram Sang taps->tap; 868b5b6a5f4SSimon Horman hit = true; 869b5b6a5f4SSimon Horman break; 870b5b6a5f4SSimon Horman } 871b5b6a5f4SSimon Horman } 872b5b6a5f4SSimon Horman 873b5b6a5f4SSimon Horman if (!hit) 874e5088f20SWolfram Sang dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); 875b5b6a5f4SSimon Horman 876b5b6a5f4SSimon Horman host->init_tuning = renesas_sdhi_init_tuning; 877b5b6a5f4SSimon Horman host->prepare_tuning = renesas_sdhi_prepare_tuning; 878b5b6a5f4SSimon Horman host->select_tuning = renesas_sdhi_select_tuning; 879b5b6a5f4SSimon Horman host->check_scc_error = renesas_sdhi_check_scc_error; 88026eb2607SMasaharu Hayakawa host->prepare_hs400_tuning = 88126eb2607SMasaharu Hayakawa renesas_sdhi_prepare_hs400_tuning; 88226eb2607SMasaharu Hayakawa host->hs400_downgrade = renesas_sdhi_disable_scc; 88326eb2607SMasaharu Hayakawa host->hs400_complete = renesas_sdhi_hs400_complete; 884b5b6a5f4SSimon Horman } 885b5b6a5f4SSimon Horman 886e8307ec5SGeert Uytterhoeven num_irqs = platform_irq_count(pdev); 887e8307ec5SGeert Uytterhoeven if (num_irqs < 0) { 888e8307ec5SGeert Uytterhoeven ret = num_irqs; 889b5b6a5f4SSimon Horman goto eirq; 890b5b6a5f4SSimon Horman } 891b5b6a5f4SSimon Horman 892b5b6a5f4SSimon Horman /* There must be at least one IRQ source */ 893e8307ec5SGeert Uytterhoeven if (!num_irqs) { 894e8307ec5SGeert Uytterhoeven ret = -ENXIO; 895e8307ec5SGeert Uytterhoeven goto eirq; 896e8307ec5SGeert Uytterhoeven } 897e8307ec5SGeert Uytterhoeven 898e8307ec5SGeert Uytterhoeven for (i = 0; i < num_irqs; i++) { 899e8307ec5SGeert Uytterhoeven irq = platform_get_irq(pdev, i); 900e8307ec5SGeert Uytterhoeven if (irq < 0) { 901b5b6a5f4SSimon Horman ret = irq; 902b5b6a5f4SSimon Horman goto eirq; 903b5b6a5f4SSimon Horman } 904b5b6a5f4SSimon Horman 905e8307ec5SGeert Uytterhoeven ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, 906e8307ec5SGeert Uytterhoeven dev_name(&pdev->dev), host); 907e8307ec5SGeert Uytterhoeven if (ret) 908e8307ec5SGeert Uytterhoeven goto eirq; 909e8307ec5SGeert Uytterhoeven } 910e8307ec5SGeert Uytterhoeven 911b5b6a5f4SSimon Horman dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", 912b5b6a5f4SSimon Horman mmc_hostname(host->mmc), (unsigned long) 913b5b6a5f4SSimon Horman (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), 914b5b6a5f4SSimon Horman host->mmc->f_max / 1000000); 915b5b6a5f4SSimon Horman 916b5b6a5f4SSimon Horman return ret; 917b5b6a5f4SSimon Horman 918b5b6a5f4SSimon Horman eirq: 919b5b6a5f4SSimon Horman tmio_mmc_host_remove(host); 920b21fc294SMasahiro Yamada edisclk: 921b21fc294SMasahiro Yamada renesas_sdhi_clk_disable(host); 922b5b6a5f4SSimon Horman efree: 923b5b6a5f4SSimon Horman tmio_mmc_host_free(host); 9244ce62817SMasahiro Yamada 925b5b6a5f4SSimon Horman return ret; 926b5b6a5f4SSimon Horman } 9279d08428aSSimon Horman EXPORT_SYMBOL_GPL(renesas_sdhi_probe); 928b5b6a5f4SSimon Horman 9299d08428aSSimon Horman int renesas_sdhi_remove(struct platform_device *pdev) 930b5b6a5f4SSimon Horman { 931a3b05373SMasahiro Yamada struct tmio_mmc_host *host = platform_get_drvdata(pdev); 932b5b6a5f4SSimon Horman 933b5b6a5f4SSimon Horman tmio_mmc_host_remove(host); 934b21fc294SMasahiro Yamada renesas_sdhi_clk_disable(host); 935b5b6a5f4SSimon Horman 936b5b6a5f4SSimon Horman return 0; 937b5b6a5f4SSimon Horman } 9389d08428aSSimon Horman EXPORT_SYMBOL_GPL(renesas_sdhi_remove); 939967a6a07SMasaharu Hayakawa 940967a6a07SMasaharu Hayakawa MODULE_LICENSE("GPL v2"); 941